47 #define MIN_VIEW_SCALE 0.05
48 #define MAX_VIEW_SCALE 1000.0
51 : QGraphicsView( parent )
53 setResizeAnchor( QGraphicsView::AnchorViewCenter );
54 setMouseTracking(
true );
55 viewport()->setMouseTracking(
true );
61 viewport()->setStyleSheet( QStringLiteral(
"background-color:#d7d7d7;" ) );
68 viewport()->setGraphicsEffect( mPreviewEffect );
80 return qobject_cast<QgsLayout *>( scene() );
85 return qobject_cast<const QgsLayout *>( scene() );
99 mSnapMarker =
new QgsLayoutViewSnapMarker();
101 layout->addItem( mSnapMarker );
102 mHorizontalSnapLine = createSnapLine();
103 mHorizontalSnapLine->hide();
104 layout->addItem( mHorizontalSnapLine );
105 mVerticalSnapLine = createSnapLine();
106 mVerticalSnapLine->hide();
107 layout->addItem( mVerticalSnapLine );
108 mSectionLabel =
nullptr;
110 if ( mHorizontalRuler )
112 connect( &layout->
guides(), &QAbstractItemModel::dataChanged, mHorizontalRuler, [ = ] { mHorizontalRuler->update(); } );
113 connect( &layout->
guides(), &QAbstractItemModel::rowsInserted, mHorizontalRuler, [ = ] { mHorizontalRuler->update(); } );
114 connect( &layout->
guides(), &QAbstractItemModel::rowsRemoved, mHorizontalRuler, [ = ] { mHorizontalRuler->update(); } );
115 connect( &layout->
guides(), &QAbstractItemModel::modelReset, mHorizontalRuler, [ = ] { mHorizontalRuler->update(); } );
117 if ( mVerticalRuler )
119 connect( &layout->
guides(), &QAbstractItemModel::dataChanged, mVerticalRuler, [ = ] { mVerticalRuler->update(); } );
120 connect( &layout->
guides(), &QAbstractItemModel::rowsInserted, mVerticalRuler, [ = ] { mVerticalRuler->update(); } );
121 connect( &layout->
guides(), &QAbstractItemModel::rowsRemoved, mVerticalRuler, [ = ] { mVerticalRuler->update(); } );
122 connect( &layout->
guides(), &QAbstractItemModel::modelReset, mVerticalRuler, [ = ] { mVerticalRuler->update(); } );
147 if ( mHorizontalSnapLine )
148 mHorizontalSnapLine->hide();
149 if ( mVerticalSnapLine )
150 mVerticalSnapLine->hide();
162 if ( mTool && mTool ==
tool )
166 setCursor( Qt::ArrowCursor );
172 mPreviewEffect->setEnabled( enabled );
177 return mPreviewEffect->isEnabled();
182 mPreviewEffect->
setMode( mode );
187 return mPreviewEffect->
mode();
192 double currentScale = transform().m11();
193 scale *= currentScale;
195 setTransform( QTransform::fromScale( scale, scale ) );
207 setTransform( QTransform::fromScale( level, level ) );
211 double dpi = mScreenDpi;
213 if ( ( dpi < 60 ) || ( dpi > 1200 ) )
219 setTransform( QTransform::fromScale( mmLevel, mmLevel ) );
227 mHorizontalRuler = ruler;
231 connect( &layout->guides(), &QAbstractItemModel::dataChanged, ruler, [ = ] { mHorizontalRuler->update(); } );
232 connect( &layout->guides(), &QAbstractItemModel::rowsInserted, ruler, [ = ] { mHorizontalRuler->update(); } );
233 connect( &layout->guides(), &QAbstractItemModel::rowsRemoved, ruler, [ = ] { mHorizontalRuler->update(); } );
234 connect( &layout->guides(), &QAbstractItemModel::modelReset, ruler, [ = ] { mHorizontalRuler->update(); } );
241 mVerticalRuler = ruler;
245 connect( &layout->guides(), &QAbstractItemModel::dataChanged, ruler, [ = ] { mVerticalRuler->update(); } );
246 connect( &layout->guides(), &QAbstractItemModel::rowsInserted, ruler, [ = ] { mVerticalRuler->update(); } );
247 connect( &layout->guides(), &QAbstractItemModel::rowsRemoved, ruler, [ = ] { mVerticalRuler->update(); } );
248 connect( &layout->guides(), &QAbstractItemModel::modelReset, ruler, [ = ] { mVerticalRuler->update(); } );
255 mMenuProvider.reset( provider );
260 return mMenuProvider.get();
266 return QList< QgsLayoutItemPage *>();
269 QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() );
270 QRectF visibleRect = mapToScene( viewportRect ).boundingRect();
277 return QList< int >();
280 QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() );
281 QRectF visibleRect = mapToScene( viewportRect ).boundingRect();
324 QDomElement documentElement = doc.createElement( QStringLiteral(
"LayoutItemClipboard" ) );
328 QSet< QgsLayoutMultiFrame * > copiedMultiFrames;
335 const QList<QgsLayoutItem *> groupedItems = itemGroup->items();
338 groupedItem->writeXml( documentElement, doc, context );
341 else if (
QgsLayoutFrame *frame = qobject_cast<QgsLayoutFrame *>( item ) )
344 if ( frame->multiFrame() && !copiedMultiFrames.contains( frame->multiFrame() ) )
346 frame->multiFrame()->writeXml( documentElement, doc, context );
347 copiedMultiFrames.insert( frame->multiFrame() );
350 item->writeXml( documentElement, doc, context );
354 doc.appendChild( documentElement );
362 QDomNodeList itemsNodes = doc.elementsByTagName( QStringLiteral(
"LayoutItem" ) );
363 for (
int i = 0; i < itemsNodes.count(); ++i )
365 QDomNode itemNode = itemsNodes.at( i );
366 if ( itemNode.isElement() )
368 itemNode.toElement().removeAttribute( QStringLiteral(
"uuid" ) );
369 itemNode.toElement().removeAttribute( QStringLiteral(
"groupUuid" ) );
372 QDomNodeList multiFrameNodes = doc.elementsByTagName( QStringLiteral(
"LayoutMultiFrame" ) );
373 for (
int i = 0; i < multiFrameNodes.count(); ++i )
375 QDomNode multiFrameNode = multiFrameNodes.at( i );
376 if ( multiFrameNode.isElement() )
378 multiFrameNode.toElement().removeAttribute( QStringLiteral(
"uuid" ) );
379 QDomNodeList frameNodes = multiFrameNode.toElement().elementsByTagName( QStringLiteral(
"childFrame" ) );
380 for (
int j = 0; j < frameNodes.count(); ++j )
382 QDomNode itemNode = frameNodes.at( j );
383 if ( itemNode.isElement() )
385 itemNode.toElement().removeAttribute( QStringLiteral(
"uuid" ) );
391 QMimeData *mimeData =
new QMimeData;
392 mimeData->setData( QStringLiteral(
"text/xml" ), doc.toByteArray() );
393 QClipboard *clipboard = QApplication::clipboard();
394 clipboard->setMimeData( mimeData );
400 return QList< QgsLayoutItem * >();
402 QList< QgsLayoutItem * > pastedItems;
404 QClipboard *clipboard = QApplication::clipboard();
405 if ( doc.setContent( clipboard->mimeData()->data( QStringLiteral(
"text/xml" ) ) ) )
407 QDomElement docElem = doc.documentElement();
408 if ( docElem.tagName() == QLatin1String(
"LayoutItemClipboard" ) )
417 pt = mapToScene( mapFromGlobal( QCursor::pos() ) );
423 pt = mapToScene( viewport()->rect().center() );
441 return QList<QgsLayoutItem *>();
443 QList< QgsLayoutItem * > pastedItems;
445 QClipboard *clipboard = QApplication::clipboard();
446 if ( doc.setContent( clipboard->mimeData()->data( QStringLiteral(
"text/xml" ) ) ) )
448 QDomElement docElem = doc.documentElement();
449 if ( docElem.tagName() == QLatin1String(
"LayoutItemClipboard" ) )
464 QClipboard *clipboard = QApplication::clipboard();
465 if ( doc.setContent( clipboard->mimeData()->data( QStringLiteral(
"text/xml" ) ) ) )
467 QDomElement docElem = doc.documentElement();
468 if ( docElem.tagName() == QLatin1String(
"LayoutItemClipboard" ) )
477 double increment = 1.0;
478 if ( event->modifiers() & Qt::ShiftModifier )
483 else if ( event->modifiers() & Qt::AltModifier )
486 double viewScale = transform().m11();
489 increment = 1 / viewScale;
495 switch ( event->key() )
513 return QPointF( deltaX, deltaY );
518 mPaintingEnabled = enabled;
528 if ( !mSectionLabel )
530 mSectionLabel =
new QgsLayoutReportSectionLabel(
currentLayout(),
this );
532 mSectionLabel->setRect( 0, -200, 1000, 200 );
533 mSectionLabel->setZValue( -1 );
535 mSectionLabel->setLabel( label );
543 fitInView( scene()->sceneRect(), Qt::KeepAspectRatio );
554 QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() );
555 QRectF visibleRect = mapToScene( viewportRect ).boundingRect();
557 double verticalCenter = ( visibleRect.top() + visibleRect.bottom() ) / 2.0;
562 const double tinyHeight = 0.01;
563 QRectF targetRect( scene()->sceneRect().left(),
564 verticalCenter - tinyHeight,
565 scene()->sceneRect().width(),
568 fitInView( targetRect, Qt::KeepAspectRatio );
602 const QList<QGraphicsItem *> itemList =
currentLayout()->items();
603 for ( QGraphicsItem *graphicsItem : itemList )
607 if ( item && !paperItem )
644 const QList<QGraphicsItem *> itemList =
currentLayout()->items();
645 for ( QGraphicsItem *graphicsItem : itemList )
649 if ( item && !paperItem )
652 if ( item->isSelected() || item->
isLocked() )
676 if ( !selectedItems.isEmpty() )
678 previousSelectedItem = selectedItems.at( 0 );
681 if ( !previousSelectedItem )
689 selectedItem = layout->
itemsModel()->findItemBelow( previousSelectedItem );
691 selectedItem = layout->
itemsModel()->findItemAbove( previousSelectedItem );
718 bool itemsRaised =
false;
741 bool itemsLowered =
false;
764 bool itemsRaised =
false;
787 bool itemsLowered =
false;
813 item->setLocked(
true );
833 const QList<QGraphicsItem *> itemList =
currentLayout()->items();
834 for ( QGraphicsItem *graphicItem : itemList )
908 QList< QgsLayoutItem * > ungroupedItems;
920 if ( !ungroupedItems.empty() )
922 for (
QgsLayoutItem *item : std::as_const( ungroupedItems ) )
936 mSnapMarker->setVisible(
false );
941 mTool->layoutPressEvent( me.get() );
942 event->setAccepted( me->isAccepted() );
945 if ( !mTool || !event->isAccepted() )
947 if ( event->button() == Qt::MiddleButton )
950 setTool( mMidMouseButtonPanTool );
953 else if ( event->button() == Qt::RightButton && mMenuProvider )
955 QMenu *menu = mMenuProvider->createContextMenu(
this,
currentLayout(), mapToScene( event->pos() ) );
958 menu->exec( event->globalPos() );
964 QGraphicsView::mousePressEvent( event );
977 mTool->layoutReleaseEvent( me.get() );
978 event->setAccepted( me->isAccepted() );
981 if ( !mTool || !event->isAccepted() )
982 QGraphicsView::mouseReleaseEvent( event );
990 mMouseCurrentXY =
event->pos();
992 QPointF cursorPos = mapToScene( mMouseCurrentXY );
998 me->snapPoint( mHorizontalSnapLine, mVerticalSnapLine, mTool->ignoredSnapItems() );
1003 if ( me->isSnapped() )
1005 cursorPos = me->snappedPoint();
1008 mSnapMarker->setPos( me->snappedPoint() );
1009 mSnapMarker->setVisible(
true );
1012 else if ( mSnapMarker )
1014 mSnapMarker->setVisible(
false );
1017 mTool->layoutMoveEvent( me.get() );
1018 event->setAccepted( me->isAccepted() );
1024 if ( !mTool || !event->isAccepted() )
1025 QGraphicsView::mouseMoveEvent( event );
1036 mTool->layoutDoubleClickEvent( me.get() );
1037 event->setAccepted( me->isAccepted() );
1040 if ( !mTool || !event->isAccepted() )
1041 QGraphicsView::mouseDoubleClickEvent( event );
1051 mTool->wheelEvent( event );
1054 if ( !mTool || !event->isAccepted() )
1068 mTool->keyPressEvent( event );
1071 if ( mTool && event->isAccepted() )
1074 if ( event->key() == Qt::Key_Space && ! event->isAutoRepeat() )
1076 if ( !( event->modifiers() & Qt::ControlModifier ) )
1088 else if ( event->key() == Qt::Key_Left
1089 || event->key() == Qt::Key_Right
1090 || event->key() == Qt::Key_Up
1091 || event->key() == Qt::Key_Down )
1102 item->attemptMoveBy( delta.x(), delta.y() );
1117 mTool->keyReleaseEvent( event );
1120 if ( !mTool || !event->isAccepted() )
1121 QGraphicsView::keyReleaseEvent( event );
1126 QGraphicsView::resizeEvent( event );
1133 QGraphicsView::scrollContentsBy( dx, dy );
1147 if ( mPaintingEnabled )
1149 QGraphicsView::paintEvent( event );
1160 QGraphicsView::showEvent( event );
1162 updateDevicePixelFromScreen();
1164 if ( window()->windowHandle() )
1166 connect( window()->windowHandle(), &QWindow::screenChanged,
this, [ = ]( QScreen * )
1168 disconnect( mScreenDpiChangedConnection );
1169 mScreenDpiChangedConnection = connect( window()->windowHandle()->screen(), &QScreen::physicalDotsPerInchChanged,
this, &QgsLayoutView::updateDevicePixelFromScreen );
1170 updateDevicePixelFromScreen();
1173 mScreenDpiChangedConnection = connect( window()->windowHandle()->screen(), &QScreen::physicalDotsPerInchChanged,
this, &QgsLayoutView::updateDevicePixelFromScreen );
1177 void QgsLayoutView::invalidateCachedRenders()
1183 QList< QgsLayoutItem *> items;
1188 item->invalidateCache();
1192 void QgsLayoutView::updateDevicePixelFromScreen()
1194 if ( window()->windowHandle() )
1195 mScreenDpi = window()->windowHandle()->screen()->physicalDotsPerInch();
1200 if ( mHorizontalRuler )
1204 if ( mVerticalRuler )
1210 QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() );
1211 QRectF visibleRect = mapToScene( viewportRect ).boundingRect();
1212 QPointF centerVisible = visibleRect.center();
1217 if ( newPage != mCurrentPage )
1219 mCurrentPage = newPage;
1230 void QgsLayoutView::wheelZoom( QWheelEvent *event )
1234 double zoomFactor = settings.
value( QStringLiteral(
"qgis/zoom_factor" ), 2 ).toDouble();
1237 zoomFactor = 1.0 + ( zoomFactor - 1.0 ) / 120.0 * std::fabs( event->angleDelta().y() );
1239 if ( event->modifiers() & Qt::ControlModifier )
1242 zoomFactor = 1.0 + ( zoomFactor - 1.0 ) / 20.0;
1246 bool zoomIn =
event->angleDelta().y() > 0;
1247 double scaleFactor = (
zoomIn ? 1 / zoomFactor : zoomFactor );
1250 QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() );
1254 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
1255 QPointF scenePoint = mapToScene( event->pos() );
1257 QPointF scenePoint = mapToScene( event->position().x(), event->position().y() );
1262 QgsPointXY newCenter( scenePoint.x() + ( ( oldCenter.x() - scenePoint.x() ) * scaleFactor ),
1263 scenePoint.y() + ( ( oldCenter.y() - scenePoint.y() ) * scaleFactor ) );
1264 centerOn( newCenter.x(), newCenter.y() );
1277 QGraphicsLineItem *QgsLayoutView::createSnapLine()
const
1279 std::unique_ptr< QGraphicsLineItem> item(
new QGraphicsLineItem(
nullptr ) );
1280 QPen pen = QPen( QColor( Qt::blue ) );
1281 pen.setStyle( Qt::DotLine );
1282 pen.setWidthF( 0.0 );
1283 item->setPen( pen );
1285 return item.release();
1293 QgsLayoutViewSnapMarker::QgsLayoutViewSnapMarker()
1294 : QGraphicsRectItem( QRectF( 0, 0, 0, 0 ) )
1297 QFontMetrics fm( f );
1298 mSize = fm.horizontalAdvance(
'X' );
1299 setPen( QPen( Qt::transparent, mSize ) );
1301 setFlags( flags() | QGraphicsItem::ItemIgnoresTransformations );
1305 void QgsLayoutViewSnapMarker::paint( QPainter *p,
const QStyleOptionGraphicsItem *, QWidget * )
1307 QPen pen( QColor( 255, 0, 0 ) );
1310 p->setBrush( Qt::NoBrush );
1312 double halfSize = mSize / 2.0;
1313 p->drawLine( QLineF( -halfSize, -halfSize, halfSize, halfSize ) );
1314 p->drawLine( QLineF( -halfSize, halfSize, halfSize, -halfSize ) );