libs/flake

KoShapeReorderCommand.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE project
00002  * Copyright (C) 2006 Thomas Zander <zander@kde.org>
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Library General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Library General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Library General Public License
00015  * along with this library; see the file COPYING.LIB.  If not, write to
00016  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018  */
00019 
00020 #include "KoShapeReorderCommand.h"
00021 #include "KoShape.h"
00022 #include "KoShapeManager.h"
00023 #include "KoShapeContainer.h"
00024 
00025 #include <klocale.h>
00026 #include <kdebug.h>
00027 #include <limits.h>
00028 
00029 KoShapeReorderCommand::KoShapeReorderCommand(const QList<KoShape*> &shapes, QList<int> &newIndexes, QUndoCommand *parent)
00030         : QUndoCommand(parent)
00031         , m_shapes(shapes)
00032         , m_newIndexes(newIndexes)
00033 {
00034     Q_ASSERT(m_shapes.count() == m_newIndexes.count());
00035     foreach(KoShape *shape, shapes)
00036         m_previousIndexes.append(shape->zIndex());
00037 
00038     setText(i18n("Reorder shapes"));
00039 }
00040 
00041 void KoShapeReorderCommand::redo()
00042 {
00043     QUndoCommand::redo();
00044     for (int i = 0; i < m_shapes.count(); i++) {
00045         m_shapes.at(i)->update();
00046         m_shapes.at(i)->setZIndex(m_newIndexes.at(i));
00047         m_shapes.at(i)->update();
00048     }
00049 }
00050 
00051 void KoShapeReorderCommand::undo()
00052 {
00053     QUndoCommand::undo();
00054     for (int i = 0; i < m_shapes.count(); i++) {
00055         m_shapes.at(i)->update();
00056         m_shapes.at(i)->setZIndex(m_previousIndexes.at(i));
00057         m_shapes.at(i)->update();
00058     }
00059 }
00060 
00061 void KoShapeReorderCommand::prepare(KoShape * s, QMap<KoShape*, QList<KoShape*> > & newOrder, KoShapeManager * manager, MoveShapeType move)
00062 {
00063     KoShapeContainer * parent = s->parent();
00064     QMap<KoShape*, QList<KoShape*> >::iterator it( newOrder.find( parent ) );
00065     if ( it == newOrder.end() ) {
00066         QList<KoShape*> children;
00067         if ( parent != 0 ) {
00068             children = parent->childShapes();
00069         }
00070         else {
00071             // get all toplevel shapes
00072             children = manager->topLevelShapes();
00073         }
00074         qSort(children.begin(), children.end(), KoShape::compareShapeZIndex);
00075         // the append and prepend are needed so that the raise/lower of all shapes works as expected.
00076         children.append(0);
00077         children.prepend(0);
00078         it = newOrder.insert(parent, children);
00079     }
00080     QList<KoShape *> & shapes(newOrder[parent]);
00081     int index = shapes.indexOf(s);
00082     if (index != -1) {
00083         shapes.removeAt(index);
00084         switch ( move ) {
00085             case BringToFront:
00086                 index = shapes.size();
00087                 break;
00088             case RaiseShape:
00089                 if (index < shapes.size()) {
00090                     ++index;
00091                 }
00092                 break;
00093             case LowerShape:
00094                 if (index > 0) {
00095                     --index;
00096                 }
00097                 break;
00098             case SendToBack:
00099                 index = 0;
00100                 break;
00101         }
00102         shapes.insert(index,s);
00103     }
00104 }
00105 
00106 // static
00107 KoShapeReorderCommand *KoShapeReorderCommand::createCommand(const QList<KoShape*> &shapes, KoShapeManager *manager, MoveShapeType move, QUndoCommand *parent)
00108 {
00109     QList<int> newIndexes;
00110     QList<KoShape*> changedShapes;
00111     QMap<KoShape*, QList<KoShape*> > newOrder;
00112     QList<KoShape*> sortedShapes(shapes);
00113     qSort(sortedShapes.begin(), sortedShapes.end(), KoShape::compareShapeZIndex);
00114     if ( move == BringToFront || move == LowerShape ) {
00115         for ( int i = 0; i < sortedShapes.size(); ++i ) {
00116             prepare(sortedShapes.at(i), newOrder, manager, move);
00117         }
00118     }
00119     else {
00120         for ( int i = sortedShapes.size() - 1; i >= 0; --i ) {
00121             prepare(sortedShapes.at(i), newOrder, manager, move);
00122         }
00123     }
00124 
00125 
00126     QMap<KoShape*, QList<KoShape*> >::iterator newIt(newOrder.begin());
00127     for (; newIt!= newOrder.end(); ++newIt) {
00128         QList<KoShape*> order( newIt.value() );
00129         order.removeAll(0);
00130         int index = -2^13;
00131         int pos = 0;
00132         for (; pos < order.size(); ++pos) {
00133             if (order[pos]->zIndex() > index) {
00134                 index = order[pos]->zIndex();
00135             }
00136             else {
00137                 break;
00138             }
00139         }
00140 
00141         if (pos == order.size()) {
00142             //nothing needs to be done
00143             continue;
00144         }
00145         else if (pos <= order.size() / 2) {
00146             // new index for the front
00147             int startIndex = order[pos]->zIndex() - pos;
00148             for (int i = 0; i < pos; ++i) {
00149                 changedShapes.append(order[i]);
00150                 newIndexes.append(startIndex++);
00151             }
00152         }
00153         else {
00154             //new index for the end
00155             for (int i = pos; i < order.size(); ++i) {
00156                 changedShapes.append(order[i]);
00157                 newIndexes.append(++index);
00158             }
00159         }
00160     }
00161     Q_ASSERT(changedShapes.count() == newIndexes.count());
00162     return changedShapes.isEmpty() ? 0: new KoShapeReorderCommand(changedShapes, newIndexes, parent);
00163 }