File indexing completed on 2024-05-26 16:15:04
0001 /* This file is part of the KDE project 0002 * Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net> 0003 * Copyright (C) 2008 Fredy Yanardi <fyanardi@gmail.com> 0004 * 0005 * This library is free software; you can redistribute it and/or 0006 * modify it under the terms of the GNU Library General Public 0007 * License as published by the Free Software Foundation; either 0008 * version 2 of the License, or (at your option) any later version. 0009 * 0010 * This library is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 * Library General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU Library General Public License 0016 * along with this library; see the file COPYING.LIB. If not, write to 0017 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0018 * Boston, MA 02110-1301, USA. 0019 */ 0020 0021 #include "KoPADocumentModel.h" 0022 0023 #include "KoPADocument.h" 0024 #include "KoPAPageBase.h" 0025 #include <KoShapePainter.h> 0026 #include <KoShapeManager.h> 0027 #include <KoShapeContainer.h> 0028 #include <KoToolManager.h> 0029 #include <KoPageLayout.h> 0030 #include <KoCanvasBase.h> 0031 #include <KoCanvasController.h> 0032 #include <KoSelection.h> 0033 #include <KoShapeLayer.h> 0034 #include <KoShapeGroup.h> 0035 #include <KoShapeGroupCommand.h> 0036 #include <KoShapeUngroupCommand.h> 0037 #include <KoShapeRenameCommand.h> 0038 #include <KoZoomHandler.h> 0039 #include <KoPAOdfPageSaveHelper.h> 0040 #include <KoDrag.h> 0041 #include <KoPAPastePage.h> 0042 #include <KoIcon.h> 0043 0044 #include <klocalizedstring.h> 0045 #include <PageAppDebug.h> 0046 0047 #include <QMimeData> 0048 #include <QApplication> 0049 #include <QClipboard> 0050 #include <QMenu> 0051 #include <QPainterPath> 0052 0053 #include "commands/KoPAPageMoveCommand.h" 0054 0055 KoPADocumentModel::KoPADocumentModel( QObject* parent, KoPADocument *document ) 0056 : KoDocumentSectionModel( parent ) 0057 , m_document(0) 0058 , m_master(false) 0059 , m_lastContainer( 0 ) 0060 { 0061 setDocument( document ); 0062 } 0063 0064 Qt::DropActions KoPADocumentModel::supportedDragActions() const 0065 { 0066 return Qt::MoveAction; 0067 } 0068 0069 void KoPADocumentModel::update() 0070 { 0071 emit layoutAboutToBeChanged(); 0072 emit layoutChanged(); 0073 if (m_document) { 0074 dataChanged(index(0, 0), index(m_document->pageCount() - 1, columnCount() - 1)); 0075 } 0076 } 0077 0078 int KoPADocumentModel::rowCount( const QModelIndex &parent ) const 0079 { 0080 if (!m_document) { 0081 return 0; 0082 } 0083 0084 // check if parent is root node 0085 if ( ! parent.isValid() ) { 0086 return m_document->pages(m_master).count(); 0087 } 0088 0089 Q_ASSERT(parent.model() == this); 0090 Q_ASSERT(parent.internalPointer()); 0091 0092 KoShapeContainer *parentShape = dynamic_cast<KoShapeContainer*>( (KoShape*)parent.internalPointer() ); 0093 if ( ! parentShape ) { 0094 return 0; 0095 } 0096 0097 return parentShape->shapeCount(); 0098 } 0099 0100 int KoPADocumentModel::columnCount( const QModelIndex & ) const 0101 { 0102 return 1; 0103 } 0104 0105 QModelIndex KoPADocumentModel::index( int row, int column, const QModelIndex &parent ) const 0106 { 0107 if ( !m_document ) { 0108 return QModelIndex(); 0109 } 0110 0111 // check if parent is root node 0112 if ( ! parent.isValid() ) { 0113 if ( row >= 0 && row < m_document->pages(m_master).count() ) { 0114 return createIndex( row, column, m_document->pages(m_master).at(row) ); 0115 } else { 0116 return QModelIndex(); 0117 } 0118 } 0119 0120 Q_ASSERT(parent.model() == this); 0121 Q_ASSERT(parent.internalPointer()); 0122 0123 KoShapeContainer *parentShape = dynamic_cast<KoShapeContainer*>( (KoShape*)parent.internalPointer() ); 0124 if ( ! parentShape ) { 0125 return QModelIndex(); 0126 } 0127 0128 if ( row < parentShape->shapeCount() ) { 0129 return createIndex( row, column, childFromIndex( parentShape, row ) ); 0130 } else { 0131 return QModelIndex(); 0132 } 0133 } 0134 0135 QModelIndex KoPADocumentModel::parent( const QModelIndex &child ) const 0136 { 0137 // check if child is root node 0138 if ( ! child.isValid() || !m_document ) { 0139 return QModelIndex(); 0140 } 0141 0142 Q_ASSERT(child.model() == this); 0143 Q_ASSERT(child.internalPointer()); 0144 0145 KoShape *childShape = static_cast<KoShape*>( child.internalPointer() ); 0146 if ( ! childShape ) { 0147 return QModelIndex(); 0148 } 0149 0150 // get the children's parent shape 0151 KoShapeContainer *parentShape = childShape->parent(); 0152 if ( ! parentShape ) { 0153 return QModelIndex(); 0154 } 0155 0156 // get the grandparent to determine the row of the parent shape 0157 KoShapeContainer *grandParentShape = parentShape->parent(); 0158 if ( ! grandParentShape ) { 0159 KoPAPageBase* page = dynamic_cast<KoPAPageBase*>( parentShape); 0160 return createIndex( m_document->pages(m_master).indexOf( page ), 0, parentShape ); 0161 } 0162 0163 return createIndex( indexFromChild( grandParentShape, parentShape ), 0, parentShape ); 0164 } 0165 0166 QVariant KoPADocumentModel::data( const QModelIndex &index, int role ) const 0167 { 0168 if ( ! index.isValid() || !m_document ) { 0169 return QVariant(); 0170 } 0171 0172 Q_ASSERT(index.model() == this); 0173 Q_ASSERT(index.internalPointer()); 0174 0175 KoShape *shape = static_cast<KoShape*>( index.internalPointer() ); 0176 0177 switch (role) 0178 { 0179 case Qt::DisplayRole: 0180 { 0181 QString name = shape->name(); 0182 if ( name.isEmpty() ) { 0183 if ( dynamic_cast<KoPAPageBase *>( shape ) ) { 0184 if (m_document->pageType() == KoPageApp::Slide ) { 0185 name = i18n("Slide %1", m_document->pageIndex(dynamic_cast<KoPAPageBase *>(shape)) + 1); 0186 } else { 0187 name = i18n("Page %1", m_document->pageIndex(dynamic_cast<KoPAPageBase *>(shape)) + 1); 0188 } 0189 } else if ( dynamic_cast<KoShapeLayer*>( shape ) ) { 0190 name = i18n("Layer") + QString(" (%1)").arg(shape->zIndex()); 0191 } else if ( dynamic_cast<KoShapeGroup*>( shape ) ) { 0192 name = i18n("Group") + QString(" (%1)").arg(shape->zIndex()); 0193 } else { 0194 name = i18n("Shape") + QString(" (%1)").arg(shape->zIndex()); 0195 } 0196 } 0197 return name; 0198 } 0199 case Qt::DecorationRole: return QVariant();//return shape->icon(); 0200 case Qt::EditRole: return shape->name(); 0201 case Qt::SizeHintRole: 0202 { 0203 KoPAPageBase *page = dynamic_cast<KoPAPageBase*>(shape); 0204 if (page) { // return actual page size for page 0205 KoPageLayout layout = page->pageLayout(); 0206 return QSize(layout.width, layout.height); 0207 } 0208 else 0209 return shape->size(); 0210 } 0211 case ActiveRole: 0212 { 0213 KoCanvasController * canvasController = KoToolManager::instance()->activeCanvasController(); 0214 KoSelection * selection = canvasController->canvas()->shapeManager()->selection(); 0215 if ( ! selection ) { 0216 return false; 0217 } 0218 0219 /* KoShapeLayer *layer = dynamic_cast<KoShapeLayer*>( shape ); 0220 if ( layer ) 0221 return (layer == selection->activeLayer() ); 0222 else */ 0223 return selection->isSelected( shape ); 0224 } 0225 case PropertiesRole: return QVariant::fromValue( properties( shape ) ); 0226 case AspectRatioRole: 0227 { 0228 QTransform matrix = shape->absoluteTransformation( 0 ); 0229 QRectF bbox = matrix.mapRect( shape->outline().boundingRect() ); 0230 KoShapeContainer *container = dynamic_cast<KoShapeContainer*>( shape ); 0231 if ( container ) { 0232 bbox = QRectF(); 0233 foreach( KoShape* shape, container->shapes() ) { 0234 bbox = bbox.united( shape->outline().boundingRect() ); 0235 } 0236 } 0237 return qreal(bbox.width()) / bbox.height(); 0238 } 0239 default: 0240 if (role >= int(BeginThumbnailRole)) { 0241 return createThumbnail( shape, QSize( role - int(BeginThumbnailRole), role - int(BeginThumbnailRole) ) ); 0242 } else { 0243 return QVariant(); 0244 } 0245 } 0246 } 0247 0248 Qt::ItemFlags KoPADocumentModel::flags(const QModelIndex &index) const 0249 { 0250 if ( !m_document ) { 0251 return 0; 0252 } 0253 0254 if ( ! index.isValid() ) { 0255 return Qt::ItemIsEnabled | Qt::ItemIsDropEnabled; 0256 } 0257 0258 Q_ASSERT(index.model() == this); 0259 Q_ASSERT(index.internalPointer()); 0260 0261 Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEditable; 0262 //if ( dynamic_cast<KoShapeContainer*>( (KoShape*)index.internalPointer() ) ) 0263 flags |= Qt::ItemIsDropEnabled; 0264 return flags; 0265 } 0266 0267 bool KoPADocumentModel::setData(const QModelIndex &index, const QVariant &value, int role ) 0268 { 0269 if ( ! index.isValid() || !m_document ) { 0270 return false; 0271 } 0272 0273 Q_ASSERT(index.model() == this); 0274 Q_ASSERT(index.internalPointer()); 0275 0276 KoShape *shape = static_cast<KoShape*>( index.internalPointer() ); 0277 switch (role) 0278 { 0279 case Qt::DisplayRole: 0280 case Qt::EditRole: 0281 { 0282 KUndo2Command * cmd = new KoShapeRenameCommand( shape, value.toString() ); 0283 if (dynamic_cast<KoPAPageBase *>(shape)) { 0284 if (m_document->pageType() == KoPageApp::Slide) { 0285 cmd->setText(kundo2_i18n("Rename Slide")); 0286 } else { 0287 cmd->setText(kundo2_i18n("Rename Page")); 0288 } 0289 } 0290 else if (dynamic_cast<KoShapeLayer *>(shape)) { 0291 cmd->setText(kundo2_i18n("Rename Layer")); 0292 } 0293 m_document->addCommand( cmd ); 0294 } break; 0295 case PropertiesRole: 0296 setProperties( shape, value.value<PropertyList>()); 0297 break; 0298 case ActiveRole: 0299 /* if (value.toBool()) 0300 { 0301 KoCanvasController * canvasController = KoToolManager::instance()->activeCanvasController(); 0302 KoSelection * selection = canvasController->canvas()->shapeManager()->selection(); 0303 0304 KoShapeLayer *layer = dynamic_cast<KoShapeLayer*>( shape ); 0305 if ( layer && selection ) { 0306 selection->setActiveLayer( layer ); 0307 } 0308 } */ 0309 break; 0310 default: 0311 return false; 0312 } 0313 0314 emit dataChanged( index, index ); 0315 return true; 0316 } 0317 0318 KoDocumentSectionModel::PropertyList KoPADocumentModel::properties( KoShape* shape ) const 0319 { 0320 PropertyList l; 0321 0322 if (KoPAPageBase *page = dynamic_cast<KoPAPageBase *>(shape)) { 0323 // The idea is to display the page-number so users know what page-number/slide-number 0324 // the shape has also in the case the slide has a name (in which case it's not named 0325 // "Slide [slide-number]" any longer. 0326 // Maybe we should better use KoTextPage::visiblePageNumber here? 0327 l << Property(i18n("Slide"), QString::number(m_document->pageIndex(page) + 1)); 0328 } 0329 0330 l << Property(i18n("Visible"), koIcon("layer-visible-on"), koIcon("layer-visible-off"), shape->isVisible()); 0331 l << Property(i18n("Locked"), koIcon("object-locked"), koIcon("object-unlocked"), shape->isGeometryProtected()); 0332 return l; 0333 } 0334 0335 void KoPADocumentModel::setProperties( KoShape* shape, const PropertyList &properties ) 0336 { 0337 bool oldVisibleState = shape->isVisible(); 0338 bool oldLockedState = shape->isGeometryProtected(); 0339 0340 shape->setVisible( properties.at( 0 ).state.toBool() ); 0341 shape->setGeometryProtected( properties.at( 1 ).state.toBool() ); 0342 0343 if ( ( oldVisibleState != shape->isVisible() ) || ( oldLockedState != shape->isGeometryProtected() ) ) { 0344 shape->update(); 0345 } 0346 } 0347 0348 QImage KoPADocumentModel::createThumbnail( KoShape* shape, const QSize &thumbSize ) const 0349 { 0350 QSize size(thumbSize.width(), thumbSize.height()); 0351 KoShapePainter shapePainter; 0352 0353 KoPAPageBase *page = dynamic_cast<KoPAPageBase*>(shape); 0354 if (page) { // We create a thumbnail with actual width / height ratio for page 0355 KoZoomHandler zoomHandler; 0356 KoPageLayout layout = page->pageLayout(); 0357 qreal ratio = (zoomHandler.resolutionX() * layout.width) / (zoomHandler.resolutionY() * layout.height); 0358 if ( ratio > 1 ) { 0359 size.setHeight( size.width() / ratio ); 0360 } else { 0361 size.setWidth( size.height() * ratio ); 0362 } 0363 QPixmap pixmap = m_document->pageThumbnail( page, size ); 0364 return pixmap.toImage(); 0365 } 0366 0367 QList<KoShape*> shapes; 0368 KoShapeContainer *container = dynamic_cast<KoShapeContainer*>(shape); 0369 if (container) { 0370 shapes = container->shapes(); 0371 } 0372 shapes.append(shape); 0373 0374 shapePainter.setShapes( shapes ); 0375 0376 QImage thumb( size, QImage::Format_RGB32 ); 0377 // draw the background of the thumbnail 0378 thumb.fill( QColor( Qt::white ).rgb() ); 0379 shapePainter.paint(thumb); 0380 0381 return thumb; 0382 } 0383 0384 KoShape * KoPADocumentModel::childFromIndex( KoShapeContainer *parent, int row ) const 0385 { 0386 return parent->shapes().at(row); 0387 } 0388 0389 int KoPADocumentModel::indexFromChild( KoShapeContainer *parent, KoShape *child ) const 0390 { 0391 if ( !m_document ) { 0392 return 0; 0393 } 0394 0395 return parent->shapes().indexOf( child ); 0396 } 0397 0398 Qt::DropActions KoPADocumentModel::supportedDropActions () const 0399 { 0400 return Qt::MoveAction | Qt::CopyAction; 0401 } 0402 0403 QStringList KoPADocumentModel::mimeTypes() const 0404 { 0405 QStringList types; 0406 types << QLatin1String("application/x-kopalayermodeldatalist"); 0407 return types; 0408 } 0409 0410 QMimeData * KoPADocumentModel::mimeData( const QModelIndexList & indexes ) const 0411 { 0412 // check if there is data to encode 0413 if ( ! indexes.count() ) { 0414 return 0; 0415 } 0416 0417 // check if we support a format 0418 QStringList types = mimeTypes(); 0419 if ( types.isEmpty() ) { 0420 return 0; 0421 } 0422 0423 QMimeData *data = new QMimeData(); 0424 QString format = types[0]; 0425 QByteArray encoded; 0426 QDataStream stream(&encoded, QIODevice::WriteOnly); 0427 0428 // encode the data 0429 QModelIndexList::ConstIterator it = indexes.begin(); 0430 for( ; it != indexes.end(); ++it) { 0431 stream << QVariant::fromValue( qulonglong( it->internalPointer() ) ); 0432 } 0433 0434 data->setData(format, encoded); 0435 return data; 0436 } 0437 0438 bool KoPADocumentModel::dropMimeData( const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent ) 0439 { 0440 Q_UNUSED( row ); 0441 Q_UNUSED( column ); 0442 0443 // check if the action is supported 0444 if ( ! data || action != Qt::MoveAction ) { 0445 return false; 0446 } 0447 // check if the format is supported 0448 QStringList types = mimeTypes(); 0449 if ( types.isEmpty() ) { 0450 return false; 0451 } 0452 QString format = types[0]; 0453 if ( ! data->hasFormat(format) ) { 0454 return false; 0455 } 0456 0457 QByteArray encoded = data->data( format ); 0458 QDataStream stream(&encoded, QIODevice::ReadOnly); 0459 QList<KoShape*> shapes; 0460 0461 // decode the data 0462 while( ! stream.atEnd() ) { 0463 QVariant v; 0464 stream >> v; 0465 shapes.append( static_cast<KoShape*>( (void*)v.value<qulonglong>() ) ); 0466 } 0467 0468 QList<KoShape*> toplevelShapes; 0469 QList<KoShapeLayer*> layers; 0470 QList<KoPAPageBase *> pages; 0471 // remove shapes having its parent in the list 0472 // and separate the layers 0473 foreach( KoShape * shape, shapes ) { 0474 // check whether the selection contains page 0475 // by the UI rules, the selection should contains page only 0476 KoPAPageBase *page = dynamic_cast<KoPAPageBase *>( shape ); 0477 if ( page ) { 0478 pages.append( page ); 0479 continue; 0480 } 0481 0482 KoShapeContainer *parentShape = shape->parent(); 0483 bool hasParentInList = false; 0484 while ( parentShape ) { 0485 if ( shapes.contains( parentShape ) ) { 0486 hasParentInList = true; 0487 break; 0488 } 0489 parentShape = parentShape->parent(); 0490 } 0491 if ( hasParentInList ) { 0492 continue; 0493 } 0494 0495 KoShapeLayer * layer = dynamic_cast<KoShapeLayer*>( shape ); 0496 if ( layer ) { 0497 layers.append( layer ); 0498 } else { 0499 toplevelShapes.append( shape ); 0500 } 0501 } 0502 0503 // dropping to root, only page(s) is allowed 0504 if (!parent.isValid()) { 0505 if ( !pages.isEmpty() ) { 0506 if ( row < 0 ) { 0507 return false; 0508 } 0509 KoPAPageBase *after = (row != 0) ? m_document->pageByIndex(row - 1, false) : 0; 0510 debugPageApp << "KoPADocumentModel::dropMimeData parent = root, dropping page(s) as root, moving page(s)"; 0511 return doDrop(pages, after, action); 0512 } 0513 else { 0514 debugPageApp << "KoPADocumentModel::dropMimeData parent = root, dropping non-page as root, returning false"; 0515 return false; 0516 } 0517 } 0518 else if (parent.isValid() && !pages.isEmpty()){ 0519 if (parent.row() < 0) { 0520 return false; 0521 } 0522 KoPAPageBase *after; 0523 if ((m_document->pageIndex(pages.first()) - 1) == parent.row()) { 0524 after = (parent.row() != 0) ? m_document->pageByIndex(parent.row() - 1, false) : 0; 0525 } 0526 else { 0527 after = (parent.row() > -1) ? m_document->pageByIndex(parent.row(), false) : 0; 0528 } 0529 return doDrop(pages, after, action); 0530 } 0531 0532 KoShape *shape = static_cast<KoShape*>( parent.internalPointer() ); 0533 KoShapeContainer * container = dynamic_cast<KoShapeContainer*>( shape ); 0534 if ( container ) { 0535 KoShapeGroup * group = dynamic_cast<KoShapeGroup*>( container ); 0536 if ( group ) { 0537 debugPageApp <<"KoPADocumentModel::dropMimeData parent = group"; 0538 if ( ! toplevelShapes.count() ) { 0539 return false; 0540 } 0541 0542 emit layoutAboutToBeChanged(); 0543 beginInsertRows( parent, group->shapeCount(), group->shapeCount()+toplevelShapes.count() ); 0544 0545 KUndo2Command * cmd = new KUndo2Command(); 0546 cmd->setText( kundo2_i18n("Reparent shapes") ); 0547 0548 foreach( KoShape * shape, toplevelShapes ) { 0549 new KoShapeUngroupCommand( shape->parent(), QList<KoShape*>() << shape, QList<KoShape*>(), cmd ); 0550 } 0551 0552 new KoShapeGroupCommand( group, toplevelShapes, cmd ); 0553 KoCanvasController * canvasController = KoToolManager::instance()->activeCanvasController(); 0554 canvasController->canvas()->addCommand( cmd ); 0555 0556 endInsertRows(); 0557 emit layoutChanged(); 0558 } else { 0559 debugPageApp <<"KoPADocumentModel::dropMimeData parent = container"; 0560 if ( toplevelShapes.count() ) { 0561 emit layoutAboutToBeChanged(); 0562 beginInsertRows( parent, container->shapeCount(), container->shapeCount()+toplevelShapes.count() ); 0563 0564 KUndo2Command * cmd = new KUndo2Command(); 0565 cmd->setText( kundo2_i18n("Reparent shapes") ); 0566 0567 QList<bool> clipped; 0568 QList<bool> inheritsTransform; 0569 foreach( KoShape * shape, toplevelShapes ) { 0570 if ( ! shape->parent() ) { 0571 clipped.append( false ); 0572 inheritsTransform.append(false); 0573 continue; 0574 } 0575 0576 clipped.append( shape->parent()->isClipped( shape ) ); 0577 inheritsTransform.append(shape->parent()->inheritsTransform(shape)); 0578 new KoShapeUngroupCommand( shape->parent(), QList<KoShape*>() << shape, QList<KoShape*>(), cmd ); 0579 } 0580 // shapes are dropped on a container, so add them to the container 0581 new KoShapeGroupCommand(container, toplevelShapes, clipped, inheritsTransform, cmd); 0582 KoCanvasController * canvasController = KoToolManager::instance()->activeCanvasController(); 0583 canvasController->canvas()->addCommand( cmd ); 0584 0585 endInsertRows(); 0586 emit layoutChanged(); 0587 } else if ( layers.count() ) { 0588 KoShapeLayer * layer = dynamic_cast<KoShapeLayer*>( container ); 0589 if ( ! layer ) { 0590 return false; 0591 } 0592 0593 // TODO layers are dropped on a layer, so change layer ordering 0594 return false; 0595 } 0596 } 0597 } else { 0598 debugPageApp <<"KoPADocumentModel::dropMimeData parent = shape"; 0599 if ( ! toplevelShapes.count() ) { 0600 return false; 0601 } 0602 0603 // TODO shapes are dropped on a shape, reorder them 0604 return false; 0605 } 0606 0607 return true; 0608 } 0609 0610 QModelIndex KoPADocumentModel::parentIndexFromShape( const KoShape * child ) 0611 { 0612 if ( !m_document ) { 0613 return QModelIndex(); 0614 } 0615 0616 // check if child shape is a layer, and return invalid model index if it is 0617 const KoShapeLayer *childlayer = dynamic_cast<const KoShapeLayer*>( child ); 0618 if ( childlayer ) { 0619 return QModelIndex(); 0620 } 0621 0622 // get the children's parent shape 0623 KoShapeContainer *parentShape = child->parent(); 0624 if ( ! parentShape ) { 0625 return QModelIndex(); 0626 } 0627 0628 // check if the parent is a layer 0629 KoShapeLayer *parentLayer = dynamic_cast<KoShapeLayer*>( parentShape ); 0630 0631 0632 if ( parentLayer ) { 0633 KoPAPageBase * page = dynamic_cast<KoPAPageBase*>( parentLayer->parent() ); 0634 if ( page ) { 0635 return createIndex( m_document->pages(m_master).count() - 1 - m_document->pages(m_master).indexOf( page ), 0, parentLayer ); 0636 } 0637 } 0638 // get the grandparent to determine the row of the parent shape 0639 KoShapeContainer *grandParentShape = parentShape->parent(); 0640 if ( ! grandParentShape ) { 0641 return QModelIndex(); 0642 } 0643 0644 return createIndex( indexFromChild( grandParentShape, parentShape ), 0, parentShape ); 0645 } 0646 0647 void KoPADocumentModel::setDocument( KoPADocument* document ) 0648 { 0649 if (m_document == document) { 0650 return; 0651 } 0652 0653 if (m_document) { 0654 disconnect( m_document, SIGNAL(pageAdded(KoPAPageBase*)), this, SLOT(update()) ); 0655 disconnect( m_document, SIGNAL(pageRemoved(KoPAPageBase*)), this, SLOT(update()) ); 0656 disconnect( m_document, SIGNAL(update(KoPAPageBase*)), this, SLOT(update()) ); 0657 disconnect( m_document, SIGNAL(shapeAdded(KoShape*)), this, SLOT(update()) ); 0658 disconnect( m_document, SIGNAL(shapeRemoved(KoShape*)), this, SLOT(update()) ); 0659 } 0660 0661 beginResetModel(); 0662 m_document = document; 0663 endResetModel(); 0664 0665 if ( m_document ) { 0666 connect( m_document, SIGNAL(pageAdded(KoPAPageBase*)), this, SLOT(update()) ); 0667 connect( m_document, SIGNAL(pageRemoved(KoPAPageBase*)), this, SLOT(update()) ); 0668 connect( m_document, SIGNAL(update(KoPAPageBase*)), this, SLOT(update()) ); 0669 connect( m_document, SIGNAL(shapeAdded(KoShape*)), this, SLOT(update()) ); 0670 connect( m_document, SIGNAL(shapeRemoved(KoShape*)), this, SLOT(update()) ); 0671 } 0672 } 0673 0674 void KoPADocumentModel::setMasterMode(bool master) 0675 { 0676 m_master = master; 0677 update(); // Rebuild the model 0678 } 0679 0680 bool KoPADocumentModel::doDrop(QList<KoPAPageBase *> pages, KoPAPageBase *pageAfter, Qt::DropAction action) 0681 { 0682 Qt::KeyboardModifiers modifiers = QApplication::keyboardModifiers(); 0683 bool enableMove = true; 0684 0685 foreach (KoPAPageBase *page, pages) { 0686 if (!m_document->pages(false).contains(page)) { 0687 KoPAPageBase *newPage = page; 0688 pages.replace(pages.indexOf(page), newPage); 0689 enableMove = false; 0690 break; 0691 } 0692 } 0693 0694 if (((modifiers & Qt::ControlModifier) == 0) && 0695 ((modifiers & Qt::ShiftModifier) == 0)) { 0696 QMenu popup; 0697 QString seq = QKeySequence(Qt::ShiftModifier).toString(); 0698 seq.chop(1); 0699 QAction *popupMoveAction = new QAction(i18n("&Move Here") + '\t' + seq, this); 0700 popupMoveAction->setIcon(koIcon("go-jump")); 0701 seq = QKeySequence(Qt::ControlModifier).toString(); 0702 seq.chop(1); 0703 QAction *popupCopyAction = new QAction(i18n("&Copy Here") + '\t' + seq, this); 0704 popupCopyAction->setIcon(koIcon("edit-copy")); 0705 seq = QKeySequence( Qt::ControlModifier + Qt::ShiftModifier ).toString(); 0706 seq.chop(1); 0707 QAction *popupCancelAction = new QAction(i18n("C&ancel") + '\t' + QKeySequence(Qt::Key_Escape).toString(), this); 0708 popupCancelAction->setIcon(koIcon("process-stop")); 0709 0710 if (enableMove) { 0711 popup.addAction(popupMoveAction); 0712 } 0713 popup.addAction(popupCopyAction); 0714 popup.addSeparator(); 0715 popup.addAction(popupCancelAction); 0716 0717 QAction *result = popup.exec(QCursor::pos()); 0718 0719 if (result == popupCopyAction) { 0720 action = Qt::CopyAction; 0721 } else if (result == popupMoveAction) { 0722 action = Qt::MoveAction; 0723 } else { 0724 return false; 0725 } 0726 } else if ((modifiers & Qt::ControlModifier) != 0) { 0727 action = Qt::CopyAction; 0728 } else if ((modifiers & Qt::ShiftModifier) != 0) { 0729 action = Qt::MoveAction; 0730 } else { 0731 return false; 0732 } 0733 0734 switch (action) { 0735 case Qt::MoveAction: { 0736 KoPAPageMoveCommand *command = new KoPAPageMoveCommand(m_document, pages, pageAfter); 0737 m_document->addCommand( command ); 0738 if ((m_document->pageIndex(pageAfter) + pages.count()) < m_document->pageCount()) { 0739 emit requestPageSelection(m_document->pageIndex(pageAfter) + 1, pages.count()); 0740 } 0741 return true; 0742 } 0743 case Qt::CopyAction: { 0744 // Copy Pages 0745 KoPAOdfPageSaveHelper saveHelper(m_document, pages); 0746 KoDrag drag; 0747 drag.setOdf(KoOdf::mimeType(m_document->documentType()), saveHelper); 0748 drag.addToClipboard(); 0749 //Paste Pages 0750 const QMimeData * data = QApplication::clipboard()->mimeData(); 0751 static const KoOdf::DocumentType documentTypes[] = { KoOdf::Graphics, KoOdf::Presentation }; 0752 0753 for (unsigned int i = 0; i < sizeof(documentTypes) / sizeof(KoOdf::DocumentType); ++i) { 0754 if (data->hasFormat( KoOdf::mimeType(documentTypes[i]))) { 0755 KoPAPastePage paste(m_document, pageAfter); 0756 paste.paste(documentTypes[i], data); 0757 break; 0758 } 0759 } 0760 emit requestPageSelection(m_document->pageIndex(pageAfter) + 1, sizeof(documentTypes) / sizeof(KoOdf::DocumentType) - 1); 0761 return true; 0762 } 0763 default: 0764 qDebug("Unknown action: %d ", (int)action); 0765 return false; 0766 } 0767 return false; 0768 }