File indexing completed on 2024-05-19 16:09:36

0001 /* This file is part of the KDE project
0002  * Copyright ( C ) 2007 Thorsten Zachmann <zachmann@kde.org>
0003  * Copyright ( C ) 2010 Benjamin Port <port.benjamin@gmail.com>
0004  * Copyright ( C ) 2012 Paul Mendez <paulestebanms@gmail.com>
0005  *
0006  * This library is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Library General Public
0008  * License as published by the Free Software Foundation; either
0009  * version 2 of the License, or (  at your option ) any later version.
0010  *
0011  * This library is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * Library General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Library General Public License
0017  * along with this library; see the file COPYING.LIB.  If not, write to
0018  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  * Boston, MA 02110-1301, USA.
0020  */
0021 
0022 #include "KPrShapeAnimations.h"
0023 
0024 //Qt Headers
0025 #include <QList>
0026 #include <QSet>
0027 #include <QPainter>
0028 #include <QPainterPath>
0029 
0030 //Stage Headers
0031 #include "KPrDocument.h"
0032 #include "animations/KPrAnimationSubStep.h"
0033 #include "animations/KPrAnimateMotion.h"
0034 #include "commands/KPrAnimationRemoveCommand.h"
0035 #include "commands/KPrReorderAnimationCommand.h"
0036 #include <commands/KPrEditAnimationTimeLineCommand.h>
0037 #include <commands/KPrAnimationEditNodeTypeCommand.h>
0038 #include <commands/KPrReplaceAnimationCommand.h>
0039 #include <commands/KPrAnimationCreateCommand.h>
0040 #include "StageDebug.h"
0041 
0042 //Calligra Headers
0043 #include <KoShape.h>
0044 #include <KoShapePainter.h>
0045 #include <KoShapeContainer.h>
0046 #include <KoPathShape.h>
0047 #include <KoIcon.h>
0048 
0049 //KF5 Headers
0050 #include <kiconloader.h>
0051 #include <klocalizedstring.h>
0052 
0053 const int COLUMN_COUNT = 10;
0054 const int INVALID = -1;
0055 
0056 KPrShapeAnimations::KPrShapeAnimations(KPrDocument *document, QObject *parent)
0057     :QAbstractTableModel(parent)
0058     , m_currentEditedAnimation(0)
0059     , m_firstEdition(true)
0060     , m_oldBegin(INVALID)
0061     , m_oldDuration(INVALID)
0062     , m_document(document)
0063 {
0064 }
0065 
0066 KPrShapeAnimations::~KPrShapeAnimations()
0067 {
0068 }
0069 
0070 Qt::ItemFlags KPrShapeAnimations::flags(const QModelIndex &index) const
0071 {
0072     Qt::ItemFlags theFlags = QAbstractTableModel::flags(index);
0073     if (index.isValid()) {
0074         theFlags |= Qt::ItemIsSelectable|Qt::ItemIsEnabled;
0075         //if (index.column() == Name)
0076             //theFlags |= Qt::ItemIsEditable;//|
0077                         //Qt::ItemIsDragEnabled|Qt::ItemIsDropEnabled;
0078     }
0079     return theFlags;
0080 }
0081 
0082 QVariant KPrShapeAnimations::data(const QModelIndex &index, int role) const
0083 {
0084     if (!index.isValid() || index.column() < 0 ||
0085             index.column() >= COLUMN_COUNT || index.row() < 0
0086             || index.row() >= rowCount(QModelIndex())) {
0087         return QVariant();
0088     }
0089 
0090     // Read Data
0091     KPrShapeAnimation::NodeType nodeType;
0092     int currentGroup = -1;
0093     KPrShapeAnimation *thisAnimation = animationByRow(index.row(), &currentGroup, &nodeType);
0094     if (!thisAnimation) {
0095         return QVariant();
0096     }
0097 
0098     if (role == Qt::DisplayRole || role == Qt::EditRole) {
0099         switch (index.column()) {
0100             case Group: return currentGroup;
0101             case StepCount:
0102                 if (nodeType == KPrShapeAnimation::OnClick) {
0103                     return currentGroup;
0104                 }
0105                 else {
0106                     return QVariant();
0107                 }
0108             case TriggerEvent: return QVariant();
0109             case Name: return getAnimationName(thisAnimation);
0110             case ShapeThumbnail: return QVariant();
0111             case AnimationIcon: return QVariant();
0112             case StartTime: return thisAnimation->timeRange().first;
0113             case Duration: return thisAnimation->globalDuration();
0114             case AnimationClass: return thisAnimation->presetClass();
0115             case NodeType: return nodeType;
0116             default: Q_ASSERT(false);
0117         }
0118     }
0119     if (role == Qt::TextAlignmentRole) {
0120         if (index.column() == Name) {
0121             return static_cast<int>(Qt::AlignLeft|Qt::AlignVCenter);
0122         }
0123         return static_cast<int>(Qt::AlignCenter);
0124     }
0125     if (role == Qt::DecorationRole) {
0126         switch (index.column()) {
0127             case Group: return QVariant();
0128             case StepCount: return QVariant();
0129             case TriggerEvent:
0130                 if (nodeType == KPrShapeAnimation::OnClick)
0131                     return koIcon("onclick");
0132                 if (nodeType == KPrShapeAnimation::AfterPrevious)
0133                     return koIcon("after_previous");
0134                 if (nodeType == KPrShapeAnimation::WithPrevious)
0135                     return koIcon("with_previous");
0136                 return QVariant();
0137             case Name: return QVariant();
0138             case ShapeThumbnail: return getAnimationShapeThumbnail(thisAnimation);
0139             case AnimationIcon:  return getAnimationIcon(thisAnimation);
0140             case StartTime: return QVariant();
0141             case Duration: return QVariant();
0142             case AnimationClass: return QVariant();
0143             case NodeType: return QVariant();
0144             default: Q_ASSERT(false);
0145         }
0146     }
0147     if (role == Qt::SizeHintRole) {
0148         switch (index.column()) {
0149             case Group:
0150             case StepCount: return QVariant();
0151             case TriggerEvent: return QSize(KIconLoader::SizeSmall, KIconLoader::SizeSmall);
0152             case Name: return QVariant();
0153             case ShapeThumbnail: return QSize(KIconLoader::SizeMedium, KIconLoader::SizeMedium);
0154             case AnimationIcon:
0155             case StartTime:
0156             case Duration:
0157             case AnimationClass: return QVariant();
0158             case NodeType: return QVariant();
0159             default: Q_ASSERT(false);
0160         }
0161     }
0162     if (role == Qt::ToolTipRole) {
0163             switch (index.column()) {
0164             case Group:
0165             case StepCount: return QVariant();
0166             case TriggerEvent:/// emitted if an item time range has changed (return the index of the item changed)
0167                 if (nodeType == KPrShapeAnimation::OnClick)
0168                     return i18n("start on mouse click");
0169                 if (nodeType == KPrShapeAnimation::AfterPrevious)
0170                     return i18n("start after previous animation");
0171                 if (nodeType == KPrShapeAnimation::WithPrevious)
0172                     return i18n("start with previous animation");
0173                 return QVariant();
0174             case Name: return QVariant();
0175             case ShapeThumbnail: return thisAnimation->shape()->name();
0176             case AnimationIcon: return getAnimationName(thisAnimation);
0177             case StartTime: {
0178                 const float startDelay = thisAnimation->timeRange().first / 1000.0;
0179                 const float duration = thisAnimation->globalDuration() / 1000.0;
0180                 return i18n("Start after %1 seconds. Duration of %2 seconds.", startDelay, duration);
0181             }
0182             case Duration: return QVariant();
0183             case AnimationClass: return thisAnimation->presetClassText();
0184             case NodeType: return QVariant();
0185             default: Q_ASSERT(false);
0186             }
0187         }
0188     return QVariant();
0189 }
0190 
0191 QVariant KPrShapeAnimations::headerData(int section, Qt::Orientation orientation, int role) const
0192 {
0193     if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
0194         if (section == Name) {
0195             return i18n("Animation");
0196         }
0197         else if (section == TriggerEvent) {
0198             return QString();
0199         }
0200         else if (section == ShapeThumbnail) {
0201             return i18n("Shape");
0202         }
0203     }
0204     return QVariant();
0205 }
0206 
0207 void KPrShapeAnimations::dump() const
0208 {
0209     debugStageAnimation << "Share animations:";
0210     foreach (KPrAnimationStep *step, m_shapeAnimations) {
0211         debugStageAnimation << "  Step:";
0212         for (int i=0; i < step->animationCount(); i++) {
0213             QAbstractAnimation *animation = step->animationAt(i);
0214             if (KPrAnimationSubStep *a = dynamic_cast<KPrAnimationSubStep*>(animation)) {
0215                 debugStageAnimation << "    Substep" << a;
0216                 for (int sub=0; sub < a->animationCount(); ++sub) {
0217                     QAbstractAnimation *baseAnim = a->animationAt(sub);
0218                     KPrShapeAnimation *anim = dynamic_cast<KPrShapeAnimation *>(baseAnim);
0219                     if (anim) {
0220                         debugStageAnimation << "      Animation" << anim << getAnimationName(anim);
0221                     } else {
0222                         debugStageAnimation << "      NOT a KPrShapeAnimation!" << anim;
0223                     }
0224                 }
0225             } else {
0226                 debugStageAnimation << "    NOT a KPrAnimationSubStep!" << animation;
0227             }
0228         }
0229     }
0230 }
0231 
0232 int KPrShapeAnimations::rowCount(const QModelIndex &parent) const
0233 {
0234     if (parent.isValid()) {
0235         return 0;
0236     }
0237     int rowCount = 0;
0238     foreach (KPrAnimationStep *step, m_shapeAnimations) {
0239         for (int i=0; i < step->animationCount(); i++) {
0240             QAbstractAnimation *animation = step->animationAt(i);
0241             if (KPrAnimationSubStep *a = dynamic_cast<KPrAnimationSubStep*>(animation)) {
0242                 rowCount = rowCount + a->animationCount();
0243             }
0244         }
0245     }
0246     return rowCount;
0247 
0248 }
0249 
0250 int KPrShapeAnimations::columnCount(const QModelIndex &parent) const
0251 {
0252     return parent.isValid() ? 0 : COLUMN_COUNT;
0253 }
0254 
0255 bool KPrShapeAnimations::setData(const QModelIndex &index, const QVariant &value, int role)
0256 {
0257     if (!index.isValid() || index.column() < 0 ||
0258             (index.column() > columnCount(QModelIndex()))) {
0259         return false;
0260     }
0261     // Read Data
0262     KPrShapeAnimation *thisAnimation = animationByRow(index.row());
0263     if (!thisAnimation) {
0264         return false;
0265     }
0266     if (role == Qt::EditRole) {
0267         switch (index.column()) {
0268             case Group:
0269             case StepCount:
0270             case TriggerEvent:
0271             case Name:
0272             case ShapeThumbnail:
0273                 return false;
0274             case AnimationIcon:
0275                 return false;
0276             case StartTime:
0277                 setTimeRangeIncrementalChange(thisAnimation, value.toInt(), thisAnimation->globalDuration(), BeginTime);
0278                 emit dataChanged(index, index);
0279                 return true;
0280             case Duration:
0281                 setTimeRangeIncrementalChange(thisAnimation, thisAnimation->timeRange().first, value.toInt(), DurationTime);
0282                 emit dataChanged(index, index);
0283                 return true;
0284             case AnimationClass:
0285                 return false;
0286             default:
0287                 return false;
0288 
0289         }
0290     }
0291     return false;
0292 }
0293 
0294 void KPrShapeAnimations::init(const QList<KPrAnimationStep *> &animations)
0295 {
0296     m_shapeAnimations = animations;
0297 }
0298 
0299 void KPrShapeAnimations::add(KPrShapeAnimation *animation)
0300 {
0301     // TODO: what is the purpose of this empty KPrAnimationStep?
0302     if (m_shapeAnimations.isEmpty()) {
0303         m_shapeAnimations.append(new KPrAnimationStep());
0304     }
0305     if (!animation->step()) {
0306         KPrAnimationStep *newStep = new KPrAnimationStep();
0307         animation->setStep(newStep);
0308     }
0309     if (!animation->subStep()) {
0310         KPrAnimationSubStep *newSubStep = new KPrAnimationSubStep();
0311         animation->setSubStep(newSubStep);
0312     }
0313     if (!m_shapeAnimations.contains(animation->step())) {
0314         if ((animation->stepIndex() >= 0) && (animation->stepIndex() <= m_shapeAnimations.count())) {
0315             m_shapeAnimations.insert(animation->stepIndex(), animation->step());
0316         }
0317         else {
0318             m_shapeAnimations.append(animation->step());
0319         }
0320     }
0321     if (!(animation->step()->indexOfAnimation(animation->subStep()) >= 0)) {
0322         if ((animation->subStepIndex() >= 0) &&
0323                 (animation->subStepIndex() <= animation->step()->animationCount())) {
0324             animation->step()->insertAnimation(animation->subStepIndex(), animation->subStep());
0325         }
0326         else {
0327             animation->step()->addAnimation(animation->subStep());
0328         }
0329     }
0330 
0331     if ((animation->animIndex() >= 0) &&
0332             (animation->animIndex() <= animation->subStep()->animationCount())) {
0333         animation->subStep()->insertAnimation(animation->animIndex(), animation);
0334     }
0335     else {
0336         animation->subStep()->addAnimation(animation);
0337     }
0338 
0339     //updateModel
0340     QModelIndex index = indexByAnimation(animation);
0341     beginInsertRows(QModelIndex(), index.row(), index.row());
0342     endInsertRows();
0343     return;
0344 }
0345 
0346 void KPrShapeAnimations::remove(KPrShapeAnimation *animation)
0347 {
0348     //updateModel
0349     QModelIndex index = indexByAnimation(animation);
0350     beginRemoveRows(QModelIndex(), index.row(), index.row());
0351 
0352     KPrAnimationStep *step = animation->step();
0353     KPrAnimationSubStep *subStep = animation->subStep();
0354     if (subStep->animationCount() <= 1) {
0355         animation->setSubStepIndex(step->indexOfAnimation(subStep));
0356         step->removeAnimation(subStep);
0357         if (step->animationCount() <= 0) {
0358             animation->setStepIndex(m_shapeAnimations.indexOf(step));
0359             m_shapeAnimations.removeAll(step);
0360         }
0361     }
0362     animation->setAnimIndex(subStep->indexOfAnimation(animation));
0363     subStep->removeAnimation(animation);
0364     endRemoveRows();
0365 }
0366 
0367 void KPrShapeAnimations::insertStep(const int i, KPrAnimationStep *step)
0368 {
0369     if (step) {
0370         m_shapeAnimations.insert(i, step);
0371     }
0372 }
0373 
0374 void KPrShapeAnimations::removeStep(KPrAnimationStep *step)
0375 {
0376     if (step) {
0377         m_shapeAnimations.removeAll(step);
0378     }
0379 }
0380 
0381 void KPrShapeAnimations::swapSteps(int i, int j)
0382 {
0383     m_shapeAnimations.swap(i, j);
0384     emit dataChanged(this->index(i,0), this->index(i, COLUMN_COUNT));
0385     emit dataChanged(this->index(j,0), this->index(j, COLUMN_COUNT));
0386 }
0387 
0388 void KPrShapeAnimations::swapAnimations(KPrShapeAnimation *oldAnimation, KPrShapeAnimation *newAnimation)
0389 {
0390     KPrAnimationStep *oldStep = oldAnimation->step();
0391     KPrAnimationSubStep *oldSubStep = oldAnimation->subStep();
0392     KPrAnimationSubStep *newSubStep = newAnimation->subStep();
0393     int oldIndex = oldSubStep->indexOfAnimation(oldAnimation);
0394     int newIndex = newSubStep->indexOfAnimation(newAnimation);
0395     if (oldSubStep != newSubStep) {
0396         oldSubStep->removeAnimation(oldAnimation);
0397         newSubStep->removeAnimation(newAnimation);
0398         oldSubStep->insertAnimation(oldIndex, newAnimation);
0399         newSubStep->insertAnimation(newIndex, oldAnimation);
0400     }
0401     else {
0402         if (oldIndex < newIndex) {
0403             oldSubStep->removeAnimation(newAnimation);
0404             oldSubStep->insertAnimation(oldIndex, newAnimation);
0405         }
0406         else {
0407             oldSubStep->removeAnimation(oldAnimation);
0408             oldSubStep->insertAnimation(newIndex, oldAnimation);
0409         }
0410     }
0411 
0412     oldAnimation->setStep(newAnimation->step());
0413     oldAnimation->setSubStep(newSubStep);
0414     newAnimation->setStep(oldStep);
0415     newAnimation->setSubStep(oldSubStep);
0416     QModelIndex indexOld = indexByAnimation(oldAnimation);
0417     QModelIndex indexNew = indexByAnimation(newAnimation);
0418     emit dataChanged(this->index(indexOld.row(), 0), this->index(indexOld.row(), COLUMN_COUNT));
0419     emit dataChanged(this->index(indexNew.row(), 0), this->index(indexNew.row(), COLUMN_COUNT));
0420 }
0421 
0422 void KPrShapeAnimations::replaceAnimation(KPrShapeAnimation *oldAnimation, KPrShapeAnimation *newAnimation)
0423 {
0424     KPrAnimationSubStep *subStep = oldAnimation->subStep();
0425     int currentAnimationIndex = subStep->indexOfAnimation(oldAnimation);
0426     newAnimation->setStep(oldAnimation->step());
0427     newAnimation->setSubStep(oldAnimation->subStep());
0428     newAnimation->setTextBlockUserData(oldAnimation->textBlockUserData());
0429     subStep->insertAnimation(currentAnimationIndex, newAnimation);
0430     subStep->removeAnimation(oldAnimation);
0431     QModelIndex indexModified = indexByAnimation(newAnimation);
0432     emit dataChanged(this->index(indexModified.row(), 0), this->index(indexModified.row(), COLUMN_COUNT));
0433 }
0434 
0435 QList<KPrAnimationStep *> KPrShapeAnimations::steps() const
0436 {
0437     return m_shapeAnimations;
0438 }
0439 
0440 void KPrShapeAnimations::endTimeLineEdition()
0441 {
0442     if (!m_firstEdition && m_currentEditedAnimation && (m_oldBegin != INVALID) && (m_oldDuration != INVALID)) {
0443         int begin = m_currentEditedAnimation->timeRange().first;
0444         int duration = m_currentEditedAnimation->globalDuration();
0445         if ((begin != m_oldBegin) || (duration != m_oldDuration)) {
0446             m_currentEditedAnimation->setBeginTime(m_oldBegin);
0447             m_currentEditedAnimation->setGlobalDuration(m_oldDuration);
0448             setTimeRange(m_currentEditedAnimation, begin, duration);
0449             emit timeScaleModified();
0450         }
0451         m_oldBegin = INVALID;
0452         m_oldDuration = INVALID;
0453     }
0454     m_firstEdition = true;
0455     m_currentEditedAnimation = 0;
0456 }
0457 
0458 void KPrShapeAnimations::setTimeRange(KPrShapeAnimation *item, const int begin, const int duration)
0459 {
0460     if (item && m_document) {
0461         KPrEditAnimationTimeLineCommand *command = new KPrEditAnimationTimeLineCommand(item,
0462                                                                                      begin, duration);
0463         m_document->addCommand(command);
0464         connect(item, SIGNAL(timeChanged(int,int)), this, SLOT(notifyAnimationEdited()));
0465     }
0466 }
0467 
0468 int KPrShapeAnimations::animationEnd(const QModelIndex &index) const
0469 {
0470     if (index.isValid()) {
0471         KPrShapeAnimation *previousAnimation = animationByRow(index.row());
0472         KPrShapeAnimation::NodeType previousNodeType =
0473                 static_cast<KPrShapeAnimation::NodeType>(data(this->index(index.row(),
0474                                                                            KPrShapeAnimations::NodeType)).toInt());
0475         if (previousNodeType == KPrShapeAnimation::OnClick) {
0476             return previousAnimation->timeRange().second;
0477         }
0478         if (previousNodeType == KPrShapeAnimation::WithPrevious) {
0479             return previousAnimation->timeRange().second +
0480                     animationStart(this->index(index.row() - 1, index.column(), QModelIndex()));
0481         }
0482         else if (previousNodeType == KPrShapeAnimation::AfterPrevious) {
0483             return previousAnimation->timeRange().second +
0484                     animationEnd(this->index(index.row() - 1, index.column(), QModelIndex()));
0485         }
0486     }
0487     return 0;
0488 }
0489 
0490 int KPrShapeAnimations::animationStart(const QModelIndex &index) const
0491 {
0492     if (index.isValid()) {
0493         KPrShapeAnimation *previousAnimation = animationByRow(index.row());
0494         KPrShapeAnimation::NodeType previousNodeType =
0495                 static_cast<KPrShapeAnimation::NodeType>(data(this->index(index.row(),
0496                                                                            KPrShapeAnimations::NodeType)).toInt());
0497         if (previousNodeType == KPrShapeAnimation::OnClick) {
0498             return previousAnimation->timeRange().first;
0499         }
0500         if (previousNodeType == KPrShapeAnimation::WithPrevious) {
0501             return animationStart(this->index(index.row() - 1, index.column(), QModelIndex()));
0502         }
0503         else if (previousNodeType == KPrShapeAnimation::AfterPrevious) {
0504             return animationEnd(this->index(index.row() - 1, index.column(), QModelIndex()));
0505         }
0506     }
0507     return 0;
0508 }
0509 
0510 QModelIndex KPrShapeAnimations::replaceAnimation(const QModelIndex &index, KPrShapeAnimation *newAnimation)
0511 {
0512     if (!index.isValid() || !m_document) {
0513         return QModelIndex();
0514     }
0515     KPrShapeAnimation *oldAnimation = animationByRow(index.row());
0516     Q_ASSERT(oldAnimation);
0517     KPrReplaceAnimationCommand *cmd = new KPrReplaceAnimationCommand(m_document, oldAnimation, newAnimation);
0518     m_document->addCommand(cmd);
0519     return index;
0520 }
0521 
0522 bool KPrShapeAnimations::setTriggerEvent(const QModelIndex &index, const KPrShapeAnimation::NodeType type)
0523 {
0524     KPrShapeAnimation *animation = animationByRow(index.row());
0525     if (animation) {
0526         KPrShapeAnimation::NodeType currentType =
0527                 static_cast<KPrShapeAnimation::NodeType>(data(this->index(index.row(),
0528                                                                            KPrShapeAnimations::NodeType)).toInt());
0529         if (currentType == KPrShapeAnimation::AfterPrevious) {
0530             if (type == KPrShapeAnimation::WithPrevious) {
0531                 Q_ASSERT(index.row() > 0);
0532             }
0533         }
0534         else if (currentType == KPrShapeAnimation::OnClick) {
0535              if (index.row() < 1) {
0536                  // Resync trigger event edit widget
0537                  emit layoutChanged();
0538                  return false;
0539              }
0540         }
0541         if (type != currentType) {
0542             return createTriggerEventEditCmd(animation, currentType, type);
0543         }
0544     }
0545     return false;
0546 }
0547 
0548 bool KPrShapeAnimations::setNodeType(KPrShapeAnimation *animation, const KPrShapeAnimation::NodeType type)
0549 {
0550     resyncStepsWithAnimations();
0551     if (animation) {
0552         QModelIndex index = indexByAnimation(animation);
0553         if (!index.isValid()) {
0554             return false;
0555         }
0556         QList<KPrShapeAnimation *> movedChildren = QList<KPrShapeAnimation *>();
0557         QList<KPrAnimationSubStep *>movedSubSteps = QList<KPrAnimationSubStep *>();
0558         KPrAnimationSubStep *newSubStep = 0;
0559         KPrAnimationStep *newStep = 0;
0560         KPrShapeAnimation::NodeType currentType =
0561                 static_cast<KPrShapeAnimation::NodeType>(data(this->index(index.row(),
0562                                                                            KPrShapeAnimations::NodeType)).toInt());
0563         if (currentType == KPrShapeAnimation::AfterPrevious) {
0564             // After Previous to With Previous
0565             if (type == KPrShapeAnimation::WithPrevious) {
0566                 //use previous animation to reparent current animation
0567                 Q_ASSERT(index.row() > 0);
0568                 KPrShapeAnimation *previousAnimation = animationByRow(index.row() - 1);
0569                 newSubStep = previousAnimation->subStep();
0570                 movedChildren = getWithPreviousSiblings(animation);
0571             }
0572 
0573             // After Previous to On Click
0574             else if (type == KPrShapeAnimation::OnClick) {
0575                  // Get index of current substep
0576                  int currentSubStepIndex = animation->step()->indexOfAnimation(animation->subStep());
0577                  int subStepCount = animation->step()->animationCount();
0578 
0579                  //Create new step to reparent current item and all following items.
0580                  newStep = new KPrAnimationStep();
0581 
0582                  // Add step after original one
0583                  int currentStepIndex = m_shapeAnimations.indexOf(animation->step());
0584                  insertStep(currentStepIndex + 1, newStep);
0585 
0586                  //reparent children
0587                  if (currentSubStepIndex < subStepCount - 1) {
0588                      movedSubSteps = getSubSteps(currentSubStepIndex + 1, subStepCount, animation->step());
0589                  }
0590             }
0591             else {
0592                 return false;
0593             }
0594         }
0595         else if (currentType == KPrShapeAnimation::WithPrevious) {
0596            // With Previous to After Previous
0597            if (type == KPrShapeAnimation::AfterPrevious) {
0598                // Get index of current substep
0599                int currentSubStepIndex = animation->step()->indexOfAnimation(animation->subStep());
0600                //Create new substep to reparent current item and all following items.
0601                newSubStep = new KPrAnimationSubStep();
0602 
0603                // Add substep after original one
0604                animation->step()->insertAnimation(currentSubStepIndex + 1, newSubStep);
0605 
0606                //reparent children
0607                movedChildren = getWithPreviousSiblings(animation);
0608            }
0609            // With Previous to On Click
0610            else if (type == KPrShapeAnimation::OnClick) {
0611                 // Get index of current substep
0612                 int currentSubStepIndex = animation->step()->indexOfAnimation(animation->subStep());
0613                 int subStepCount = animation->step()->animationCount();
0614 
0615                 //Create new step to reparent current item and all following items.
0616                 newStep = new KPrAnimationStep();
0617 
0618                 //Create new substep to reparent current item and all following items.
0619                 newSubStep = new KPrAnimationSubStep();
0620 
0621                 // Add step after original one
0622                 //insert new Step
0623                 int currentStepIndex = m_shapeAnimations.indexOf(animation->step());
0624                 insertStep(currentStepIndex + 1, newStep);
0625 
0626                 //reparent children
0627                 if (currentSubStepIndex < subStepCount - 1) {
0628                     movedSubSteps = getSubSteps(currentSubStepIndex + 1, subStepCount, animation->step());
0629                 }
0630                 movedChildren = getWithPreviousSiblings(animation);
0631            }
0632            else {
0633                return false;
0634            }
0635         }
0636         else if (currentType == KPrShapeAnimation::OnClick) {
0637              if (index.row() < 1) {
0638                  // Resync trigger event edit widget
0639                  emit layoutChanged();
0640                  return false;
0641              }
0642             // On click to With Previous
0643             if (type == KPrShapeAnimation::WithPrevious) {
0644                 // Get previous animation
0645                 KPrShapeAnimation *previousAnimation = animationByRow(index.row() - 1);
0646                 newStep = previousAnimation->step();
0647                 newSubStep = previousAnimation->subStep();
0648 
0649                 movedChildren = getWithPreviousSiblings(animation);
0650 
0651                 int subStepCount = animation->step()->animationCount();
0652                 int currentSubStepIndex = animation->step()->indexOfAnimation(animation->subStep());
0653                 if (subStepCount > 1) {
0654                     movedSubSteps = getSubSteps(currentSubStepIndex + 1, subStepCount, animation->step());
0655                 }
0656             }
0657 
0658             // On click to After Previous
0659             else if (type == KPrShapeAnimation::AfterPrevious) {
0660                  // Get previous animation
0661                  KPrShapeAnimation *previousAnimation = animationByRow(index.row() - 1);
0662                  newStep = previousAnimation->step();
0663                  int subStepCount = animation->step()->animationCount();
0664                  if (subStepCount > 1) {
0665                      movedSubSteps = getSubSteps(1, subStepCount, animation->step());
0666                  }
0667             }
0668             else {
0669                 return false;
0670             }
0671         }
0672         else {
0673             return false;
0674         }
0675         KPrAnimationSubStep *oldSubStep = animation->subStep();
0676         KPrAnimationStep *oldStep = animation->step();
0677 
0678         // if new subStep reparent main item and children
0679         if (newSubStep) {
0680             if (oldSubStep->indexOfAnimation(animation) >= 0) {
0681                 newSubStep->addAnimation(oldSubStep->takeAnimation(oldSubStep->indexOfAnimation(animation)));
0682             }
0683             if (!movedChildren.isEmpty()) {
0684                 foreach(KPrShapeAnimation *anim, movedChildren) {
0685                     if ((oldSubStep->indexOfAnimation(anim) >= 0) && (oldSubStep->indexOfAnimation(anim) <
0686                                                                       oldSubStep->animationCount())) {
0687                         newSubStep->addAnimation(oldSubStep->takeAnimation(oldSubStep->indexOfAnimation(anim)));
0688                     }
0689                 }
0690             }
0691         }
0692         // If newStep reparent subSteps and children
0693         if (newStep) {
0694             if (!newSubStep) {
0695                 newSubStep = oldSubStep;
0696             }
0697             if (movedSubSteps.isEmpty()) {
0698                 movedSubSteps.append(newSubStep);
0699             }
0700             else {
0701                 movedSubSteps.insert(0, newSubStep);
0702             }
0703             foreach(KPrAnimationSubStep *subStep, movedSubSteps) {
0704                 newStep->addAnimation(subStep);
0705             }
0706         }
0707         // If old substep or step is empty remove from list;
0708         if (oldSubStep->children().isEmpty()) {
0709             oldSubStep->setParent(0);
0710         }
0711         if (oldStep->children().isEmpty()) {
0712             removeStep(oldStep);
0713         }
0714 
0715         if ((currentType == KPrShapeAnimation::OnClick) || (type == KPrShapeAnimation::OnClick)) {
0716             notifyOnClickEventChanged();
0717         }
0718         notifyAnimationChanged(animation);
0719         resyncStepsWithAnimations();
0720         return true;
0721     }
0722     return false;
0723 }
0724 
0725 void KPrShapeAnimations::recalculateStart(const QModelIndex &mIndex)
0726 {
0727     if (!mIndex.isValid() || mIndex.row() < 1) {
0728         return;
0729     }
0730     KPrShapeAnimation *animation = animationByRow(mIndex.row());
0731 
0732     KPrShapeAnimation::NodeType type =
0733             static_cast<KPrShapeAnimation::NodeType>(data(this->index(mIndex.row(),
0734                                                                        KPrShapeAnimations::NodeType)).toInt());
0735     if (type == KPrShapeAnimation::AfterPrevious) {
0736         setTimeRange(animation, animationEnd(mIndex), animation->globalDuration());
0737         setTriggerEvent(mIndex, KPrShapeAnimation::WithPrevious);
0738     }
0739     else if (type == KPrShapeAnimation::WithPrevious) {
0740         recalculateStart(index(mIndex.row() - 1, 0));
0741     }
0742 }
0743 
0744 QModelIndex KPrShapeAnimations::moveUp(const QModelIndex &index)
0745 {
0746     if (!index.isValid() || index.row() < 1) {
0747         return QModelIndex();
0748     }
0749     return moveAnimation(index.row(), index.row() - 1);
0750 }
0751 
0752 QModelIndex KPrShapeAnimations::moveDown(const QModelIndex &index)
0753 {
0754     if (!index.isValid() || (index.row() >= (rowCount() - 1))) {
0755         return QModelIndex();
0756     }
0757 
0758     return moveAnimation(index.row(), index.row() + 1);
0759 }
0760 
0761 QModelIndex KPrShapeAnimations::moveAnimation(int oldRow, int newRow)
0762 {
0763     Q_ASSERT(0 <= oldRow && oldRow < rowCount() &&
0764              0 <= newRow && newRow < rowCount());
0765     QModelIndex newIndex;
0766     // swap items
0767     KPrShapeAnimation *animationOld = animationByRow(oldRow);
0768     KPrShapeAnimation *animationNew = animationByRow(newRow);
0769     Q_ASSERT(animationOld);
0770     Q_ASSERT(animationNew);
0771     if (m_document) {
0772         newIndex = index(newRow, 0);
0773         KPrReorderAnimationCommand *cmd = new KPrReorderAnimationCommand(this, animationOld, animationNew);
0774         m_document->addCommand(cmd);
0775     }
0776     return newIndex;
0777 }
0778 
0779 QModelIndex KPrShapeAnimations::removeAnimationByIndex(const QModelIndex &index)
0780 {
0781     if (!index.isValid()) {
0782         return index;
0783     }
0784     KPrShapeAnimation *animation = animationByRow(index.row());
0785     Q_ASSERT(animation);
0786 
0787     if (animation) {
0788         Q_ASSERT(m_document);
0789         KPrAnimationRemoveCommand *command = new KPrAnimationRemoveCommand(m_document, animation);
0790         m_document->addCommand(command);
0791     }
0792     return QModelIndex();
0793 }
0794 
0795 KoShape *KPrShapeAnimations::shapeByIndex(const QModelIndex &index) const
0796 {
0797     if (index.isValid()) {
0798         KPrShapeAnimation *animation = animationByRow(index.row());
0799         if (animation) {
0800             return animation->shape();
0801         }
0802     }
0803     return 0;
0804 }
0805 
0806 QModelIndex KPrShapeAnimations::indexByShape(KoShape *shape) const
0807 {
0808     int rowCount = 0;
0809     foreach (KPrAnimationStep *step, m_shapeAnimations) {
0810         for (int i=0; i < step->animationCount(); i++) {
0811             QAbstractAnimation *animation = step->animationAt(i);
0812             if (KPrAnimationSubStep *a = dynamic_cast<KPrAnimationSubStep*>(animation)) {
0813                 for (int j=0; j < a->animationCount(); j++) {
0814                     QAbstractAnimation *shapeAnimation = a->animationAt(j);
0815                     if (KPrShapeAnimation *b = dynamic_cast<KPrShapeAnimation*>(shapeAnimation)) {
0816                         if ((b->presetClass() != KPrShapeAnimation::None) && (b->shape())) {
0817                             if (b->shape() == shape)
0818                                 return this->index(rowCount, 0);
0819                         }
0820                         rowCount++;
0821                     }
0822                 }
0823             }
0824         }
0825     }
0826     return QModelIndex();
0827 }
0828 
0829 void KPrShapeAnimations::setBeginTime(const QModelIndex &index, const int begin)
0830 {
0831     if (!index.isValid()) {
0832         return;
0833     }
0834     KPrShapeAnimation *item = animationByRow(index.row());
0835     if (item) {
0836         setTimeRange(item, begin, item->globalDuration());
0837         emit dataChanged(index, index);
0838     }
0839 
0840 }
0841 
0842 void KPrShapeAnimations::setDuration(const QModelIndex &index, const int duration)
0843 {
0844     if (!index.isValid()) {
0845         return;
0846     }
0847     KPrShapeAnimation *item = animationByRow(index.row());
0848     if (item) {
0849         setTimeRange(item, item->timeRange().first, duration);
0850         emit dataChanged(index, index);
0851     }
0852 }
0853 
0854 void KPrShapeAnimations::notifyAnimationEdited()
0855 {
0856     if (KPrShapeAnimation *animation = qobject_cast<KPrShapeAnimation*>(sender())) {
0857         QModelIndex index = indexByAnimation(animation);
0858         if (index.isValid()) {
0859             emit dataChanged(index, index);
0860         }
0861     }
0862 }
0863 
0864 void KPrShapeAnimations::notifyAnimationChanged(KPrShapeAnimation *animation)
0865 {
0866     QModelIndex index = indexByAnimation(animation);
0867     if (index.isValid()) {
0868         emit dataChanged(this->index(index.row(), 0), this->index(index.row(), COLUMN_COUNT));
0869     }
0870 }
0871 
0872 void KPrShapeAnimations::notifyOnClickEventChanged()
0873 {
0874     emit onClickEventChanged();
0875 }
0876 
0877 KPrShapeAnimation *KPrShapeAnimations::animationByRow(int row, int *pGroup, KPrShapeAnimation::NodeType *pNodeType) const
0878 {
0879     int rowCount = 0;
0880     int groupCount = 0;
0881     KPrShapeAnimation::NodeType currentNodeType = KPrShapeAnimation::OnClick;
0882     foreach (KPrAnimationStep *step, m_shapeAnimations) {
0883         int stepChild = -1;
0884         if (step->animationCount() > 0) {
0885             currentNodeType = KPrShapeAnimation::OnClick;
0886             ++groupCount;
0887         }
0888         for (int i=0; i < step->animationCount(); i++) {
0889             QAbstractAnimation *animation = step->animationAt(i);
0890             if (KPrAnimationSubStep *a = dynamic_cast<KPrAnimationSubStep*>(animation)) {
0891                 int subStepChild = -1;
0892                 if (stepChild != -1) {
0893                     currentNodeType = KPrShapeAnimation::AfterPrevious;
0894                 }
0895                 if (rowCount + a->animationCount() < row) {
0896                     rowCount = rowCount + a->animationCount();
0897                     stepChild = stepChild + a->animationCount();
0898                     subStepChild = subStepChild + a->animationCount();
0899                     continue;
0900                 }
0901                 for (int j=0; j < a->animationCount(); j++) {
0902                     QAbstractAnimation *shapeAnimation = a->animationAt(j);
0903                     if (KPrShapeAnimation *b = dynamic_cast<KPrShapeAnimation*>(shapeAnimation)) {
0904                         stepChild++;
0905                         subStepChild++;
0906                         if (subStepChild > 0) {
0907                             currentNodeType = KPrShapeAnimation::WithPrevious;
0908                         }
0909                         if (rowCount == row) {
0910                             if (pGroup) {
0911                                 *pGroup = groupCount;
0912                             }
0913                             if (pNodeType) {
0914                                 *pNodeType = currentNodeType;
0915                             }
0916                             return b;
0917                         }
0918                         rowCount++;
0919                     }
0920                 }
0921             }
0922         }
0923     }
0924     return 0;
0925 }
0926 
0927 void KPrShapeAnimations::insertNewAnimation(KPrShapeAnimation *newAnimation, const QModelIndex &previousAnimation)
0928 {
0929     Q_ASSERT(newAnimation);
0930     // Create new Parent step and substep
0931     KPrAnimationStep *newStep = new KPrAnimationStep();
0932     KPrAnimationSubStep *newSubStep = new KPrAnimationSubStep();
0933     int stepIndex = -1;
0934     // insert step and substep
0935     if (previousAnimation.isValid()) {
0936         KPrShapeAnimation *previous = animationByRow(previousAnimation.row());
0937         stepIndex = m_shapeAnimations.indexOf(previous->step()) + 1;
0938     }
0939     else if (m_shapeAnimations.count() < 1) {
0940         stepIndex = -1;
0941     }
0942     else {
0943         stepIndex = m_shapeAnimations.count();
0944     }
0945 
0946     // Setup new Animation
0947     newAnimation->setStepIndex(stepIndex);
0948     newAnimation->setStep(newStep);
0949     newAnimation->setSubStep(newSubStep);
0950     newStep->addAnimation(newSubStep);
0951     Q_ASSERT(m_document);
0952     KPrAnimationCreateCommand *command = new KPrAnimationCreateCommand(m_document, newAnimation);
0953     m_document->addCommand(command);
0954 }
0955 
0956 QString KPrShapeAnimations::getAnimationName(KPrShapeAnimation *animation, bool omitSubType) const
0957 {
0958     if (animation) {
0959         QStringList descriptionList = animation->id().split(QLatin1Char('-'));
0960         if (descriptionList.count() > 2) {
0961             descriptionList.removeFirst();
0962             descriptionList.removeFirst();
0963         }
0964         if (!omitSubType && (!animation->presetSubType().isEmpty())) {
0965             descriptionList.append(animation->presetSubType());
0966         }
0967         return descriptionList.join(QChar::fromLatin1(' '));
0968     }
0969     return QString();
0970 }
0971 
0972 QPixmap KPrShapeAnimations::getAnimationShapeThumbnail(KPrShapeAnimation *animation) const
0973 {
0974     if (animation) {
0975         //TODO: Draw image file to load when shape thumbnail can't be created
0976        QPixmap thumbnail = koIcon("calligrastage").pixmap(KIconLoader::SizeMedium, KIconLoader::SizeMedium);
0977 
0978         if (
0979             thumbnail.convertFromImage(createThumbnail(animation->shape(),
0980                                                        QSize(KIconLoader::SizeMedium, KIconLoader::SizeMedium)))
0981         ) {
0982             thumbnail.scaled(QSize(KIconLoader::SizeMedium, KIconLoader::SizeMedium), Qt::KeepAspectRatio);
0983         }
0984         return thumbnail;
0985     }
0986     return QPixmap();
0987 }
0988 
0989 QPixmap KPrShapeAnimations::getAnimationIcon(KPrShapeAnimation *animation) const
0990 {
0991     if (!animation) {
0992         return QPixmap();
0993     }
0994     QString name = getAnimationName(animation, true);
0995     // Return Path Motion Animation icon
0996     if (animation->presetClass() == KPrShapeAnimation::MotionPath) {
0997         QPainterPath m_path;
0998         for (int i = 0; i < animation->animationCount(); i++) {
0999             if (KPrAnimateMotion *motion = dynamic_cast<KPrAnimateMotion *>(animation->animationAt(i))) {
1000                 m_path = motion->pathOutline();
1001                 break;
1002             }
1003         }
1004         if (!m_path.isEmpty()) {
1005             const int margin = 8;
1006             const int width = 4;
1007             QImage thumb(QSize(KIconLoader::SizeHuge, KIconLoader::SizeHuge), QImage::Format_RGB32);
1008             // fill backgroung
1009             thumb.fill(QColor(Qt::white).rgb());
1010             QRect imageRect = thumb.rect();
1011             // adjust to left space for margins
1012             imageRect.adjust(margin, margin, -margin, -margin);
1013             //Center path
1014             m_path.translate(-m_path.boundingRect().x() + margin, -m_path.boundingRect().y() + margin);
1015             QTransform transform;
1016             transform.scale(thumb.width() / (m_path.boundingRect().width() + 2 * margin),
1017                             thumb.height() / (m_path.boundingRect().height() + 2 * margin));
1018             m_path = m_path * transform;
1019             QPainter painter(&thumb);
1020             painter.setRenderHints(QPainter::Antialiasing);
1021             painter.setPen(QPen(QColor(0, 100, 224), width, Qt::SolidLine,
1022                                 Qt::FlatCap, Qt::MiterJoin));
1023             painter.drawPath(m_path);
1024             QPixmap iconPixmap;
1025             if (iconPixmap.convertFromImage(thumb)) {
1026                 return iconPixmap;
1027             }
1028         }
1029     }
1030     // Return animation icon
1031     else if (!name.isEmpty()) {
1032         name = name.append("_animation");
1033         name.replace(QLatin1Char(' '), QLatin1Char('_'));
1034         QString path = KIconLoader::global()->iconPath(name, KIconLoader::Toolbar, true);
1035         if (!path.isNull()) {
1036             return QIcon::fromTheme(name).pixmap(KIconLoader::SizeHuge, KIconLoader::SizeHuge);
1037         }
1038     }
1039     return koIcon("unrecognized_animation").pixmap(KIconLoader::SizeMedium, KIconLoader::SizeMedium);
1040 }
1041 
1042 QImage KPrShapeAnimations::createThumbnail(KoShape *shape, const QSize &thumbSize) const
1043 {
1044     KoShapePainter painter;
1045     QList<KoShape*> shapes;
1046     shapes.append(shape);
1047     KoShapeContainer * container = dynamic_cast<KoShapeContainer*>(shape);
1048     if (container) {
1049         shapes.append(container->shapes());
1050     }
1051 
1052     painter.setShapes(shapes);
1053 
1054     QImage thumb(thumbSize, QImage::Format_RGB32);
1055     // draw the background of the thumbnail
1056     thumb.fill(QColor(Qt::white).rgb());
1057 
1058     QRect imageRect = thumb.rect();
1059     // use 2 pixel border around the content
1060     imageRect.adjust(2, 2, -2, -2);
1061 
1062     QPainter p(&thumb);
1063     painter.paint(p, imageRect, painter.contentRect());
1064 
1065     return thumb;
1066 }
1067 
1068 void KPrShapeAnimations::setTimeRangeIncrementalChange(KPrShapeAnimation *item, const int begin, const int duration, TimeUpdated updatedTimes)
1069 {
1070     if (m_firstEdition) {
1071         m_oldBegin = item->timeRange().first;
1072         m_oldDuration = item->timeRange().second;
1073         m_currentEditedAnimation = item;
1074         m_firstEdition = false;
1075     }
1076     if (item == m_currentEditedAnimation) {
1077         if ((updatedTimes == BothTimes) || (updatedTimes == BeginTime)) {
1078             item->setBeginTime(begin);
1079         }
1080         if ((updatedTimes == BothTimes) || (updatedTimes == DurationTime)) {
1081             item->setGlobalDuration(duration);
1082         }
1083     }
1084     else {
1085         endTimeLineEdition();
1086     }
1087 }
1088 
1089 QModelIndex KPrShapeAnimations::indexByAnimation(KPrShapeAnimation *animation) const
1090 {
1091     int rowCount = 0;
1092     foreach (KPrAnimationStep *step, m_shapeAnimations) {
1093         for (int i=0; i < step->animationCount(); i++) {
1094             QAbstractAnimation *subStep = step->animationAt(i);
1095             if (KPrAnimationSubStep *a = dynamic_cast<KPrAnimationSubStep*>(subStep)) {
1096                 for (int j=0; j < a->animationCount(); j++) {
1097                     QAbstractAnimation *shapeAnimation = a->animationAt(j);
1098                     if (KPrShapeAnimation *b = dynamic_cast<KPrShapeAnimation*>(shapeAnimation)) {
1099                         if ((b->presetClass() != KPrShapeAnimation::None) && (b->shape())) {
1100                             if (b == animation) {
1101                                 return this->index(rowCount, 0, QModelIndex());
1102                             }
1103                             rowCount++;
1104                         }
1105                     }
1106                 }
1107             }
1108         }
1109     }
1110     return QModelIndex();
1111 }
1112 
1113 void KPrShapeAnimations::resyncStepsWithAnimations()
1114 {
1115     int row = -1;
1116     foreach (KPrAnimationStep *step, m_shapeAnimations) {
1117         row++;
1118         for (int i=0; i < step->animationCount(); i++) {
1119             QAbstractAnimation *subStep = step->animationAt(i);
1120             if (KPrAnimationSubStep *a = dynamic_cast<KPrAnimationSubStep*>(subStep)) {
1121                 for (int j=0; j < a->animationCount(); j++) {
1122                     QAbstractAnimation *shapeAnimation = a->animationAt(j);
1123                     if (KPrShapeAnimation *b = dynamic_cast<KPrShapeAnimation*>(shapeAnimation)) {
1124                         if ((b->presetClass() != KPrShapeAnimation::None) && (b->shape())) {
1125                             b->setStep(step);
1126                             b->setSubStep(a);
1127                         }
1128                     }
1129                 }
1130             }
1131         }
1132     }
1133 }
1134 
1135 KPrShapeAnimation::NodeType KPrShapeAnimations::triggerEventByIndex(const QModelIndex &index)
1136 {
1137     Q_ASSERT(index.isValid());
1138     KPrShapeAnimation::NodeType nodeType = KPrShapeAnimation::OnClick;
1139     animationByRow(index.row(), 0, &nodeType);
1140     return nodeType;
1141 }
1142 
1143 QList<KPrShapeAnimation *> KPrShapeAnimations::getWithPreviousSiblings(KPrShapeAnimation *animation) const
1144 {
1145     bool startAdding = false;
1146     QList<KPrShapeAnimation *> siblings = QList<KPrShapeAnimation *>();
1147 
1148     if (KPrAnimationSubStep *a = animation->subStep()) {
1149         for (int j=0; j < a->animationCount(); j++) {
1150             QAbstractAnimation *shapeAnimation = a->animationAt(j);
1151             if (KPrShapeAnimation *b = dynamic_cast<KPrShapeAnimation*>(shapeAnimation)) {
1152                 if ((b->presetClass() != KPrShapeAnimation::None) && (b->shape())) {
1153                     if (startAdding) {
1154                         siblings.append(b);
1155                     }
1156                     if (b == animation) {
1157                         startAdding = true;
1158                     }
1159                 }
1160             }
1161         }
1162     }
1163     return siblings;
1164 }
1165 
1166 QList<KPrAnimationSubStep *> KPrShapeAnimations::getSubSteps(int start, int end, KPrAnimationStep *step) const
1167 {
1168     QList<KPrAnimationSubStep *>movedSubSteps = QList<KPrAnimationSubStep *>();
1169     for (int i = start; i < end; i++) {
1170         if (KPrAnimationSubStep *substep = dynamic_cast<KPrAnimationSubStep *>(step->animationAt(i))) {
1171            movedSubSteps.append(substep);
1172         }
1173     }
1174     return movedSubSteps;
1175 }
1176 
1177 bool KPrShapeAnimations::createTriggerEventEditCmd(KPrShapeAnimation *animation, KPrShapeAnimation::NodeType oldType, KPrShapeAnimation::NodeType newType)
1178 {
1179     KPrAnimationEditNodeTypeCommand *command =new KPrAnimationEditNodeTypeCommand(animation, oldType, newType, this);
1180     if (m_document) {
1181         m_document->addCommand(command);
1182         emit timeScaleModified();
1183         return true;
1184     }
1185     return false;
1186 }