void QgsLayoutView::unlockAllItems() { //unlock all items in layout currentLayout()->undoStack()->beginMacro( tr( "Unlock Items" ) ); //first, clear the selection currentLayout()->deselectAll(); QgsLayoutItem *focusItem = nullptr; const QList<QGraphicsItem *> itemList = currentLayout()->items(); for ( QGraphicsItem *graphicItem : itemList ) { QgsLayoutItem *item = dynamic_cast<QgsLayoutItem *>( graphicItem ); if ( item && item->isLocked() ) { focusItem = item; item->setLocked( false ); //select unlocked items, same behavior as illustrator item->setSelected( true ); } } currentLayout()->undoStack()->endMacro(); emit itemFocused( focusItem ); }
QgsLayoutItem *QgsLayout::layoutItemAt( QPointF position, const QgsLayoutItem *belowItem, const bool ignoreLocked ) const { //get a list of items which intersect the specified position, in descending z order const QList<QGraphicsItem *> itemList = items( position, Qt::IntersectsItemShape, Qt::DescendingOrder ); bool foundBelowItem = false; for ( QGraphicsItem *graphicsItem : itemList ) { QgsLayoutItem *layoutItem = dynamic_cast<QgsLayoutItem *>( graphicsItem ); QgsLayoutItemPage *paperItem = dynamic_cast<QgsLayoutItemPage *>( layoutItem ); if ( layoutItem && !paperItem ) { // If we are not checking for a an item below a specified item, or if we've // already found that item, then we've found our target if ( ( ! belowItem || foundBelowItem ) && ( !ignoreLocked || !layoutItem->isLocked() ) ) { return layoutItem; } else { if ( layoutItem == belowItem ) { //Target item is next in list foundBelowItem = true; } } } } return nullptr; }
void QgsLayoutView::invertSelection() { if ( !currentLayout() ) { return; } QgsLayoutItem *focusedItem = nullptr; //check all items in layout const QList<QGraphicsItem *> itemList = currentLayout()->items(); for ( QGraphicsItem *graphicsItem : itemList ) { QgsLayoutItem *item = dynamic_cast<QgsLayoutItem *>( graphicsItem ); QgsLayoutItemPage *paperItem = dynamic_cast<QgsLayoutItemPage *>( graphicsItem ); if ( item && !paperItem ) { //flip selected state for items (and deselect any locked items) if ( item->isSelected() || item->isLocked() ) { item->setSelected( false ); } else { item->setSelected( true ); if ( !focusedItem ) focusedItem = item; } } } if ( focusedItem ) emit itemFocused( focusedItem ); }
void QgsLayoutView::selectAll() { if ( !currentLayout() ) { return; } //select all items in layout QgsLayoutItem *focusedItem = nullptr; const QList<QGraphicsItem *> itemList = currentLayout()->items(); for ( QGraphicsItem *graphicsItem : itemList ) { QgsLayoutItem *item = dynamic_cast<QgsLayoutItem *>( graphicsItem ); QgsLayoutItemPage *paperItem = dynamic_cast<QgsLayoutItemPage *>( graphicsItem ); if ( item && !paperItem ) { if ( !item->isLocked() ) { item->setSelected( true ); if ( !focusedItem ) focusedItem = item; } else { //deselect all locked items item->setSelected( false ); } } } emit itemFocused( focusedItem ); }
void QgsLayoutItemUndoCommand::saveState( QDomDocument &stateDoc ) const { stateDoc.clear(); QDomElement documentElement = stateDoc.createElement( QStringLiteral( "ItemState" ) ); QgsLayoutItem *item = mLayout->itemByUuid( mItemUuid ); Q_ASSERT_X( item, "QgsLayoutItemUndoCommand::saveState", "could not retrieve item for saving state" ); item->writeXml( documentElement, stateDoc, QgsReadWriteContext() ); stateDoc.appendChild( documentElement ); }
QgsLayoutItem *QgsLayout::itemById( const QString &id ) const { const QList<QGraphicsItem *> itemList = items(); for ( QGraphicsItem *item : itemList ) { QgsLayoutItem *layoutItem = dynamic_cast<QgsLayoutItem *>( item ); if ( layoutItem && layoutItem->id() == id ) { return layoutItem; } } return nullptr; }
void QgsLayoutItemUndoCommand::restoreState( QDomDocument &stateDoc ) { // find item by uuid... QgsLayoutItem *item = mLayout->itemByUuid( mItemUuid ); if ( !item ) { // uh oh - it's been deleted! we need to create a new instance item = recreateItem( mItemType, mLayout ); } item->readXml( stateDoc.documentElement().firstChild().toElement(), stateDoc, QgsReadWriteContext() ); item->finalizeRestoreFromXml(); mLayout->project()->setDirty( true ); mLayout->undoStack()->notifyUndoRedoOccurred( item ); }
QList<QgsLayoutItem *> QgsLayout::selectedLayoutItems( const bool includeLockedItems ) { QList<QgsLayoutItem *> layoutItemList; const QList<QGraphicsItem *> graphicsItemList = selectedItems(); for ( QGraphicsItem *item : graphicsItemList ) { QgsLayoutItem *layoutItem = dynamic_cast<QgsLayoutItem *>( item ); if ( layoutItem && ( includeLockedItems || !layoutItem->isLocked() ) ) { layoutItemList.push_back( layoutItem ); } } return layoutItemList; }
void QgsLayoutViewToolAddItem::layoutReleaseEvent( QgsLayoutViewMouseEvent *event ) { if ( event->button() != Qt::LeftButton || !mDrawing ) { event->ignore(); return; } mDrawing = false; QRectF rect = mRubberBand->finish( event->snappedPoint(), event->modifiers() ); QgsLayoutItem *item = QgsApplication::layoutItemRegistry()->createItem( mItemType, layout() ); // click? or click-and-drag? bool clickOnly = !isClickAndDrag( mMousePressStartPos, event->pos() ); if ( clickOnly ) { QgsLayoutItemPropertiesDialog dlg( view() ); dlg.setLayout( layout() ); dlg.setItemPosition( QgsLayoutPoint( event->snappedPoint(), layout()->units() ) ); if ( dlg.exec() ) { item->setReferencePoint( dlg.referencePoint() ); item->attemptResize( dlg.itemSize() ); item->attemptMove( dlg.itemPosition() ); } else { delete item; return; } } else { item->attemptResize( QgsLayoutSize( rect.width(), rect.height(), QgsUnitTypes::LayoutMillimeters ) ); item->attemptMove( QgsLayoutPoint( rect.left(), rect.top(), QgsUnitTypes::LayoutMillimeters ) ); } // record last created item size QgsSettings settings; settings.setValue( QStringLiteral( "LayoutDesigner/lastItemWidth" ), item->sizeWithUnits().width() ); settings.setValue( QStringLiteral( "LayoutDesigner/lastItemHeight" ), item->sizeWithUnits().height() ); settings.setValue( QStringLiteral( "LayoutDesigner/lastSizeUnit" ), static_cast< int >( item->sizeWithUnits().units() ) ); layout()->addLayoutItem( item ); layout()->setSelectedItem( item ); }
void QgsLayoutViewToolSelect::layoutPressEvent( QgsLayoutViewMouseEvent *event ) { if ( mMouseHandles->shouldBlockEvent( event ) ) { //swallow clicks while dragging/resizing items return; } if ( mMouseHandles->isVisible() ) { //selection handles are being shown, get mouse action for current cursor position QgsLayoutMouseHandles::MouseAction mouseAction = mMouseHandles->mouseActionForScenePos( event->layoutPoint() ); if ( mouseAction != QgsLayoutMouseHandles::MoveItem && mouseAction != QgsLayoutMouseHandles::NoAction && mouseAction != QgsLayoutMouseHandles::SelectItem ) { //mouse is over a resize handle, so propagate event onward event->ignore(); return; } } if ( event->button() != Qt::LeftButton ) { event->ignore(); return; } QgsLayoutItem *selectedItem = nullptr; QgsLayoutItem *previousSelectedItem = nullptr; QList<QgsLayoutItem *> selectedItems = layout()->selectedLayoutItems(); if ( event->modifiers() & Qt::ControlModifier ) { //CTRL modifier, so we are trying to select the next item below the current one //first, find currently selected item if ( !selectedItems.isEmpty() ) { previousSelectedItem = selectedItems.at( 0 ); } } if ( previousSelectedItem ) { //select highest item just below previously selected item at position of event selectedItem = layout()->layoutItemAt( event->layoutPoint(), previousSelectedItem, true ); //if we didn't find a lower item we'll use the top-most as fall-back //this duplicates mapinfo/illustrator/etc behavior where ctrl-clicks are "cyclic" if ( !selectedItem ) { selectedItem = layout()->layoutItemAt( event->layoutPoint(), true ); } } else { //select topmost item at position of event selectedItem = layout()->layoutItemAt( event->layoutPoint(), true ); } if ( !selectedItem ) { //not clicking over an item, so start marquee selection mIsSelecting = true; mMousePressStartPos = event->pos(); mRubberBand->start( event->layoutPoint(), nullptr ); return; } if ( ( event->modifiers() & Qt::ShiftModifier ) && ( selectedItem->isSelected() ) ) { //SHIFT-clicking a selected item deselects it selectedItem->setSelected( false ); //Check if we have any remaining selected items, and if so, update the item panel const QList<QgsLayoutItem *> selectedItems = layout()->selectedLayoutItems(); if ( !selectedItems.isEmpty() ) { emit itemFocused( selectedItems.at( 0 ) ); } else { emit itemFocused( nullptr ); } } else { if ( ( !selectedItem->isSelected() ) && //keep selection if an already selected item pressed !( event->modifiers() & Qt::ShiftModifier ) ) //keep selection if shift key pressed { layout()->setSelectedItem( selectedItem ); // clears existing selection } else { selectedItem->setSelected( true ); } event->ignore(); emit itemFocused( selectedItem ); } }
void QgsLayoutViewToolSelect::layoutReleaseEvent( QgsLayoutViewMouseEvent *event ) { if ( event->button() != Qt::LeftButton && mMouseHandles->shouldBlockEvent( event ) ) { //swallow clicks while dragging/resizing items return; } if ( !mIsSelecting || event->button() != Qt::LeftButton ) { event->ignore(); return; } mIsSelecting = false; bool wasClick = !isClickAndDrag( mMousePressStartPos, event->pos() ); QRectF rect = mRubberBand->finish( event->layoutPoint(), event->modifiers() ); bool subtractingSelection = false; if ( event->modifiers() & Qt::ShiftModifier ) { //shift modifier means adding to selection, nothing required here } else if ( event->modifiers() & Qt::ControlModifier ) { //control modifier means subtract from current selection subtractingSelection = true; } else { //not adding to or removing from selection, so clear current selection whileBlocking( layout() )->deselectAll(); } //determine item selection mode, default to intersection Qt::ItemSelectionMode selectionMode = Qt::IntersectsItemShape; if ( event->modifiers() & Qt::AltModifier ) { //alt modifier switches to contains selection mode selectionMode = Qt::ContainsItemShape; } //find all items in rect QList<QGraphicsItem *> itemList; if ( wasClick ) itemList = layout()->items( rect.center(), selectionMode ); else itemList = layout()->items( rect, selectionMode ); for ( QGraphicsItem *item : qgis::as_const( itemList ) ) { QgsLayoutItem *layoutItem = dynamic_cast<QgsLayoutItem *>( item ); QgsLayoutItemPage *paperItem = dynamic_cast<QgsLayoutItemPage *>( item ); if ( layoutItem && !paperItem ) { if ( !layoutItem->isLocked() ) { if ( subtractingSelection ) { layoutItem->setSelected( false ); } else { layoutItem->setSelected( true ); } if ( wasClick ) { // found an item, and only a click - nothing more to do break; } } } } //update item panel const QList<QgsLayoutItem *> selectedItemList = layout()->selectedLayoutItems(); if ( !selectedItemList.isEmpty() ) { emit itemFocused( selectedItemList.at( 0 ) ); } else { emit itemFocused( nullptr ); } mMouseHandles->selectionChanged(); }
void QgsLayoutViewToolAddItem::layoutReleaseEvent( QgsLayoutViewMouseEvent *event ) { if ( event->button() != Qt::LeftButton || !mDrawing ) { event->ignore(); return; } mDrawing = false; QRectF rect = mRubberBand->finish( event->snappedPoint(), event->modifiers() ); QString undoText; if ( QgsLayoutItemAbstractGuiMetadata *metadata = QgsGui::layoutItemGuiRegistry()->itemMetadata( mItemMetadataId ) ) { undoText = tr( "Create %1" ).arg( metadata->visibleName() ); } else { undoText = tr( "Create Item" ); } layout()->undoStack()->beginMacro( undoText ); QgsLayoutItem *item = QgsGui::layoutItemGuiRegistry()->createItem( mItemMetadataId, layout() ); if ( !item ) { layout()->undoStack()->endMacro(); return; } // click? or click-and-drag? bool clickOnly = !isClickAndDrag( mMousePressStartPos, event->pos() ); if ( clickOnly ) { QgsLayoutItemPropertiesDialog dlg( view() ); dlg.setLayout( layout() ); dlg.setItemPosition( QgsLayoutPoint( event->snappedPoint(), layout()->units() ) ); if ( dlg.exec() ) { item->setReferencePoint( dlg.referencePoint() ); item->attemptResize( dlg.itemSize() ); item->attemptMove( dlg.itemPosition(), true, false, dlg.page() ); } else { delete item; layout()->undoStack()->endMacro(); return; } } else { item->attemptResize( QgsLayoutSize( rect.width(), rect.height(), QgsUnitTypes::LayoutMillimeters ) ); item->attemptMove( QgsLayoutPoint( rect.left(), rect.top(), QgsUnitTypes::LayoutMillimeters ) ); } // record last created item size QgsSettings settings; settings.setValue( QStringLiteral( "LayoutDesigner/lastItemWidth" ), item->sizeWithUnits().width() ); settings.setValue( QStringLiteral( "LayoutDesigner/lastItemHeight" ), item->sizeWithUnits().height() ); settings.setValue( QStringLiteral( "LayoutDesigner/lastSizeUnit" ), static_cast< int >( item->sizeWithUnits().units() ) ); QgsGui::layoutItemGuiRegistry()->newItemAddedToLayout( mItemMetadataId, item ); // it's possible (in certain circumstances, e.g. when adding frame items) that this item // has already been added to the layout if ( item->scene() != layout() ) layout()->addLayoutItem( item ); layout()->setSelectedItem( item ); layout()->undoStack()->endMacro(); emit createdItem(); }