1 /* This file is part of the KDE project
2 * Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
3 * Copyright (C) 2008 Fredy Yanardi <fyanardi@gmail.com>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #include "KoPADocumentModel.h"
22
23 #include "KoPADocument.h"
24 #include "KoPAPageBase.h"
25 #include <KoShapePainter.h>
26 #include <KoShapeManager.h>
27 #include <KoShapeContainer.h>
28 #include <KoToolManager.h>
29 #include <KoPageLayout.h>
30 #include <KoCanvasBase.h>
31 #include <KoCanvasController.h>
32 #include <KoSelection.h>
33 #include <KoShapeLayer.h>
34 #include <KoShapeGroup.h>
35 #include <KoShapeGroupCommand.h>
36 #include <KoShapeUngroupCommand.h>
37 #include <KoShapeRenameCommand.h>
38 #include <KoZoomHandler.h>
39 #include <KoPAOdfPageSaveHelper.h>
40 #include <KoDrag.h>
41 #include <KoPAPastePage.h>
42 #include <KoIcon.h>
43
44 #include <klocalizedstring.h>
45 #include <PageAppDebug.h>
46
47 #include <QMimeData>
48 #include <QApplication>
49 #include <QClipboard>
50 #include <QMenu>
51 #include <QPainterPath>
52
53 #include "commands/KoPAPageMoveCommand.h"
54
KoPADocumentModel(QObject * parent,KoPADocument * document)55 KoPADocumentModel::KoPADocumentModel( QObject* parent, KoPADocument *document )
56 : KoDocumentSectionModel( parent )
57 , m_document(0)
58 , m_master(false)
59 , m_lastContainer( 0 )
60 {
61 setDocument( document );
62 }
63
supportedDragActions() const64 Qt::DropActions KoPADocumentModel::supportedDragActions() const
65 {
66 return Qt::MoveAction;
67 }
68
update()69 void KoPADocumentModel::update()
70 {
71 emit layoutAboutToBeChanged();
72 emit layoutChanged();
73 if (m_document) {
74 dataChanged(index(0, 0), index(m_document->pageCount() - 1, columnCount() - 1));
75 }
76 }
77
rowCount(const QModelIndex & parent) const78 int KoPADocumentModel::rowCount( const QModelIndex &parent ) const
79 {
80 if (!m_document) {
81 return 0;
82 }
83
84 // check if parent is root node
85 if ( ! parent.isValid() ) {
86 return m_document->pages(m_master).count();
87 }
88
89 Q_ASSERT(parent.model() == this);
90 Q_ASSERT(parent.internalPointer());
91
92 KoShapeContainer *parentShape = dynamic_cast<KoShapeContainer*>( (KoShape*)parent.internalPointer() );
93 if ( ! parentShape ) {
94 return 0;
95 }
96
97 return parentShape->shapeCount();
98 }
99
columnCount(const QModelIndex &) const100 int KoPADocumentModel::columnCount( const QModelIndex & ) const
101 {
102 return 1;
103 }
104
index(int row,int column,const QModelIndex & parent) const105 QModelIndex KoPADocumentModel::index( int row, int column, const QModelIndex &parent ) const
106 {
107 if ( !m_document ) {
108 return QModelIndex();
109 }
110
111 // check if parent is root node
112 if ( ! parent.isValid() ) {
113 if ( row >= 0 && row < m_document->pages(m_master).count() ) {
114 return createIndex( row, column, m_document->pages(m_master).at(row) );
115 } else {
116 return QModelIndex();
117 }
118 }
119
120 Q_ASSERT(parent.model() == this);
121 Q_ASSERT(parent.internalPointer());
122
123 KoShapeContainer *parentShape = dynamic_cast<KoShapeContainer*>( (KoShape*)parent.internalPointer() );
124 if ( ! parentShape ) {
125 return QModelIndex();
126 }
127
128 if ( row < parentShape->shapeCount() ) {
129 return createIndex( row, column, childFromIndex( parentShape, row ) );
130 } else {
131 return QModelIndex();
132 }
133 }
134
parent(const QModelIndex & child) const135 QModelIndex KoPADocumentModel::parent( const QModelIndex &child ) const
136 {
137 // check if child is root node
138 if ( ! child.isValid() || !m_document ) {
139 return QModelIndex();
140 }
141
142 Q_ASSERT(child.model() == this);
143 Q_ASSERT(child.internalPointer());
144
145 KoShape *childShape = static_cast<KoShape*>( child.internalPointer() );
146 if ( ! childShape ) {
147 return QModelIndex();
148 }
149
150 // get the children's parent shape
151 KoShapeContainer *parentShape = childShape->parent();
152 if ( ! parentShape ) {
153 return QModelIndex();
154 }
155
156 // get the grandparent to determine the row of the parent shape
157 KoShapeContainer *grandParentShape = parentShape->parent();
158 if ( ! grandParentShape ) {
159 KoPAPageBase* page = dynamic_cast<KoPAPageBase*>( parentShape);
160 return createIndex( m_document->pages(m_master).indexOf( page ), 0, parentShape );
161 }
162
163 return createIndex( indexFromChild( grandParentShape, parentShape ), 0, parentShape );
164 }
165
data(const QModelIndex & index,int role) const166 QVariant KoPADocumentModel::data( const QModelIndex &index, int role ) const
167 {
168 if ( ! index.isValid() || !m_document ) {
169 return QVariant();
170 }
171
172 Q_ASSERT(index.model() == this);
173 Q_ASSERT(index.internalPointer());
174
175 KoShape *shape = static_cast<KoShape*>( index.internalPointer() );
176
177 switch (role)
178 {
179 case Qt::DisplayRole:
180 {
181 QString name = shape->name();
182 if ( name.isEmpty() ) {
183 if ( dynamic_cast<KoPAPageBase *>( shape ) ) {
184 if (m_document->pageType() == KoPageApp::Slide ) {
185 name = i18n("Slide %1", m_document->pageIndex(dynamic_cast<KoPAPageBase *>(shape)) + 1);
186 } else {
187 name = i18n("Page %1", m_document->pageIndex(dynamic_cast<KoPAPageBase *>(shape)) + 1);
188 }
189 } else if ( dynamic_cast<KoShapeLayer*>( shape ) ) {
190 name = i18n("Layer") + QString(" (%1)").arg(shape->zIndex());
191 } else if ( dynamic_cast<KoShapeGroup*>( shape ) ) {
192 name = i18n("Group") + QString(" (%1)").arg(shape->zIndex());
193 } else {
194 name = i18n("Shape") + QString(" (%1)").arg(shape->zIndex());
195 }
196 }
197 return name;
198 }
199 case Qt::DecorationRole: return QVariant();//return shape->icon();
200 case Qt::EditRole: return shape->name();
201 case Qt::SizeHintRole:
202 {
203 KoPAPageBase *page = dynamic_cast<KoPAPageBase*>(shape);
204 if (page) { // return actual page size for page
205 KoPageLayout layout = page->pageLayout();
206 return QSize(layout.width, layout.height);
207 }
208 else
209 return shape->size();
210 }
211 case ActiveRole:
212 {
213 KoCanvasController * canvasController = KoToolManager::instance()->activeCanvasController();
214 KoSelection * selection = canvasController->canvas()->shapeManager()->selection();
215 if ( ! selection ) {
216 return false;
217 }
218
219 /* KoShapeLayer *layer = dynamic_cast<KoShapeLayer*>( shape );
220 if ( layer )
221 return (layer == selection->activeLayer() );
222 else */
223 return selection->isSelected( shape );
224 }
225 case PropertiesRole: return QVariant::fromValue( properties( shape ) );
226 case AspectRatioRole:
227 {
228 QTransform matrix = shape->absoluteTransformation( 0 );
229 QRectF bbox = matrix.mapRect( shape->outline().boundingRect() );
230 KoShapeContainer *container = dynamic_cast<KoShapeContainer*>( shape );
231 if ( container ) {
232 bbox = QRectF();
233 foreach( KoShape* shape, container->shapes() ) {
234 bbox = bbox.united( shape->outline().boundingRect() );
235 }
236 }
237 return qreal(bbox.width()) / bbox.height();
238 }
239 default:
240 if (role >= int(BeginThumbnailRole)) {
241 return createThumbnail( shape, QSize( role - int(BeginThumbnailRole), role - int(BeginThumbnailRole) ) );
242 } else {
243 return QVariant();
244 }
245 }
246 }
247
flags(const QModelIndex & index) const248 Qt::ItemFlags KoPADocumentModel::flags(const QModelIndex &index) const
249 {
250 if ( !m_document ) {
251 return 0;
252 }
253
254 if ( ! index.isValid() ) {
255 return Qt::ItemIsEnabled | Qt::ItemIsDropEnabled;
256 }
257
258 Q_ASSERT(index.model() == this);
259 Q_ASSERT(index.internalPointer());
260
261 Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEditable;
262 //if ( dynamic_cast<KoShapeContainer*>( (KoShape*)index.internalPointer() ) )
263 flags |= Qt::ItemIsDropEnabled;
264 return flags;
265 }
266
setData(const QModelIndex & index,const QVariant & value,int role)267 bool KoPADocumentModel::setData(const QModelIndex &index, const QVariant &value, int role )
268 {
269 if ( ! index.isValid() || !m_document ) {
270 return false;
271 }
272
273 Q_ASSERT(index.model() == this);
274 Q_ASSERT(index.internalPointer());
275
276 KoShape *shape = static_cast<KoShape*>( index.internalPointer() );
277 switch (role)
278 {
279 case Qt::DisplayRole:
280 case Qt::EditRole:
281 {
282 KUndo2Command * cmd = new KoShapeRenameCommand( shape, value.toString() );
283 if (dynamic_cast<KoPAPageBase *>(shape)) {
284 if (m_document->pageType() == KoPageApp::Slide) {
285 cmd->setText(kundo2_i18n("Rename Slide"));
286 } else {
287 cmd->setText(kundo2_i18n("Rename Page"));
288 }
289 }
290 else if (dynamic_cast<KoShapeLayer *>(shape)) {
291 cmd->setText(kundo2_i18n("Rename Layer"));
292 }
293 m_document->addCommand( cmd );
294 } break;
295 case PropertiesRole:
296 setProperties( shape, value.value<PropertyList>());
297 break;
298 case ActiveRole:
299 /* if (value.toBool())
300 {
301 KoCanvasController * canvasController = KoToolManager::instance()->activeCanvasController();
302 KoSelection * selection = canvasController->canvas()->shapeManager()->selection();
303
304 KoShapeLayer *layer = dynamic_cast<KoShapeLayer*>( shape );
305 if ( layer && selection ) {
306 selection->setActiveLayer( layer );
307 }
308 } */
309 break;
310 default:
311 return false;
312 }
313
314 emit dataChanged( index, index );
315 return true;
316 }
317
properties(KoShape * shape) const318 KoDocumentSectionModel::PropertyList KoPADocumentModel::properties( KoShape* shape ) const
319 {
320 PropertyList l;
321
322 if (KoPAPageBase *page = dynamic_cast<KoPAPageBase *>(shape)) {
323 // The idea is to display the page-number so users know what page-number/slide-number
324 // the shape has also in the case the slide has a name (in which case it's not named
325 // "Slide [slide-number]" any longer.
326 // Maybe we should better use KoTextPage::visiblePageNumber here?
327 l << Property(i18n("Slide"), QString::number(m_document->pageIndex(page) + 1));
328 }
329
330 l << Property(i18n("Visible"), koIcon("layer-visible-on"), koIcon("layer-visible-off"), shape->isVisible());
331 l << Property(i18n("Locked"), koIcon("object-locked"), koIcon("object-unlocked"), shape->isGeometryProtected());
332 return l;
333 }
334
setProperties(KoShape * shape,const PropertyList & properties)335 void KoPADocumentModel::setProperties( KoShape* shape, const PropertyList &properties )
336 {
337 bool oldVisibleState = shape->isVisible();
338 bool oldLockedState = shape->isGeometryProtected();
339
340 shape->setVisible( properties.at( 0 ).state.toBool() );
341 shape->setGeometryProtected( properties.at( 1 ).state.toBool() );
342
343 if ( ( oldVisibleState != shape->isVisible() ) || ( oldLockedState != shape->isGeometryProtected() ) ) {
344 shape->update();
345 }
346 }
347
createThumbnail(KoShape * shape,const QSize & thumbSize) const348 QImage KoPADocumentModel::createThumbnail( KoShape* shape, const QSize &thumbSize ) const
349 {
350 QSize size(thumbSize.width(), thumbSize.height());
351 KoShapePainter shapePainter;
352
353 KoPAPageBase *page = dynamic_cast<KoPAPageBase*>(shape);
354 if (page) { // We create a thumbnail with actual width / height ratio for page
355 KoZoomHandler zoomHandler;
356 KoPageLayout layout = page->pageLayout();
357 qreal ratio = (zoomHandler.resolutionX() * layout.width) / (zoomHandler.resolutionY() * layout.height);
358 if ( ratio > 1 ) {
359 size.setHeight( size.width() / ratio );
360 } else {
361 size.setWidth( size.height() * ratio );
362 }
363 QPixmap pixmap = m_document->pageThumbnail( page, size );
364 return pixmap.toImage();
365 }
366
367 QList<KoShape*> shapes;
368 KoShapeContainer *container = dynamic_cast<KoShapeContainer*>(shape);
369 if (container) {
370 shapes = container->shapes();
371 }
372 shapes.append(shape);
373
374 shapePainter.setShapes( shapes );
375
376 QImage thumb( size, QImage::Format_RGB32 );
377 // draw the background of the thumbnail
378 thumb.fill( QColor( Qt::white ).rgb() );
379 shapePainter.paint(thumb);
380
381 return thumb;
382 }
383
childFromIndex(KoShapeContainer * parent,int row) const384 KoShape * KoPADocumentModel::childFromIndex( KoShapeContainer *parent, int row ) const
385 {
386 return parent->shapes().at(row);
387 }
388
indexFromChild(KoShapeContainer * parent,KoShape * child) const389 int KoPADocumentModel::indexFromChild( KoShapeContainer *parent, KoShape *child ) const
390 {
391 if ( !m_document ) {
392 return 0;
393 }
394
395 return parent->shapes().indexOf( child );
396 }
397
supportedDropActions() const398 Qt::DropActions KoPADocumentModel::supportedDropActions () const
399 {
400 return Qt::MoveAction | Qt::CopyAction;
401 }
402
mimeTypes() const403 QStringList KoPADocumentModel::mimeTypes() const
404 {
405 QStringList types;
406 types << QLatin1String("application/x-kopalayermodeldatalist");
407 return types;
408 }
409
mimeData(const QModelIndexList & indexes) const410 QMimeData * KoPADocumentModel::mimeData( const QModelIndexList & indexes ) const
411 {
412 // check if there is data to encode
413 if ( ! indexes.count() ) {
414 return 0;
415 }
416
417 // check if we support a format
418 QStringList types = mimeTypes();
419 if ( types.isEmpty() ) {
420 return 0;
421 }
422
423 QMimeData *data = new QMimeData();
424 QString format = types[0];
425 QByteArray encoded;
426 QDataStream stream(&encoded, QIODevice::WriteOnly);
427
428 // encode the data
429 QModelIndexList::ConstIterator it = indexes.begin();
430 for( ; it != indexes.end(); ++it) {
431 stream << QVariant::fromValue( qulonglong( it->internalPointer() ) );
432 }
433
434 data->setData(format, encoded);
435 return data;
436 }
437
dropMimeData(const QMimeData * data,Qt::DropAction action,int row,int column,const QModelIndex & parent)438 bool KoPADocumentModel::dropMimeData( const QMimeData * data, Qt::DropAction action, int row, int column, const QModelIndex & parent )
439 {
440 Q_UNUSED( row );
441 Q_UNUSED( column );
442
443 // check if the action is supported
444 if ( ! data || action != Qt::MoveAction ) {
445 return false;
446 }
447 // check if the format is supported
448 QStringList types = mimeTypes();
449 if ( types.isEmpty() ) {
450 return false;
451 }
452 QString format = types[0];
453 if ( ! data->hasFormat(format) ) {
454 return false;
455 }
456
457 QByteArray encoded = data->data( format );
458 QDataStream stream(&encoded, QIODevice::ReadOnly);
459 QList<KoShape*> shapes;
460
461 // decode the data
462 while( ! stream.atEnd() ) {
463 QVariant v;
464 stream >> v;
465 shapes.append( static_cast<KoShape*>( (void*)v.value<qulonglong>() ) );
466 }
467
468 QList<KoShape*> toplevelShapes;
469 QList<KoShapeLayer*> layers;
470 QList<KoPAPageBase *> pages;
471 // remove shapes having its parent in the list
472 // and separate the layers
473 foreach( KoShape * shape, shapes ) {
474 // check whether the selection contains page
475 // by the UI rules, the selection should contains page only
476 KoPAPageBase *page = dynamic_cast<KoPAPageBase *>( shape );
477 if ( page ) {
478 pages.append( page );
479 continue;
480 }
481
482 KoShapeContainer *parentShape = shape->parent();
483 bool hasParentInList = false;
484 while ( parentShape ) {
485 if ( shapes.contains( parentShape ) ) {
486 hasParentInList = true;
487 break;
488 }
489 parentShape = parentShape->parent();
490 }
491 if ( hasParentInList ) {
492 continue;
493 }
494
495 KoShapeLayer * layer = dynamic_cast<KoShapeLayer*>( shape );
496 if ( layer ) {
497 layers.append( layer );
498 } else {
499 toplevelShapes.append( shape );
500 }
501 }
502
503 // dropping to root, only page(s) is allowed
504 if (!parent.isValid()) {
505 if ( !pages.isEmpty() ) {
506 if ( row < 0 ) {
507 return false;
508 }
509 KoPAPageBase *after = (row != 0) ? m_document->pageByIndex(row - 1, false) : 0;
510 debugPageApp << "KoPADocumentModel::dropMimeData parent = root, dropping page(s) as root, moving page(s)";
511 return doDrop(pages, after, action);
512 }
513 else {
514 debugPageApp << "KoPADocumentModel::dropMimeData parent = root, dropping non-page as root, returning false";
515 return false;
516 }
517 }
518 else if (parent.isValid() && !pages.isEmpty()){
519 if (parent.row() < 0) {
520 return false;
521 }
522 KoPAPageBase *after;
523 if ((m_document->pageIndex(pages.first()) - 1) == parent.row()) {
524 after = (parent.row() != 0) ? m_document->pageByIndex(parent.row() - 1, false) : 0;
525 }
526 else {
527 after = (parent.row() > -1) ? m_document->pageByIndex(parent.row(), false) : 0;
528 }
529 return doDrop(pages, after, action);
530 }
531
532 KoShape *shape = static_cast<KoShape*>( parent.internalPointer() );
533 KoShapeContainer * container = dynamic_cast<KoShapeContainer*>( shape );
534 if ( container ) {
535 KoShapeGroup * group = dynamic_cast<KoShapeGroup*>( container );
536 if ( group ) {
537 debugPageApp <<"KoPADocumentModel::dropMimeData parent = group";
538 if ( ! toplevelShapes.count() ) {
539 return false;
540 }
541
542 emit layoutAboutToBeChanged();
543 beginInsertRows( parent, group->shapeCount(), group->shapeCount()+toplevelShapes.count() );
544
545 KUndo2Command * cmd = new KUndo2Command();
546 cmd->setText( kundo2_i18n("Reparent shapes") );
547
548 foreach( KoShape * shape, toplevelShapes ) {
549 new KoShapeUngroupCommand( shape->parent(), QList<KoShape*>() << shape, QList<KoShape*>(), cmd );
550 }
551
552 new KoShapeGroupCommand( group, toplevelShapes, cmd );
553 KoCanvasController * canvasController = KoToolManager::instance()->activeCanvasController();
554 canvasController->canvas()->addCommand( cmd );
555
556 endInsertRows();
557 emit layoutChanged();
558 } else {
559 debugPageApp <<"KoPADocumentModel::dropMimeData parent = container";
560 if ( toplevelShapes.count() ) {
561 emit layoutAboutToBeChanged();
562 beginInsertRows( parent, container->shapeCount(), container->shapeCount()+toplevelShapes.count() );
563
564 KUndo2Command * cmd = new KUndo2Command();
565 cmd->setText( kundo2_i18n("Reparent shapes") );
566
567 QList<bool> clipped;
568 QList<bool> inheritsTransform;
569 foreach( KoShape * shape, toplevelShapes ) {
570 if ( ! shape->parent() ) {
571 clipped.append( false );
572 inheritsTransform.append(false);
573 continue;
574 }
575
576 clipped.append( shape->parent()->isClipped( shape ) );
577 inheritsTransform.append(shape->parent()->inheritsTransform(shape));
578 new KoShapeUngroupCommand( shape->parent(), QList<KoShape*>() << shape, QList<KoShape*>(), cmd );
579 }
580 // shapes are dropped on a container, so add them to the container
581 new KoShapeGroupCommand(container, toplevelShapes, clipped, inheritsTransform, cmd);
582 KoCanvasController * canvasController = KoToolManager::instance()->activeCanvasController();
583 canvasController->canvas()->addCommand( cmd );
584
585 endInsertRows();
586 emit layoutChanged();
587 } else if ( layers.count() ) {
588 KoShapeLayer * layer = dynamic_cast<KoShapeLayer*>( container );
589 if ( ! layer ) {
590 return false;
591 }
592
593 // TODO layers are dropped on a layer, so change layer ordering
594 return false;
595 }
596 }
597 } else {
598 debugPageApp <<"KoPADocumentModel::dropMimeData parent = shape";
599 if ( ! toplevelShapes.count() ) {
600 return false;
601 }
602
603 // TODO shapes are dropped on a shape, reorder them
604 return false;
605 }
606
607 return true;
608 }
609
parentIndexFromShape(const KoShape * child)610 QModelIndex KoPADocumentModel::parentIndexFromShape( const KoShape * child )
611 {
612 if ( !m_document ) {
613 return QModelIndex();
614 }
615
616 // check if child shape is a layer, and return invalid model index if it is
617 const KoShapeLayer *childlayer = dynamic_cast<const KoShapeLayer*>( child );
618 if ( childlayer ) {
619 return QModelIndex();
620 }
621
622 // get the children's parent shape
623 KoShapeContainer *parentShape = child->parent();
624 if ( ! parentShape ) {
625 return QModelIndex();
626 }
627
628 // check if the parent is a layer
629 KoShapeLayer *parentLayer = dynamic_cast<KoShapeLayer*>( parentShape );
630
631
632 if ( parentLayer ) {
633 KoPAPageBase * page = dynamic_cast<KoPAPageBase*>( parentLayer->parent() );
634 if ( page ) {
635 return createIndex( m_document->pages(m_master).count() - 1 - m_document->pages(m_master).indexOf( page ), 0, parentLayer );
636 }
637 }
638 // get the grandparent to determine the row of the parent shape
639 KoShapeContainer *grandParentShape = parentShape->parent();
640 if ( ! grandParentShape ) {
641 return QModelIndex();
642 }
643
644 return createIndex( indexFromChild( grandParentShape, parentShape ), 0, parentShape );
645 }
646
setDocument(KoPADocument * document)647 void KoPADocumentModel::setDocument( KoPADocument* document )
648 {
649 if (m_document == document) {
650 return;
651 }
652
653 if (m_document) {
654 disconnect( m_document, SIGNAL(pageAdded(KoPAPageBase*)), this, SLOT(update()) );
655 disconnect( m_document, SIGNAL(pageRemoved(KoPAPageBase*)), this, SLOT(update()) );
656 disconnect( m_document, SIGNAL(update(KoPAPageBase*)), this, SLOT(update()) );
657 disconnect( m_document, SIGNAL(shapeAdded(KoShape*)), this, SLOT(update()) );
658 disconnect( m_document, SIGNAL(shapeRemoved(KoShape*)), this, SLOT(update()) );
659 }
660
661 beginResetModel();
662 m_document = document;
663 endResetModel();
664
665 if ( m_document ) {
666 connect( m_document, SIGNAL(pageAdded(KoPAPageBase*)), this, SLOT(update()) );
667 connect( m_document, SIGNAL(pageRemoved(KoPAPageBase*)), this, SLOT(update()) );
668 connect( m_document, SIGNAL(update(KoPAPageBase*)), this, SLOT(update()) );
669 connect( m_document, SIGNAL(shapeAdded(KoShape*)), this, SLOT(update()) );
670 connect( m_document, SIGNAL(shapeRemoved(KoShape*)), this, SLOT(update()) );
671 }
672 }
673
setMasterMode(bool master)674 void KoPADocumentModel::setMasterMode(bool master)
675 {
676 m_master = master;
677 update(); // Rebuild the model
678 }
679
doDrop(QList<KoPAPageBase * > pages,KoPAPageBase * pageAfter,Qt::DropAction action)680 bool KoPADocumentModel::doDrop(QList<KoPAPageBase *> pages, KoPAPageBase *pageAfter, Qt::DropAction action)
681 {
682 Qt::KeyboardModifiers modifiers = QApplication::keyboardModifiers();
683 bool enableMove = true;
684
685 foreach (KoPAPageBase *page, pages) {
686 if (!m_document->pages(false).contains(page)) {
687 KoPAPageBase *newPage = page;
688 pages.replace(pages.indexOf(page), newPage);
689 enableMove = false;
690 break;
691 }
692 }
693
694 if (((modifiers & Qt::ControlModifier) == 0) &&
695 ((modifiers & Qt::ShiftModifier) == 0)) {
696 QMenu popup;
697 QString seq = QKeySequence(Qt::ShiftModifier).toString();
698 seq.chop(1);
699 QAction *popupMoveAction = new QAction(i18n("&Move Here") + '\t' + seq, this);
700 popupMoveAction->setIcon(koIcon("go-jump"));
701 seq = QKeySequence(Qt::ControlModifier).toString();
702 seq.chop(1);
703 QAction *popupCopyAction = new QAction(i18n("&Copy Here") + '\t' + seq, this);
704 popupCopyAction->setIcon(koIcon("edit-copy"));
705 seq = QKeySequence( Qt::ControlModifier + Qt::ShiftModifier ).toString();
706 seq.chop(1);
707 QAction *popupCancelAction = new QAction(i18n("C&ancel") + '\t' + QKeySequence(Qt::Key_Escape).toString(), this);
708 popupCancelAction->setIcon(koIcon("process-stop"));
709
710 if (enableMove) {
711 popup.addAction(popupMoveAction);
712 }
713 popup.addAction(popupCopyAction);
714 popup.addSeparator();
715 popup.addAction(popupCancelAction);
716
717 QAction *result = popup.exec(QCursor::pos());
718
719 if (result == popupCopyAction) {
720 action = Qt::CopyAction;
721 } else if (result == popupMoveAction) {
722 action = Qt::MoveAction;
723 } else {
724 return false;
725 }
726 } else if ((modifiers & Qt::ControlModifier) != 0) {
727 action = Qt::CopyAction;
728 } else if ((modifiers & Qt::ShiftModifier) != 0) {
729 action = Qt::MoveAction;
730 } else {
731 return false;
732 }
733
734 switch (action) {
735 case Qt::MoveAction: {
736 KoPAPageMoveCommand *command = new KoPAPageMoveCommand(m_document, pages, pageAfter);
737 m_document->addCommand( command );
738 if ((m_document->pageIndex(pageAfter) + pages.count()) < m_document->pageCount()) {
739 emit requestPageSelection(m_document->pageIndex(pageAfter) + 1, pages.count());
740 }
741 return true;
742 }
743 case Qt::CopyAction: {
744 // Copy Pages
745 KoPAOdfPageSaveHelper saveHelper(m_document, pages);
746 KoDrag drag;
747 drag.setOdf(KoOdf::mimeType(m_document->documentType()), saveHelper);
748 drag.addToClipboard();
749 //Paste Pages
750 const QMimeData * data = QApplication::clipboard()->mimeData();
751 static const KoOdf::DocumentType documentTypes[] = { KoOdf::Graphics, KoOdf::Presentation };
752
753 for (unsigned int i = 0; i < sizeof(documentTypes) / sizeof(KoOdf::DocumentType); ++i) {
754 if (data->hasFormat( KoOdf::mimeType(documentTypes[i]))) {
755 KoPAPastePage paste(m_document, pageAfter);
756 paste.paste(documentTypes[i], data);
757 break;
758 }
759 }
760 emit requestPageSelection(m_document->pageIndex(pageAfter) + 1, sizeof(documentTypes) / sizeof(KoOdf::DocumentType) - 1);
761 return true;
762 }
763 default:
764 qDebug("Unknown action: %d ", (int)action);
765 return false;
766 }
767 return false;
768 }
769