mirror of
https://github.com/qgis/QGIS.git
synced 2025-12-30 00:29:39 -05:00
[FEATURE][processing] Allow copying/cut/paste of model components
This commit allows users to copy and paste model components, both within the same model and between different models
This commit is contained in:
parent
058a2b8b61
commit
47f96e2466
@ -38,7 +38,7 @@ Saves this group box to a QVariant.
|
||||
.. seealso:: :py:func:`loadVariant`
|
||||
%End
|
||||
|
||||
bool loadVariant( const QVariantMap &map );
|
||||
bool loadVariant( const QVariantMap &map, bool ignoreUuid = false );
|
||||
%Docstring
|
||||
Loads this group box from a QVariantMap.
|
||||
|
||||
|
||||
@ -51,6 +51,10 @@ QGraphicsScene subclass representing the model designer.
|
||||
Constructor for QgsModelGraphicsScene with the specified ``parent`` object.
|
||||
%End
|
||||
|
||||
QgsProcessingModelAlgorithm *model();
|
||||
|
||||
void setModel( QgsProcessingModelAlgorithm *model );
|
||||
|
||||
void setFlags( QgsModelGraphicsScene::Flags flags );
|
||||
%Docstring
|
||||
Sets the combination of ``flags`` controlling how the scene is rendered and behaves.
|
||||
|
||||
@ -80,6 +80,47 @@ Starts a macro command, containing a group of interactions in the view.
|
||||
Ends a macro command, containing a group of interactions in the view.
|
||||
%End
|
||||
|
||||
|
||||
enum ClipboardOperation
|
||||
{
|
||||
ClipboardCut,
|
||||
ClipboardCopy,
|
||||
};
|
||||
|
||||
void copySelectedItems( ClipboardOperation operation );
|
||||
%Docstring
|
||||
Cuts or copies the selected items, respecting the specified ``operation``.
|
||||
|
||||
.. seealso:: :py:func:`copyItems`
|
||||
|
||||
.. seealso:: :py:func:`pasteItems`
|
||||
%End
|
||||
|
||||
void copyItems( const QList< QgsModelComponentGraphicItem * > &items, ClipboardOperation operation );
|
||||
%Docstring
|
||||
Cuts or copies the a list of ``items``, respecting the specified ``operation``.
|
||||
|
||||
.. seealso:: :py:func:`copySelectedItems`
|
||||
|
||||
.. seealso:: :py:func:`pasteItems`
|
||||
%End
|
||||
|
||||
enum PasteMode
|
||||
{
|
||||
PasteModeCursor,
|
||||
PasteModeCenter,
|
||||
PasteModeInPlace,
|
||||
};
|
||||
|
||||
void pasteItems( PasteMode mode );
|
||||
%Docstring
|
||||
Pastes items from clipboard, using the specified ``mode``.
|
||||
|
||||
.. seealso:: :py:func:`copySelectedItems`
|
||||
|
||||
.. seealso:: :py:func:`hasItemsInClipboard`
|
||||
%End
|
||||
|
||||
public slots:
|
||||
|
||||
void snapSelected();
|
||||
@ -120,6 +161,21 @@ Emitted when a macro command containing a group of interactions is started in th
|
||||
void macroCommandEnded();
|
||||
%Docstring
|
||||
Emitted when a macro command containing a group of interactions in the view has ended.
|
||||
%End
|
||||
|
||||
void beginCommand( const QString &text );
|
||||
%Docstring
|
||||
Emitted when an undo command is started in the view.
|
||||
%End
|
||||
|
||||
void endCommand();
|
||||
%Docstring
|
||||
Emitted when an undo command in the view has ended.
|
||||
%End
|
||||
|
||||
void deleteSelectedItems();
|
||||
%Docstring
|
||||
Emitted when the selected items should be deleted;
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
@ -39,10 +39,11 @@ QVariant QgsProcessingModelGroupBox::toVariant() const
|
||||
return map;
|
||||
}
|
||||
|
||||
bool QgsProcessingModelGroupBox::loadVariant( const QVariantMap &map )
|
||||
bool QgsProcessingModelGroupBox::loadVariant( const QVariantMap &map, bool ignoreUuid )
|
||||
{
|
||||
restoreCommonProperties( map );
|
||||
mUuid = map.value( QStringLiteral( "uuid" ) ).toString();
|
||||
if ( !ignoreUuid )
|
||||
mUuid = map.value( QStringLiteral( "uuid" ) ).toString();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -51,7 +51,7 @@ class CORE_EXPORT QgsProcessingModelGroupBox : public QgsProcessingModelComponen
|
||||
* Loads this group box from a QVariantMap.
|
||||
* \see toVariant()
|
||||
*/
|
||||
bool loadVariant( const QVariantMap &map );
|
||||
bool loadVariant( const QVariantMap &map, bool ignoreUuid = false );
|
||||
|
||||
/**
|
||||
* Returns the unique ID associated with this group box.
|
||||
|
||||
@ -166,6 +166,39 @@ QgsModelDesignerDialog::QgsModelDesignerDialog( QWidget *parent, Qt::WindowFlags
|
||||
mMenuView->insertMenu( mActionZoomIn, mGroupMenu );
|
||||
connect( mGroupMenu, &QMenu::aboutToShow, this, &QgsModelDesignerDialog::populateZoomToMenu );
|
||||
|
||||
//cut/copy/paste actions. Note these are not included in the ui file
|
||||
//as ui files have no support for QKeySequence shortcuts
|
||||
mActionCut = new QAction( tr( "Cu&t" ), this );
|
||||
mActionCut->setShortcuts( QKeySequence::Cut );
|
||||
mActionCut->setStatusTip( tr( "Cut" ) );
|
||||
mActionCut->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionEditCut.svg" ) ) );
|
||||
connect( mActionCut, &QAction::triggered, this, [ = ]
|
||||
{
|
||||
mView->copySelectedItems( QgsModelGraphicsView::ClipboardCut );
|
||||
} );
|
||||
|
||||
mActionCopy = new QAction( tr( "&Copy" ), this );
|
||||
mActionCopy->setShortcuts( QKeySequence::Copy );
|
||||
mActionCopy->setStatusTip( tr( "Copy" ) );
|
||||
mActionCopy->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionEditCopy.svg" ) ) );
|
||||
connect( mActionCopy, &QAction::triggered, this, [ = ]
|
||||
{
|
||||
mView->copySelectedItems( QgsModelGraphicsView::ClipboardCopy );
|
||||
} );
|
||||
|
||||
mActionPaste = new QAction( tr( "&Paste" ), this );
|
||||
mActionPaste->setShortcuts( QKeySequence::Paste );
|
||||
mActionPaste->setStatusTip( tr( "Paste" ) );
|
||||
mActionPaste->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionEditPaste.svg" ) ) );
|
||||
connect( mActionPaste, &QAction::triggered, this, [ = ]
|
||||
{
|
||||
mView->pasteItems( QgsModelGraphicsView::PasteModeCursor );
|
||||
} );
|
||||
mMenuEdit->insertAction( mActionDeleteComponents, mActionCut );
|
||||
mMenuEdit->insertAction( mActionDeleteComponents, mActionCopy );
|
||||
mMenuEdit->insertAction( mActionDeleteComponents, mActionPaste );
|
||||
mMenuEdit->insertSeparator( mActionDeleteComponents );
|
||||
|
||||
QgsProcessingToolboxProxyModel::Filters filters = QgsProcessingToolboxProxyModel::FilterModeler;
|
||||
if ( settings.value( QStringLiteral( "Processing/Configuration/SHOW_ALGORITHMS_KNOWN_ISSUES" ), false ).toBool() )
|
||||
{
|
||||
@ -272,6 +305,18 @@ QgsModelDesignerDialog::QgsModelDesignerDialog( QWidget *parent, Qt::WindowFlags
|
||||
mUndoStack->endMacro();
|
||||
mIgnoreUndoStackChanges--;
|
||||
} );
|
||||
connect( mView, &QgsModelGraphicsView::beginCommand, this, [ = ]( const QString & text )
|
||||
{
|
||||
beginUndoCommand( text );
|
||||
} );
|
||||
connect( mView, &QgsModelGraphicsView::endCommand, this, [ = ]
|
||||
{
|
||||
endUndoCommand();
|
||||
} );
|
||||
connect( mView, &QgsModelGraphicsView::deleteSelectedItems, this, [ = ]
|
||||
{
|
||||
deleteSelected();
|
||||
} );
|
||||
|
||||
connect( mActionAddGroupBox, &QAction::triggered, this, [ = ]
|
||||
{
|
||||
@ -372,6 +417,7 @@ void QgsModelDesignerDialog::setModelScene( QgsModelGraphicsScene *scene )
|
||||
mScene = scene;
|
||||
mScene->setParent( this );
|
||||
mScene->setChildAlgorithmResults( mChildResults );
|
||||
mScene->setModel( mModel.get() );
|
||||
|
||||
mView->setModelScene( mScene );
|
||||
|
||||
|
||||
@ -170,6 +170,9 @@ class GUI_EXPORT QgsModelDesignerDialog : public QMainWindow, public Ui::QgsMode
|
||||
|
||||
QMenu *mGroupMenu = nullptr;
|
||||
|
||||
QAction *mActionCut = nullptr;
|
||||
QAction *mActionCopy = nullptr;
|
||||
QAction *mActionPaste = nullptr;
|
||||
int mBlockUndoCommands = 0;
|
||||
int mIgnoreUndoStackChanges = 0;
|
||||
|
||||
|
||||
@ -29,6 +29,16 @@ QgsModelGraphicsScene::QgsModelGraphicsScene( QObject *parent )
|
||||
setItemIndexMethod( QGraphicsScene::NoIndex );
|
||||
}
|
||||
|
||||
QgsProcessingModelAlgorithm *QgsModelGraphicsScene::model()
|
||||
{
|
||||
return mModel;
|
||||
}
|
||||
|
||||
void QgsModelGraphicsScene::setModel( QgsProcessingModelAlgorithm *model )
|
||||
{
|
||||
mModel = model;
|
||||
}
|
||||
|
||||
void QgsModelGraphicsScene::setFlag( QgsModelGraphicsScene::Flag flag, bool on )
|
||||
{
|
||||
if ( on )
|
||||
@ -154,6 +164,8 @@ void QgsModelGraphicsScene::createItems( QgsProcessingModelAlgorithm *model, Qgs
|
||||
const QList< LinkSource > sourceItems = linkSourcesForParameterValue( model, QVariant::fromValue( source ), it.value().childId(), context );
|
||||
for ( const LinkSource &link : sourceItems )
|
||||
{
|
||||
if ( !link.item )
|
||||
continue;
|
||||
QgsModelArrowItem *arrow = nullptr;
|
||||
if ( link.linkIndex == -1 )
|
||||
arrow = new QgsModelArrowItem( link.item, mChildAlgorithmItems.value( it.value().childId() ), parameter->isDestination() ? Qt::BottomEdge : Qt::TopEdge, parameter->isDestination() ? bottomIdx : topIdx );
|
||||
|
||||
@ -70,6 +70,10 @@ class GUI_EXPORT QgsModelGraphicsScene : public QGraphicsScene
|
||||
*/
|
||||
QgsModelGraphicsScene( QObject *parent SIP_TRANSFERTHIS = nullptr );
|
||||
|
||||
QgsProcessingModelAlgorithm *model();
|
||||
|
||||
void setModel( QgsProcessingModelAlgorithm *model );
|
||||
|
||||
/**
|
||||
* Sets the combination of \a flags controlling how the scene is rendered and behaves.
|
||||
* \see setFlag()
|
||||
@ -210,6 +214,8 @@ class GUI_EXPORT QgsModelGraphicsScene : public QGraphicsScene
|
||||
|
||||
Flags mFlags = nullptr;
|
||||
|
||||
QgsProcessingModelAlgorithm *mModel = nullptr;
|
||||
|
||||
QMap< QString, QgsModelComponentGraphicItem * > mParameterItems;
|
||||
QMap< QString, QgsModelChildAlgorithmGraphicItem * > mChildAlgorithmItems;
|
||||
QMap< QString, QMap< QString, QgsModelComponentGraphicItem * > > mOutputItems;
|
||||
|
||||
@ -22,9 +22,15 @@
|
||||
#include "qgsmodelviewtooltemporarykeyzoom.h"
|
||||
#include "qgsmodelcomponentgraphicitem.h"
|
||||
#include "qgsmodelgraphicsscene.h"
|
||||
|
||||
#include "qgsprocessingmodelcomponent.h"
|
||||
#include "qgsprocessingmodelparameter.h"
|
||||
#include "qgsprocessingmodelchildalgorithm.h"
|
||||
#include "qgsxmlutils.h"
|
||||
#include "qgsprocessingmodelalgorithm.h"
|
||||
#include <QDragEnterEvent>
|
||||
#include <QScrollBar>
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
|
||||
///@cond NOT_STABLE
|
||||
|
||||
@ -458,6 +464,270 @@ void QgsModelGraphicsView::snapSelected()
|
||||
endMacroCommand();
|
||||
}
|
||||
|
||||
void QgsModelGraphicsView::copySelectedItems( QgsModelGraphicsView::ClipboardOperation operation )
|
||||
{
|
||||
copyItems( modelScene()->selectedComponentItems(), operation );
|
||||
}
|
||||
|
||||
void QgsModelGraphicsView::copyItems( const QList<QgsModelComponentGraphicItem *> &items, QgsModelGraphicsView::ClipboardOperation operation )
|
||||
{
|
||||
if ( !modelScene() )
|
||||
return;
|
||||
|
||||
QgsReadWriteContext context;
|
||||
QDomDocument doc;
|
||||
QDomElement documentElement = doc.createElement( QStringLiteral( "ModelComponentClipboard" ) );
|
||||
if ( operation == ClipboardCut )
|
||||
{
|
||||
emit macroCommandStarted( tr( "Cut Items" ) );
|
||||
emit beginCommand( QString() );
|
||||
}
|
||||
|
||||
QList< QVariant > paramComponents;
|
||||
QList< QVariant > groupBoxComponents;
|
||||
QList< QVariant > algComponents;
|
||||
for ( QgsModelComponentGraphicItem *item : items )
|
||||
{
|
||||
if ( QgsProcessingModelParameter *param = dynamic_cast< QgsProcessingModelParameter * >( item->component() ) )
|
||||
{
|
||||
QVariantMap paramDef;
|
||||
paramDef.insert( QStringLiteral( "component" ), param->toVariant() );
|
||||
const QgsProcessingParameterDefinition *def = modelScene()->model()->parameterDefinition( param->parameterName() );
|
||||
paramDef.insert( QStringLiteral( "definition" ), def->toVariantMap() );
|
||||
|
||||
paramComponents << paramDef;
|
||||
}
|
||||
else if ( QgsProcessingModelGroupBox *groupBox = dynamic_cast< QgsProcessingModelGroupBox * >( item->component() ) )
|
||||
{
|
||||
groupBoxComponents << groupBox->toVariant();
|
||||
}
|
||||
else if ( QgsProcessingModelChildAlgorithm *alg = dynamic_cast< QgsProcessingModelChildAlgorithm * >( item->component() ) )
|
||||
{
|
||||
algComponents << alg->toVariant();
|
||||
}
|
||||
}
|
||||
QVariantMap components;
|
||||
components.insert( QStringLiteral( "parameters" ), paramComponents );
|
||||
components.insert( QStringLiteral( "groupboxes" ), groupBoxComponents );
|
||||
components.insert( QStringLiteral( "algs" ), algComponents );
|
||||
doc.appendChild( QgsXmlUtils::writeVariant( components, doc ) );
|
||||
if ( operation == ClipboardCut )
|
||||
{
|
||||
emit deleteSelectedItems();
|
||||
emit endCommand();
|
||||
emit macroCommandEnded();
|
||||
}
|
||||
|
||||
QMimeData *mimeData = new QMimeData;
|
||||
mimeData->setData( QStringLiteral( "text/xml" ), doc.toByteArray() );
|
||||
mimeData->setText( doc.toByteArray() );
|
||||
QClipboard *clipboard = QApplication::clipboard();
|
||||
clipboard->setMimeData( mimeData );
|
||||
}
|
||||
|
||||
void QgsModelGraphicsView::pasteItems( QgsModelGraphicsView::PasteMode mode )
|
||||
{
|
||||
if ( !modelScene() )
|
||||
return;
|
||||
|
||||
QList< QgsModelComponentGraphicItem * > pastedItems;
|
||||
QDomDocument doc;
|
||||
QClipboard *clipboard = QApplication::clipboard();
|
||||
if ( doc.setContent( clipboard->mimeData()->data( QStringLiteral( "text/xml" ) ) ) )
|
||||
{
|
||||
QDomElement docElem = doc.documentElement();
|
||||
QVariantMap res = QgsXmlUtils::readVariant( docElem ).toMap();
|
||||
|
||||
if ( res.contains( QStringLiteral( "parameters" ) ) && res.contains( QStringLiteral( "algs" ) ) )
|
||||
{
|
||||
QPointF pt;
|
||||
switch ( mode )
|
||||
{
|
||||
case PasteModeCursor:
|
||||
case PasteModeInPlace:
|
||||
{
|
||||
// place items at cursor position
|
||||
pt = mapToScene( mapFromGlobal( QCursor::pos() ) );
|
||||
break;
|
||||
}
|
||||
case PasteModeCenter:
|
||||
{
|
||||
// place items in center of viewport
|
||||
pt = mapToScene( viewport()->rect().center() );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
emit beginCommand( tr( "Paste Items" ) );
|
||||
|
||||
QRectF pastedBounds;
|
||||
|
||||
QList< QgsProcessingModelGroupBox > pastedGroups;
|
||||
for ( const QVariant &v : res.value( QStringLiteral( "groupboxes" ) ).toList() )
|
||||
{
|
||||
QgsProcessingModelGroupBox box;
|
||||
// don't restore the uuid -- we need them to be unique in the model
|
||||
box.loadVariant( v.toMap(), true );
|
||||
|
||||
pastedGroups << box;
|
||||
|
||||
if ( !pastedBounds.isValid( ) )
|
||||
pastedBounds = QRectF( box.position() - QPointF( box.size().width() / 2.0, box.size().height() / 2.0 ), box.size() );
|
||||
else
|
||||
pastedBounds = pastedBounds.united( QRectF( box.position() - QPointF( box.size().width() / 2.0, box.size().height() / 2.0 ), box.size() ) );
|
||||
}
|
||||
|
||||
QStringList pastedParameters;
|
||||
for ( const QVariant &v : res.value( QStringLiteral( "parameters" ) ).toList() )
|
||||
{
|
||||
QVariantMap param = v.toMap();
|
||||
QVariantMap componentDef = param.value( QStringLiteral( "component" ) ).toMap();
|
||||
QVariantMap paramDef = param.value( QStringLiteral( "definition" ) ).toMap();
|
||||
|
||||
std::unique_ptr< QgsProcessingParameterDefinition > paramDefinition( QgsProcessingParameters::parameterFromVariantMap( paramDef ) );
|
||||
|
||||
QgsProcessingModelParameter p;
|
||||
p.loadVariant( componentDef );
|
||||
|
||||
// we need a unique name for the parameter
|
||||
QString name = p.parameterName();
|
||||
QString description = paramDefinition->description();
|
||||
int next = 1;
|
||||
while ( modelScene()->model()->parameterDefinition( name ) )
|
||||
{
|
||||
next++;
|
||||
name = QStringLiteral( "%1 (%2)" ).arg( p.parameterName() ).arg( next );
|
||||
description = QStringLiteral( "%1 (%2)" ).arg( paramDefinition->description() ).arg( next );
|
||||
}
|
||||
paramDefinition->setName( name );
|
||||
paramDefinition->setDescription( description );
|
||||
p.setParameterName( name );
|
||||
|
||||
modelScene()->model()->addModelParameter( paramDefinition.release(), p );
|
||||
pastedParameters << p.parameterName();
|
||||
|
||||
if ( !pastedBounds.isValid( ) )
|
||||
pastedBounds = QRectF( p.position() - QPointF( p.size().width() / 2.0, p.size().height() / 2.0 ), p.size() );
|
||||
else
|
||||
pastedBounds = pastedBounds.united( QRectF( p.position() - QPointF( p.size().width() / 2.0, p.size().height() / 2.0 ), p.size() ) );
|
||||
|
||||
if ( !p.comment()->description().isEmpty() )
|
||||
pastedBounds = pastedBounds.united( QRectF( p.comment()->position() - QPointF( p.comment()->size().width() / 2.0, p.comment()->size().height() / 2.0 ), p.comment()->size() ) );
|
||||
}
|
||||
|
||||
QStringList pastedAlgorithms;
|
||||
for ( const QVariant &v : res.value( QStringLiteral( "algs" ) ).toList() )
|
||||
{
|
||||
QgsProcessingModelChildAlgorithm alg;
|
||||
alg.loadVariant( v.toMap() );
|
||||
|
||||
// ensure algorithm id is unique
|
||||
alg.generateChildId( *modelScene()->model() );
|
||||
alg.reattach();
|
||||
|
||||
pastedAlgorithms << alg.childId();
|
||||
|
||||
if ( !pastedBounds.isValid( ) )
|
||||
pastedBounds = QRectF( alg.position() - QPointF( alg.size().width() / 2.0, alg.size().height() / 2.0 ), alg.size() );
|
||||
else
|
||||
pastedBounds = pastedBounds.united( QRectF( alg.position() - QPointF( alg.size().width() / 2.0, alg.size().height() / 2.0 ), alg.size() ) );
|
||||
|
||||
if ( !alg.comment()->description().isEmpty() )
|
||||
pastedBounds = pastedBounds.united( QRectF( alg.comment()->position() - QPointF( alg.comment()->size().width() / 2.0, alg.comment()->size().height() / 2.0 ), alg.comment()->size() ) );
|
||||
|
||||
const QMap<QString, QgsProcessingModelChildAlgorithm> existingAlgs = modelScene()->model()->childAlgorithms();
|
||||
|
||||
const QMap<QString, QgsProcessingModelOutput> outputs = alg.modelOutputs();
|
||||
QMap<QString, QgsProcessingModelOutput> pastedOutputs;
|
||||
for ( auto it = outputs.constBegin(); it != outputs.constEnd(); ++it )
|
||||
{
|
||||
QString name = it.value().name();
|
||||
int next = 1;
|
||||
bool unique = false;
|
||||
while ( !unique )
|
||||
{
|
||||
unique = true;
|
||||
for ( auto algIt = existingAlgs.constBegin(); algIt != existingAlgs.constEnd(); ++algIt )
|
||||
{
|
||||
const QMap<QString, QgsProcessingModelOutput> algOutputs = algIt->modelOutputs();
|
||||
for ( auto outputIt = algOutputs.constBegin(); outputIt != algOutputs.constEnd(); ++outputIt )
|
||||
{
|
||||
if ( outputIt.value().name() == name )
|
||||
{
|
||||
unique = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( !unique )
|
||||
break;
|
||||
}
|
||||
if ( unique )
|
||||
break;
|
||||
next++;
|
||||
name = QStringLiteral( "%1 (%2)" ).arg( it.value().name() ).arg( next );
|
||||
}
|
||||
|
||||
QgsProcessingModelOutput newOutput = it.value();
|
||||
newOutput.setName( name );
|
||||
newOutput.setDescription( name );
|
||||
pastedOutputs.insert( name, newOutput );
|
||||
|
||||
pastedBounds = pastedBounds.united( QRectF( newOutput.position() - QPointF( newOutput.size().width() / 2.0, newOutput.size().height() / 2.0 ), newOutput.size() ) );
|
||||
|
||||
if ( !alg.comment()->description().isEmpty() )
|
||||
pastedBounds = pastedBounds.united( QRectF( newOutput.comment()->position() - QPointF( newOutput.comment()->size().width() / 2.0, newOutput.comment()->size().height() / 2.0 ), newOutput.comment()->size() ) );
|
||||
}
|
||||
alg.setModelOutputs( pastedOutputs );
|
||||
|
||||
modelScene()->model()->addChildAlgorithm( alg );
|
||||
}
|
||||
|
||||
QPointF offset( 0, 0 );
|
||||
switch ( mode )
|
||||
{
|
||||
case PasteModeInPlace:
|
||||
break;
|
||||
|
||||
case PasteModeCursor:
|
||||
case PasteModeCenter:
|
||||
{
|
||||
offset = pt - pastedBounds.topLeft();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !offset.isNull() )
|
||||
{
|
||||
for ( QgsProcessingModelGroupBox pastedGroup : qgis::as_const( pastedGroups ) )
|
||||
{
|
||||
pastedGroup.setPosition( pastedGroup.position() + offset );
|
||||
modelScene()->model()->addGroupBox( pastedGroup );
|
||||
}
|
||||
for ( const QString &pastedParam : qgis::as_const( pastedParameters ) )
|
||||
{
|
||||
modelScene()->model()->parameterComponent( pastedParam ).setPosition( modelScene()->model()->parameterComponent( pastedParam ).position() + offset );
|
||||
modelScene()->model()->parameterComponent( pastedParam ).comment()->setPosition( modelScene()->model()->parameterComponent( pastedParam ).comment()->position() + offset );
|
||||
}
|
||||
for ( const QString &pastedAlg : qgis::as_const( pastedAlgorithms ) )
|
||||
{
|
||||
modelScene()->model()->childAlgorithm( pastedAlg ).setPosition( modelScene()->model()->childAlgorithm( pastedAlg ).position() + offset );
|
||||
modelScene()->model()->childAlgorithm( pastedAlg ).comment()->setPosition( modelScene()->model()->childAlgorithm( pastedAlg ).comment()->position() + offset );
|
||||
|
||||
const QMap<QString, QgsProcessingModelOutput> outputs = modelScene()->model()->childAlgorithm( pastedAlg ).modelOutputs();
|
||||
for ( auto it = outputs.begin(); it != outputs.end(); ++it )
|
||||
{
|
||||
modelScene()->model()->childAlgorithm( pastedAlg ).modelOutput( it.key() ).setPosition( modelScene()->model()->childAlgorithm( pastedAlg ).modelOutput( it.key() ).position() + offset );
|
||||
modelScene()->model()->childAlgorithm( pastedAlg ).modelOutput( it.key() ).comment()->setPosition( modelScene()->model()->childAlgorithm( pastedAlg ).modelOutput( it.key() ).comment()->position() + offset );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emit endCommand();
|
||||
}
|
||||
}
|
||||
|
||||
modelScene()->rebuildRequired();
|
||||
}
|
||||
|
||||
QgsModelViewSnapMarker::QgsModelViewSnapMarker()
|
||||
: QGraphicsRectItem( QRectF( 0, 0, 0, 0 ) )
|
||||
|
||||
@ -110,6 +110,44 @@ class GUI_EXPORT QgsModelGraphicsView : public QGraphicsView
|
||||
*/
|
||||
void endMacroCommand();
|
||||
|
||||
|
||||
//! Clipboard operations
|
||||
enum ClipboardOperation
|
||||
{
|
||||
ClipboardCut, //!< Cut items
|
||||
ClipboardCopy, //!< Copy items
|
||||
};
|
||||
|
||||
/**
|
||||
* Cuts or copies the selected items, respecting the specified \a operation.
|
||||
* \see copyItems()
|
||||
* \see pasteItems()
|
||||
*/
|
||||
void copySelectedItems( ClipboardOperation operation );
|
||||
|
||||
/**
|
||||
* Cuts or copies the a list of \a items, respecting the specified \a operation.
|
||||
* \see copySelectedItems()
|
||||
* \see pasteItems()
|
||||
*/
|
||||
void copyItems( const QList< QgsModelComponentGraphicItem * > &items, ClipboardOperation operation );
|
||||
|
||||
//! Paste modes
|
||||
enum PasteMode
|
||||
{
|
||||
PasteModeCursor, //!< Paste items at cursor position
|
||||
PasteModeCenter, //!< Paste items in center of view
|
||||
PasteModeInPlace, //!< Paste items in place
|
||||
};
|
||||
|
||||
/**
|
||||
* Pastes items from clipboard, using the specified \a mode.
|
||||
*
|
||||
* \see copySelectedItems()
|
||||
* \see hasItemsInClipboard()
|
||||
*/
|
||||
void pasteItems( PasteMode mode );
|
||||
|
||||
public slots:
|
||||
|
||||
/**
|
||||
@ -157,6 +195,21 @@ class GUI_EXPORT QgsModelGraphicsView : public QGraphicsView
|
||||
*/
|
||||
void macroCommandEnded();
|
||||
|
||||
/**
|
||||
* Emitted when an undo command is started in the view.
|
||||
*/
|
||||
void beginCommand( const QString &text );
|
||||
|
||||
/**
|
||||
* Emitted when an undo command in the view has ended.
|
||||
*/
|
||||
void endCommand();
|
||||
|
||||
/**
|
||||
* Emitted when the selected items should be deleted;
|
||||
*/
|
||||
void deleteSelectedItems();
|
||||
|
||||
private:
|
||||
|
||||
//! Zoom layout from a mouse wheel event
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user