Skip to content
Permalink
Browse files

Merge pull request #33283 from elpaso/relation-style-restore

Relation style restore
  • Loading branch information
elpaso committed Dec 19, 2019
2 parents 76f9d16 + a4859a8 commit 6654870c0b9d4ec506a5eb5be651cc4c02d56c6c
@@ -591,6 +591,7 @@
<file>themes/default/propertyicons/system.svg</file>
<file>themes/default/propertyicons/transparency.svg</file>
<file>themes/default/propertyicons/spacer.svg</file>
<file>themes/default/propertyicons/relations.svg</file>
<file>themes/default/rendererCategorizedSymbol.svg</file>
<file>themes/default/rendererGraduatedSymbol.svg</file>
<file>themes/default/rendererNullSymbol.svg</file>
@@ -0,0 +1,31 @@
<svg height="32" width="32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<linearGradient id="a" gradientUnits="userSpaceOnUse" x1="5.6324644" x2="10.6324644" y1="3.7047943" y2="15.7047943">
<stop offset="0" stop-color="#f1f1f1"/>
<stop offset="1" stop-color="#d6d6d6"/>
</linearGradient>
<path d="m10.283011 8.3578359l10.139192.00203v7.8920306" fill="none" stroke="#2b3b4d"/>
<g fill-rule="evenodd" stroke="#888a85" stroke-linecap="round" stroke-linejoin="round" transform="translate(-.431455 -.14381833)">
<rect fill="url(#a)" height="15" overflow="visible" rx="1" width="13" x="2.6324642" y="1.7047944"/>
<path d="m2.6324644 5.7047943l12.9999996 0" fill="#eeeeec" overflow="visible"/>
<path d="m4.6324644 8.7047943l2 0" fill="#eeeeec" overflow="visible"/>
<path d="m4.6324644 11.704794l2 0" fill="#eeeeec" overflow="visible"/>
<path d="m4.6324644 14.704795l2 0" fill="#eeeeec" overflow="visible"/>
<path d="m9.6324641 8.7047943l3.9999999 0" fill="#eeeeec" overflow="visible"/>
<path d="m9.5703417 11.663069l4.0621223.04172" fill="#eeeeec" overflow="visible"/>
<path d="m9.6324641 14.704795l3.9999999 0" fill="#eeeeec" overflow="visible"/>
<path d="m4.7035514 3.7105107l1.928913-.00572" fill="#eeeeec" overflow="visible"/>
<path d="m9.6324641 3.7047943l3.9999999 0" fill="#eeeeec" overflow="visible"/>
</g>
<g fill-rule="evenodd" stroke="#888a85" stroke-linecap="round" stroke-linejoin="round" transform="translate(14.885197 13.80656)">
<rect fill="url(#a)" height="15" overflow="visible" rx="1" width="13" x="2.6324642" y="1.7047944"/>
<path d="m2.6324644 5.7047943l12.9999996 0" fill="#eeeeec" overflow="visible"/>
<path d="m4.6324644 8.7047943l2 0" fill="#eeeeec" overflow="visible"/>
<path d="m4.6324644 11.704794l2 0" fill="#eeeeec" overflow="visible"/>
<path d="m4.6324644 14.704795l2 0" fill="#eeeeec" overflow="visible"/>
<path d="m9.6324641 8.7047943l3.9999999 0" fill="#eeeeec" overflow="visible"/>
<path d="m9.5703417 11.663069l4.0621223.04172" fill="#eeeeec" overflow="visible"/>
<path d="m9.6324641 14.704795l3.9999999 0" fill="#eeeeec" overflow="visible"/>
<path d="m4.7035514 3.7105107l1.928913-.00572" fill="#eeeeec" overflow="visible"/>
<path d="m9.6324641 3.7047943l3.9999999 0" fill="#eeeeec" overflow="visible"/>
</g>
</svg>
@@ -91,6 +91,7 @@ This is the base class for all map layer types (vector, raster).
Rendering,
CustomProperties,
GeometryOptions,
Relations,
AllStyleCategories
};
typedef QFlags<QgsMapLayer::StyleCategory> StyleCategories;
@@ -104,7 +104,7 @@ Gets all relations where the specified layer (and field) is the referencing part
:return: A list of relations matching the given layer and fieldIdx.
%End

QList<QgsRelation> referencedRelations( QgsVectorLayer *layer = 0 ) const;
QList<QgsRelation> referencedRelations( const QgsVectorLayer *layer = 0 ) const;
%Docstring
Gets all relations where this layer is the referenced part (i.e. the parent table with the primary key being referenced from another layer).

@@ -2014,6 +2014,8 @@ Returns the layer's relations, where the foreign key is on this layer.
:return: A list of relations
%End



QgsVectorLayerEditBuffer *editBuffer();
%Docstring
Buffer with uncommitted editing operations. Only valid after editing has been turned on.
@@ -75,9 +75,11 @@

#include "qgssettings.h"
#include "qgsnetworkaccessmanager.h"
#include "qgsrelationmanager.h"
#include "qgsapplication.h"
#include "qgslayerstylingwidget.h"
#include "qgstaskmanager.h"
#include "qgsweakrelation.h"
#include "qgsziputils.h"
#include "qgsbrowserguimodel.h"
#include "qgsvectorlayerjoinbuffer.h"
@@ -667,13 +669,24 @@ void QgisApp::onActiveLayerChanged( QgsMapLayer *layer )

void QgisApp::vectorLayerStyleLoaded( QgsMapLayer::StyleCategories categories )
{
if ( categories.testFlag( QgsMapLayer::StyleCategory::Forms ) )

QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( sender() );

if ( vl && vl->isValid( ) )
{
QgsVectorLayer *vl = qobject_cast<QgsVectorLayer *>( sender() );
if ( vl && vl->isValid( ) )

// Check broken dependencies in forms
if ( categories.testFlag( QgsMapLayer::StyleCategory::Forms ) )
{
resolveVectorLayerDependencies( vl );
}

// Check broken relations and try to restore them
if ( categories.testFlag( QgsMapLayer::StyleCategory::Relations ) )
{
checkVectorLayerDependencies( vl );
resolveVectorLayerWeakRelations( vl );
}

}
}

@@ -1995,37 +2008,97 @@ QgsMessageBar *QgisApp::visibleMessageBar()
}
}

QList<QgsVectorLayerRef> QgisApp::findBrokenWidgetDependencies( QgsVectorLayer *vl )
const QList<QgsVectorLayerRef> QgisApp::findBrokenLayerDependencies( QgsVectorLayer *vl, QgsMapLayer::StyleCategories categories ) const
{
QList<QgsVectorLayerRef> brokenDependencies;
// Check for missing layer widget dependencies
for ( int i = 0; i < vl->fields().count(); i++ )

if ( categories.testFlag( QgsMapLayer::StyleCategory::Forms ) )
{
const QgsEditorWidgetSetup setup = QgsGui::editorWidgetRegistry()->findBest( vl, vl->fields().field( i ).name() );
QgsFieldFormatter *fieldFormatter = QgsApplication::fieldFormatterRegistry()->fieldFormatter( setup.type() );
if ( fieldFormatter )
for ( int i = 0; i < vl->fields().count(); i++ )
{
const auto constDependencies { fieldFormatter->layerDependencies( setup.config() ) };
for ( const QgsVectorLayerRef &dependency : constDependencies )
const QgsEditorWidgetSetup setup = QgsGui::editorWidgetRegistry()->findBest( vl, vl->fields().field( i ).name() );
QgsFieldFormatter *fieldFormatter = QgsApplication::fieldFormatterRegistry()->fieldFormatter( setup.type() );
if ( fieldFormatter )
{
const QgsVectorLayer *depVl { QgsVectorLayerRef( dependency ).resolveWeakly(
QgsProject::instance(),
QgsVectorLayerRef::MatchType::Name ) };
if ( ! depVl || ! depVl->isValid() )
const QList<QgsVectorLayerRef> constDependencies { fieldFormatter->layerDependencies( setup.config() ) };
for ( const QgsVectorLayerRef &dependency : constDependencies )
{
const QgsVectorLayer *depVl { QgsVectorLayerRef( dependency ).resolveWeakly(
QgsProject::instance(),
QgsVectorLayerRef::MatchType::Name ) };
if ( ! depVl || ! depVl->isValid() )
{
brokenDependencies.append( dependency );
}
}
}
}
}

if ( categories.testFlag( QgsMapLayer::StyleCategory::Relations ) )
{
// Check for layer weak relations
const QList<QgsWeakRelation> constWeakRelations { vl->weakRelations() };
for ( const QgsWeakRelation &rel : constWeakRelations )
{
QgsRelation relation { rel.resolvedRelation( QgsProject::instance(), QgsVectorLayerRef::MatchType::Name ) };
QgsVectorLayerRef dependency;
bool found = false;
if ( ! relation.isValid() )
{
// This is the big question: do we really
// want to automatically load the referencing layer(s) too?
// This could potentially lead to a cascaded load of a
// long list of layers.
// The code is in place but let's leave it disabled for now.
if ( relation.referencedLayer() == vl )
{
// Do nothing because vl is the referenced layer
#if 0
dependency = rel.referencingLayer();
found = true;
#endif
}
else if ( relation.referencingLayer() == vl )
{
brokenDependencies.append( dependency );
dependency = rel.referencedLayer();
found = true;
}
else
{
// Something wrong is going on here, maybe this relation
// does not really apply to this layer?
QgsMessageLog::logMessage( tr( "None of the layers in the relation stored in the style match the current layer, skipping relation id: %1." ).arg( relation.id() ) );
}

if ( found )
{
// Make sure we don't add it twice
bool refFound = false;
for ( const QgsVectorLayerRef &otherRef : qgis::as_const( brokenDependencies ) )
{
if ( dependency.layerId == otherRef.layerId || ( dependency.source == otherRef.source && dependency.provider == otherRef.provider ) )
{
refFound = true;
break;
}
}
if ( ! refFound )
{
brokenDependencies.append( dependency );
}
}
}
}
}
return brokenDependencies;
}

void QgisApp::checkVectorLayerDependencies( QgsVectorLayer *vl )
void QgisApp::resolveVectorLayerDependencies( QgsVectorLayer *vl, QgsMapLayer::StyleCategories categories )
{
if ( vl && vl->isValid() )
{
const auto constDependencies { findBrokenWidgetDependencies( vl ) };
const auto constDependencies { findBrokenLayerDependencies( vl, categories ) };
for ( const QgsVectorLayerRef &dependency : constDependencies )
{
// try to aggressively resolve the broken dependencies
@@ -2115,6 +2188,31 @@ void QgisApp::checkVectorLayerDependencies( QgsVectorLayer *vl )
}
}

void QgisApp::resolveVectorLayerWeakRelations( QgsVectorLayer *vectorLayer )
{
if ( vectorLayer && vectorLayer->isValid() )
{
const QList<QgsWeakRelation> constWeakRelations { vectorLayer->weakRelations( ) };
for ( const QgsWeakRelation &rel : constWeakRelations )
{
QgsRelation relation { rel.resolvedRelation( QgsProject::instance(), QgsVectorLayerRef::MatchType::Name ) };
if ( relation.isValid() )
{
// Avoid duplicates
const QList<QgsRelation> constRelations { QgsProject::instance()->relationManager()->relations().values() };
for ( const QgsRelation &other : constRelations )
{
if ( relation.hasEqualDefinition( other ) )
{
continue;
}
}
QgsProject::instance()->relationManager()->addRelation( relation );
}
}
}
}

void QgisApp::dataSourceManager( const QString &pageName )
{
if ( ! mDataSourceManagerDialog )
@@ -6506,7 +6604,7 @@ bool QgisApp::addProject( const QString &projectFile )
{
if ( vl->isValid() )
{
checkVectorLayerDependencies( vl );
resolveVectorLayerDependencies( vl );
}
}

@@ -2025,15 +2025,31 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
QgsMessageBar *visibleMessageBar();

/**
* Searches for layer widget dependencies
* \return a list of weak references to broken widget layer dependencies
* Searches for layer dependencies by querying the form widgets and the
* \a vectorLayer itself for broken relations. Style \a categories can be
* used to limit the search to one or more of the currently implemented search
* categories ("Forms" for the form widgets and "Relations" for layer weak relations).
* \return a list of weak references to broken layer dependencies
*/
QList< QgsVectorLayerRef > findBrokenWidgetDependencies( QgsVectorLayer *vectorLayer );
const QList< QgsVectorLayerRef > findBrokenLayerDependencies( QgsVectorLayer *vectorLayer,
QgsMapLayer::StyleCategories categories = QgsMapLayer::StyleCategory::AllStyleCategories ) const;

/**
* Scans the \a vectorLayer for broken dependencies and warns the user
* Scans the \a vectorLayer for broken dependencies and automatically
* try to load the missing layers, users are notified about the operation
* result. Style \a categories can be
* used to exclude one of the currently implemented search categories
* ("Forms" for the form widgets and "Relations" for layer weak relations).
*/
void checkVectorLayerDependencies( QgsVectorLayer *vectorLayer );
void resolveVectorLayerDependencies( QgsVectorLayer *vectorLayer,
QgsMapLayer::StyleCategories categories = QgsMapLayer::AllStyleCategories );

/**
* Scans the \a vectorLayer for weak relations and automatically
* try to resolve and create the broken relations.
*/
void resolveVectorLayerWeakRelations( QgsVectorLayer *vectorLayer );


QgisAppStyleSheet *mStyleSheetBuilder = nullptr;

0 comments on commit 6654870

Please sign in to comment.
You can’t perform that action at this time.