mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-16 00:03:12 -04:00
[GRASS] refactored vector provider, initial new editing (change geometry)
This commit is contained in:
parent
0a9bf95ea9
commit
60cce74913
@ -20,6 +20,7 @@ ENDIF (WIN32)
|
||||
# Files
|
||||
|
||||
SET (GRASS_PLUGIN_SRCS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/qgsgrasseditrenderer.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/qgsgrassplugin.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/qgsgrassselect.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/qgsgrasstools.cpp
|
||||
@ -45,6 +46,7 @@ SET (GRASS_PLUGIN_UIS
|
||||
)
|
||||
|
||||
SET (GRASS_PLUGIN_MOC_HDRS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/qgsgrasseditrenderer.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/qgsgrassplugin.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/qgsgrassselect.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/qgsgrasstools.h
|
||||
@ -149,8 +151,13 @@ INCLUDE_DIRECTORIES(
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
../../core
|
||||
../../core/geometry
|
||||
../../core/layertree
|
||||
../../core/raster
|
||||
../../core/symbology-ng
|
||||
../../gui
|
||||
../../gui/editorwidgets
|
||||
../../gui/symbology-ng
|
||||
../../gui/layertree
|
||||
../../providers/grass
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../../ui
|
||||
${GDAL_INCLUDE_DIR}
|
||||
|
279
src/plugins/grass/qgsgrasseditrenderer.cpp
Normal file
279
src/plugins/grass/qgsgrasseditrenderer.cpp
Normal file
@ -0,0 +1,279 @@
|
||||
/***************************************************************************
|
||||
qgsgrasseditrenderer.cpp
|
||||
-------------------
|
||||
begin : February, 2015
|
||||
copyright : (C) 2015 by Radim Blazek
|
||||
email : radim.blazek@gmail.com
|
||||
***************************************************************************/
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "qgscategorizedsymbolrendererv2.h"
|
||||
#include "qgscategorizedsymbolrendererv2widget.h"
|
||||
#include "qgsfeature.h"
|
||||
#include "qgslogger.h"
|
||||
#include "qgsrendererv2registry.h"
|
||||
#include "qgssymbollayerv2.h"
|
||||
#include "qgssymbollayerv2utils.h"
|
||||
#include "qgssymbolv2.h"
|
||||
|
||||
#include "qgsgrasseditrenderer.h"
|
||||
#include "qgsgrassprovider.h"
|
||||
|
||||
QgsGrassEditRenderer::QgsGrassEditRenderer()
|
||||
: QgsFeatureRendererV2( "grassEdit" )
|
||||
, mLineRenderer( 0 )
|
||||
, mMarkerRenderer( 0 )
|
||||
{
|
||||
QHash<int, QColor> colors;
|
||||
colors.insert( QgsGrassProvider::TopoUndefined, QColor( 125, 125, 125 ) );
|
||||
colors.insert( QgsGrassProvider::TopoLine, QColor( Qt::black ) );
|
||||
colors.insert( QgsGrassProvider::TopoBoundary0, QColor( Qt::red ) );
|
||||
colors.insert( QgsGrassProvider::TopoBoundary1, QColor( 255, 125, 0 ) );
|
||||
colors.insert( QgsGrassProvider::TopoBoundary2, QColor( Qt::green ) );
|
||||
|
||||
QHash<int, QString> labels;
|
||||
labels.insert( QgsGrassProvider::TopoUndefined, "Unknown type" );
|
||||
labels.insert( QgsGrassProvider::TopoLine, "Line" );
|
||||
labels.insert( QgsGrassProvider::TopoBoundary0, "Boundary (isolated)" );
|
||||
labels.insert( QgsGrassProvider::TopoBoundary1, "Boundary (area on one side)" );
|
||||
labels.insert( QgsGrassProvider::TopoBoundary2, "Boundary (areas on both sides)" );
|
||||
|
||||
QgsCategoryList categoryList;
|
||||
|
||||
foreach ( int value, colors.keys() )
|
||||
{
|
||||
QgsSymbolV2 * symbol = QgsSymbolV2::defaultSymbol( QGis::Line );
|
||||
symbol->setColor( colors.value( value ) );
|
||||
categoryList << QgsRendererCategoryV2( QVariant( value ), symbol, labels.value( value ) );
|
||||
}
|
||||
|
||||
mLineRenderer = new QgsCategorizedSymbolRendererV2( "topo_symbol", categoryList );
|
||||
|
||||
colors.clear();
|
||||
labels.clear();
|
||||
|
||||
colors.insert( QgsGrassProvider::TopoPoint, QColor( 0, 0, 0 ) );
|
||||
colors.insert( QgsGrassProvider::TopoCentroidIn, QColor( 0, 255, 0 ) );
|
||||
colors.insert( QgsGrassProvider::TopoCentroidOut, QColor( 255, 0, 0 ) );
|
||||
colors.insert( QgsGrassProvider::TopoCentroidDupl, QColor( 255, 0, 255 ) );
|
||||
|
||||
labels.insert( QgsGrassProvider::TopoPoint, "Point" );
|
||||
labels.insert( QgsGrassProvider::TopoCentroidIn, "Centroid in area" );
|
||||
labels.insert( QgsGrassProvider::TopoCentroidOut, "Centroid outside area" );
|
||||
labels.insert( QgsGrassProvider::TopoCentroidDupl, "Duplicate centroid" );
|
||||
|
||||
categoryList.clear();
|
||||
|
||||
foreach ( int value, colors.keys() )
|
||||
{
|
||||
QgsSymbolV2 * symbol = QgsSymbolV2::defaultSymbol( QGis::Point );
|
||||
symbol->setColor( colors.value( value ) );
|
||||
categoryList << QgsRendererCategoryV2( QVariant( value ), symbol, labels.value( value ) );
|
||||
}
|
||||
|
||||
mMarkerRenderer = new QgsCategorizedSymbolRendererV2( "topo_symbol", categoryList );
|
||||
}
|
||||
|
||||
QgsGrassEditRenderer::~QgsGrassEditRenderer()
|
||||
{
|
||||
}
|
||||
|
||||
void QgsGrassEditRenderer::setLineRenderer( QgsFeatureRendererV2 *renderer )
|
||||
{
|
||||
delete mLineRenderer;
|
||||
mLineRenderer = renderer;
|
||||
}
|
||||
void QgsGrassEditRenderer::setMarkerRenderer( QgsFeatureRendererV2 *renderer )
|
||||
{
|
||||
delete mMarkerRenderer;
|
||||
mMarkerRenderer = renderer;
|
||||
}
|
||||
|
||||
QgsSymbolV2* QgsGrassEditRenderer::symbolForFeature( QgsFeature& feature, QgsRenderContext& context )
|
||||
{
|
||||
int symbolCode = feature.attribute( "topo_symbol" ).toInt();
|
||||
QgsDebugMsgLevel( QString( "fid = %1 symbolCode = %2" ).arg( feature.id() ).arg( symbolCode ), 3 );
|
||||
|
||||
QgsSymbolV2* symbol = 0;
|
||||
if ( symbolCode == QgsGrassProvider::TopoPoint || symbolCode == QgsGrassProvider::TopoCentroidIn ||
|
||||
symbolCode == QgsGrassProvider::TopoCentroidOut || symbolCode == QgsGrassProvider::TopoCentroidDupl ||
|
||||
symbolCode == QgsGrassProvider::TopoNode0 || symbolCode == QgsGrassProvider::TopoNode1 ||
|
||||
symbolCode == QgsGrassProvider::TopoNode2 )
|
||||
{
|
||||
symbol = mMarkerRenderer->symbolForFeature( feature, context );
|
||||
}
|
||||
else if ( symbolCode == QgsGrassProvider::TopoLine || symbolCode == QgsGrassProvider::TopoBoundary0 ||
|
||||
symbolCode == QgsGrassProvider::TopoBoundary1 || symbolCode == QgsGrassProvider::TopoBoundary2 )
|
||||
{
|
||||
symbol = mLineRenderer->symbolForFeature( feature, context );
|
||||
}
|
||||
else
|
||||
{
|
||||
// should not happen
|
||||
QgsDebugMsg( "unknown symbol code" );
|
||||
}
|
||||
|
||||
if ( symbol )
|
||||
{
|
||||
QgsDebugMsgLevel( "color = " + symbol->color().name(), 3 );
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsDebugMsgLevel( "no symbol", 3 );
|
||||
}
|
||||
|
||||
return symbol;
|
||||
}
|
||||
|
||||
void QgsGrassEditRenderer::startRender( QgsRenderContext& context, const QgsFields& fields )
|
||||
{
|
||||
Q_UNUSED( fields );
|
||||
// TODO better
|
||||
//QgsFields topoFields;
|
||||
//topoFields.append( QgsField( "topo_symbol", QVariant::Int, "int" ) );
|
||||
mLineRenderer->startRender( context, fields );
|
||||
mMarkerRenderer->startRender( context, fields );
|
||||
}
|
||||
|
||||
void QgsGrassEditRenderer::stopRender( QgsRenderContext& context )
|
||||
{
|
||||
mLineRenderer->stopRender( context );
|
||||
mMarkerRenderer->stopRender( context );
|
||||
}
|
||||
|
||||
QList<QString> QgsGrassEditRenderer::usedAttributes()
|
||||
{
|
||||
return mLineRenderer->usedAttributes();
|
||||
}
|
||||
|
||||
QgsFeatureRendererV2* QgsGrassEditRenderer::clone() const
|
||||
{
|
||||
QgsGrassEditRenderer* r = new QgsGrassEditRenderer();
|
||||
if ( mLineRenderer )
|
||||
{
|
||||
r->mLineRenderer = mLineRenderer->clone();
|
||||
}
|
||||
if ( mMarkerRenderer )
|
||||
{
|
||||
r->mMarkerRenderer = mMarkerRenderer->clone();
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
QgsSymbolV2List QgsGrassEditRenderer::symbols( QgsRenderContext& context )
|
||||
{
|
||||
return mLineRenderer->symbols( context );
|
||||
}
|
||||
|
||||
QString QgsGrassEditRenderer::dump() const
|
||||
{
|
||||
return "GRASS edit renderer";
|
||||
}
|
||||
|
||||
QDomElement QgsGrassEditRenderer::save( QDomDocument& doc )
|
||||
{
|
||||
QgsDebugMsg( "entered" );
|
||||
QDomElement rendererElem = doc.createElement( RENDERER_TAG_NAME );
|
||||
rendererElem.setAttribute( "type", "grassEdit" );
|
||||
|
||||
QDomElement lineElem = doc.createElement( "line" );
|
||||
rendererElem.appendChild( lineElem );
|
||||
lineElem.appendChild( mLineRenderer->save( doc ) );
|
||||
|
||||
QDomElement pointElem = doc.createElement( "marker" );
|
||||
rendererElem.appendChild( pointElem );
|
||||
pointElem.appendChild( mMarkerRenderer->save( doc ) );
|
||||
|
||||
return rendererElem;
|
||||
}
|
||||
|
||||
|
||||
QgsFeatureRendererV2* QgsGrassEditRenderer::create( QDomElement& element )
|
||||
{
|
||||
QgsDebugMsg( "entered" );
|
||||
QgsGrassEditRenderer *renderer = new QgsGrassEditRenderer();
|
||||
|
||||
QDomElement childElem = element.firstChildElement();
|
||||
while ( !childElem.isNull() )
|
||||
{
|
||||
QDomElement elem = childElem.firstChildElement();
|
||||
if ( !elem.isNull() )
|
||||
{
|
||||
QString rendererType = elem.attribute( "type" );
|
||||
QgsDebugMsg( "childElem.tagName() = " + childElem.tagName() + " rendererType = " + rendererType );
|
||||
QgsRendererV2AbstractMetadata* meta = QgsRendererV2Registry::instance()->rendererMetadata( rendererType );
|
||||
if ( meta )
|
||||
{
|
||||
QgsFeatureRendererV2* subRenderer = meta->createRenderer( elem );
|
||||
if ( subRenderer )
|
||||
{
|
||||
QgsDebugMsg( "renderer created : " + renderer->type() );
|
||||
if ( childElem.tagName() == "line" )
|
||||
{
|
||||
renderer->setLineRenderer( subRenderer );
|
||||
}
|
||||
else if ( childElem.tagName() == "marker" )
|
||||
{
|
||||
renderer->setMarkerRenderer( subRenderer );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
childElem = childElem.nextSiblingElement();
|
||||
}
|
||||
return renderer;
|
||||
}
|
||||
|
||||
//--------------------------------------- QgsGrassEditRendererWidget --------------------------------------------
|
||||
|
||||
QgsRendererV2Widget* QgsGrassEditRendererWidget::create( QgsVectorLayer* layer, QgsStyleV2* style, QgsFeatureRendererV2* renderer )
|
||||
{
|
||||
QgsDebugMsg( "entered" );
|
||||
return new QgsGrassEditRendererWidget( layer, style, renderer );
|
||||
}
|
||||
|
||||
QgsGrassEditRendererWidget::QgsGrassEditRendererWidget( QgsVectorLayer* layer, QgsStyleV2* style, QgsFeatureRendererV2* renderer )
|
||||
: QgsRendererV2Widget( layer, style )
|
||||
, mRenderer( 0 )
|
||||
{
|
||||
QgsDebugMsg( "entered" );
|
||||
mRenderer = dynamic_cast<QgsGrassEditRenderer*>( renderer->clone() );
|
||||
if ( !mRenderer )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QVBoxLayout* layout = new QVBoxLayout( this );
|
||||
|
||||
mLineRendererWidget = QgsCategorizedSymbolRendererV2Widget::create( layer, style, mRenderer->lineRenderer()->clone() );
|
||||
layout->addWidget( mLineRendererWidget );
|
||||
|
||||
mPointRendererWidget = QgsCategorizedSymbolRendererV2Widget::create( layer, style, mRenderer->pointRenderer()->clone() );
|
||||
layout->addWidget( mPointRendererWidget );
|
||||
}
|
||||
|
||||
QgsGrassEditRendererWidget::~QgsGrassEditRendererWidget()
|
||||
{
|
||||
QgsDebugMsg( "entered" );
|
||||
delete mRenderer;
|
||||
}
|
||||
|
||||
QgsFeatureRendererV2* QgsGrassEditRendererWidget::renderer()
|
||||
{
|
||||
QgsDebugMsg( "entered" );
|
||||
mRenderer->setLineRenderer( mLineRendererWidget->renderer()->clone() );
|
||||
mRenderer->setMarkerRenderer( mPointRendererWidget->renderer()->clone() );
|
||||
return mRenderer;
|
||||
}
|
||||
|
||||
|
||||
|
96
src/plugins/grass/qgsgrasseditrenderer.h
Normal file
96
src/plugins/grass/qgsgrasseditrenderer.h
Normal file
@ -0,0 +1,96 @@
|
||||
/***************************************************************************
|
||||
qgsgrasseditrenderer.h
|
||||
-------------------
|
||||
begin : February, 2015
|
||||
copyright : (C) 2015 by Radim Blazek
|
||||
email : radim.blazek@gmail.com
|
||||
***************************************************************************/
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
#ifndef QGSGRASSEDITRENDERER_H
|
||||
#define QGSGRASSEDITRENDERER_H
|
||||
|
||||
#include "qgis.h"
|
||||
#include "qgscategorizedsymbolrendererv2.h"
|
||||
#include "qgsrendererv2.h"
|
||||
#include "qgssymbolv2.h"
|
||||
|
||||
#include "qgscategorizedsymbolrendererv2.h"
|
||||
#include "qgsrendererv2widget.h"
|
||||
|
||||
class QgsGrassEditRenderer : public QgsFeatureRendererV2
|
||||
{
|
||||
public:
|
||||
enum TopoSymbol
|
||||
{
|
||||
TopoPoint,
|
||||
TopoLine,
|
||||
TopoBoundary0,
|
||||
TopoBoundary1,
|
||||
TopoBoundary2,
|
||||
TopoCentroidIn,
|
||||
TopoCentroidOut,
|
||||
TopoCentroidDupl,
|
||||
TopoNode0,
|
||||
TopoNode1,
|
||||
TopoNode2
|
||||
};
|
||||
|
||||
QgsGrassEditRenderer( );
|
||||
|
||||
virtual ~QgsGrassEditRenderer();
|
||||
|
||||
virtual QgsSymbolV2* symbolForFeature( QgsFeature& feature, QgsRenderContext& context ) override;
|
||||
|
||||
virtual void startRender( QgsRenderContext& context, const QgsFields& fields ) override;
|
||||
|
||||
virtual void stopRender( QgsRenderContext& context ) override;
|
||||
|
||||
virtual QList<QString> usedAttributes() override;
|
||||
|
||||
virtual QgsFeatureRendererV2* clone() const override;
|
||||
|
||||
virtual QgsSymbolV2List symbols( QgsRenderContext& context ) override;
|
||||
|
||||
virtual QString dump() const override;
|
||||
|
||||
QgsFeatureRendererV2 *lineRenderer() const { return mLineRenderer; }
|
||||
QgsFeatureRendererV2 *pointRenderer() const { return mMarkerRenderer; }
|
||||
|
||||
void setLineRenderer( QgsFeatureRendererV2 *renderer );
|
||||
void setMarkerRenderer( QgsFeatureRendererV2 *renderer );
|
||||
|
||||
virtual QDomElement save( QDomDocument& doc ) override;
|
||||
|
||||
static QgsFeatureRendererV2* create( QDomElement& element );
|
||||
|
||||
protected:
|
||||
QgsFeatureRendererV2 *mLineRenderer;
|
||||
QgsFeatureRendererV2 *mMarkerRenderer;
|
||||
};
|
||||
|
||||
class GUI_EXPORT QgsGrassEditRendererWidget : public QgsRendererV2Widget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static QgsRendererV2Widget* create( QgsVectorLayer* layer, QgsStyleV2* style, QgsFeatureRendererV2* renderer );
|
||||
|
||||
QgsGrassEditRendererWidget( QgsVectorLayer* layer, QgsStyleV2* style, QgsFeatureRendererV2* renderer );
|
||||
~QgsGrassEditRendererWidget();
|
||||
|
||||
virtual QgsFeatureRendererV2* renderer() override;
|
||||
|
||||
protected:
|
||||
QgsGrassEditRenderer* mRenderer;
|
||||
|
||||
QgsRendererV2Widget* mLineRendererWidget;
|
||||
QgsRendererV2Widget* mPointRendererWidget;
|
||||
};
|
||||
|
||||
#endif // QGSGRASSEDITRENDERER_H
|
@ -17,8 +17,9 @@
|
||||
#include "qgsgrassplugin.h"
|
||||
#include "qgis.h"
|
||||
#include "qgsgrass.h"
|
||||
#include "qgsgrassprovider.h"
|
||||
|
||||
//the gui subclass
|
||||
#include "qgsgrasseditrenderer.h"
|
||||
#include "qgsgrassnewmapset.h"
|
||||
#include "qgsgrassregion.h"
|
||||
#include "qgsgrassselect.h"
|
||||
@ -28,10 +29,14 @@
|
||||
// includes
|
||||
#include "qgisinterface.h"
|
||||
#include "qgsapplication.h"
|
||||
#include "qgslayertreeview.h"
|
||||
#include "qgslogger.h"
|
||||
#include "qgsmapcanvas.h"
|
||||
#include "qgsmaplayerstylemanager.h"
|
||||
#include "qgsrubberband.h"
|
||||
#include "qgsproject.h"
|
||||
#include "qgsproviderregistry.h"
|
||||
#include "qgsrendererv2registry.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsmaplayerregistry.h"
|
||||
|
||||
@ -211,11 +216,103 @@ void QgsGrassPlugin::initGui()
|
||||
connect( QgsGrass::instance(), SIGNAL( regionChanged() ), SLOT( displayRegion() ) );
|
||||
connect( QgsGrass::instance(), SIGNAL( regionPenChanged() ), SLOT( displayRegion() ) );
|
||||
|
||||
// Connect start/stop editing
|
||||
connect( QgsMapLayerRegistry::instance(), SIGNAL( layerWasAdded( QgsMapLayer* ) ), this, SLOT( onLayerWasAdded( QgsMapLayer* ) ) );
|
||||
|
||||
connect( qGisInterface->layerTreeView(), SIGNAL( currentLayerChanged( QgsMapLayer* ) ),
|
||||
SLOT( onCurrentLayerChanged( QgsMapLayer* ) ) );
|
||||
|
||||
mapsetChanged();
|
||||
|
||||
// open tools when plugin is loaded so that main app restores tools dock widget state
|
||||
mTools = new QgsGrassTools( qGisInterface, qGisInterface->mainWindow() );
|
||||
qGisInterface->addDockWidget( Qt::RightDockWidgetArea, mTools );
|
||||
|
||||
|
||||
}
|
||||
|
||||
void QgsGrassPlugin::onLayerWasAdded( QgsMapLayer* theMapLayer )
|
||||
{
|
||||
QgsDebugMsg( "name = " + theMapLayer->name() );
|
||||
QgsVectorLayer *vectorLayer = qobject_cast<QgsVectorLayer *>( theMapLayer );
|
||||
if ( !vectorLayer )
|
||||
return;
|
||||
QgsGrassProvider* grassProvider = dynamic_cast<QgsGrassProvider*>( vectorLayer->dataProvider() );
|
||||
if ( !grassProvider )
|
||||
return;
|
||||
|
||||
QgsDebugMsg( "connect editing" );
|
||||
connect( vectorLayer, SIGNAL( editingStarted() ), this, SLOT( onEditingStarted() ) );
|
||||
}
|
||||
|
||||
void QgsGrassPlugin::onCurrentLayerChanged( QgsMapLayer* layer )
|
||||
{
|
||||
Q_UNUSED( layer );
|
||||
QgsDebugMsg( "Entered" );
|
||||
}
|
||||
|
||||
void QgsGrassPlugin::onEditingStarted()
|
||||
{
|
||||
QgsDebugMsg( "Entered" );
|
||||
QgsVectorLayer *vectorLayer = qobject_cast<QgsVectorLayer *>( sender() );
|
||||
if ( !vectorLayer )
|
||||
return;
|
||||
QgsDebugMsg( "started editing of layer " + vectorLayer->name() );
|
||||
|
||||
// Set editing renderer
|
||||
QgsGrassProvider* grassProvider = dynamic_cast<QgsGrassProvider*>( vectorLayer->dataProvider() );
|
||||
if ( !grassProvider )
|
||||
return;
|
||||
|
||||
QgsRendererV2Registry::instance()->addRenderer( new QgsRendererV2Metadata( "grassEdit",
|
||||
QObject::tr( "GRASS Edit" ),
|
||||
QgsGrassEditRenderer::create,
|
||||
QIcon(),
|
||||
QgsGrassEditRendererWidget::create ) );
|
||||
|
||||
QgsGrassEditRenderer *renderer = new QgsGrassEditRenderer();
|
||||
|
||||
mOldStyles[vectorLayer] = vectorLayer->styleManager()->currentStyle();
|
||||
|
||||
// Because the edit style may be stored to project:
|
||||
// - do not translate because it may be loaded in QGIS running with different language
|
||||
// - do not change the name until really necessary because it could not be found in project
|
||||
QString editStyleName = "GRASS Edit"; // should not be translated
|
||||
|
||||
if ( vectorLayer->styleManager()->styles().contains( editStyleName ) )
|
||||
{
|
||||
QgsDebugMsg( editStyleName + " style exists -> set as current" );
|
||||
vectorLayer->styleManager()->setCurrentStyle( editStyleName );
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsDebugMsg( "create and set style " + editStyleName );
|
||||
vectorLayer->styleManager()->addStyleFromLayer( editStyleName );
|
||||
|
||||
//vectorLayer->styleManager()->addStyle( editStyleName, QgsMapLayerStyle() );
|
||||
vectorLayer->styleManager()->setCurrentStyle( editStyleName );
|
||||
vectorLayer->setRendererV2( renderer );
|
||||
}
|
||||
|
||||
grassProvider->startEditing( vectorLayer );
|
||||
vectorLayer->updateFields();
|
||||
|
||||
connect( vectorLayer, SIGNAL( editingStopped() ), SLOT( onEditingStopped() ) );
|
||||
}
|
||||
|
||||
void QgsGrassPlugin::onEditingStopped()
|
||||
{
|
||||
QgsDebugMsg( "entered" );
|
||||
QgsVectorLayer *vectorLayer = qobject_cast<QgsVectorLayer *>( sender() );
|
||||
if ( vectorLayer )
|
||||
{
|
||||
QString style = mOldStyles.value( vectorLayer );
|
||||
if ( vectorLayer->styleManager()->currentStyle() == "GRASS Edit" ) // not changed by user
|
||||
{
|
||||
QgsDebugMsg( "reset style to " + style );
|
||||
vectorLayer->styleManager()->setCurrentStyle( style );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsGrassPlugin::mapsetChanged()
|
||||
@ -490,7 +587,7 @@ void QgsGrassPlugin::projectRead()
|
||||
|
||||
void QgsGrassPlugin::newProject()
|
||||
{
|
||||
// QgsDebugMsg("entered.");
|
||||
QgsDebugMsg( "entered" );
|
||||
}
|
||||
|
||||
// Unload the plugin by cleaning up the GUI
|
||||
@ -519,8 +616,6 @@ void QgsGrassPlugin::unload()
|
||||
|
||||
// disconnect slots of QgsGrassPlugin so they're not fired also after unload
|
||||
disconnect( mCanvas, SIGNAL( renderComplete( QPainter * ) ), this, SLOT( postRender( QPainter * ) ) );
|
||||
disconnect( qGisInterface, SIGNAL( currentLayerChanged( QgsMapLayer * ) ),
|
||||
this, SLOT( setEditAction() ) );
|
||||
|
||||
QWidget* qgis = qGisInterface->mainWindow();
|
||||
disconnect( qgis, SIGNAL( projectRead() ), this, SLOT( projectRead() ) );
|
||||
|
@ -25,7 +25,9 @@ class QgsGrassNewMapset;
|
||||
class QgsGrassRegion;
|
||||
|
||||
class QgsMapCanvas;
|
||||
class QgsMapLayer;
|
||||
class QgsRubberBand;
|
||||
class QgsVectorLayer;
|
||||
|
||||
class QAction;
|
||||
class QIcon;
|
||||
@ -109,6 +111,12 @@ class QgsGrassPlugin : public QObject, public QgisPlugin
|
||||
//! update plugin icons when the app tells us its theme is changed
|
||||
void setCurrentTheme( QString theThemeName );
|
||||
void setTransform();
|
||||
//! Called when a new layer was added to map registry
|
||||
void onLayerWasAdded( QgsMapLayer* theMapLayer );
|
||||
//! Called when editing of a layer started
|
||||
void onEditingStarted();
|
||||
void onEditingStopped();
|
||||
void onCurrentLayerChanged( QgsMapLayer* layer );
|
||||
private:
|
||||
//! Pointer to our toolbar
|
||||
QToolBar *mToolBarPointer;
|
||||
@ -136,6 +144,9 @@ class QgsGrassPlugin : public QObject, public QgisPlugin
|
||||
QAction *mCloseMapsetAction;
|
||||
QAction *mOpenToolsAction;
|
||||
QAction *mNewVectorAction;
|
||||
|
||||
// Names of layer styles before editing started
|
||||
QMap<QgsVectorLayer *, QString> mOldStyles;
|
||||
};
|
||||
|
||||
#endif // QGSGRASSPLUGIN_H
|
||||
|
@ -24,10 +24,13 @@ MACRO(ADD_GRASSLIB GRASS_BUILD_VERSION)
|
||||
|
||||
QT4_WRAP_CPP(GRASS_LIBRARY_MOC_SRCS
|
||||
../qgsgrass.h
|
||||
../qgsgrassfeatureiterator.h
|
||||
../qgsgrassimport.h
|
||||
../qgsgrassoptions.h
|
||||
../qgsgrassprovider.h
|
||||
../qgsgrassvector.h
|
||||
../qgsgrassvectormap.h
|
||||
../qgsgrassvectormaplayer.h
|
||||
)
|
||||
|
||||
SET (GRASS_LIBRARY_SRCS
|
||||
@ -38,6 +41,8 @@ MACRO(ADD_GRASSLIB GRASS_BUILD_VERSION)
|
||||
../qgsgrassoptions.cpp
|
||||
../qgsgrassprovider.cpp
|
||||
../qgsgrassvector.cpp
|
||||
../qgsgrassvectormap.cpp
|
||||
../qgsgrassvectormaplayer.cpp
|
||||
)
|
||||
|
||||
QT4_WRAP_UI (GRASS_LIBRARY_UIS_H
|
||||
@ -108,8 +113,16 @@ MACRO(ADD_GRASSLIB GRASS_BUILD_VERSION)
|
||||
#
|
||||
# GRASS vector provider
|
||||
#
|
||||
QT4_WRAP_CPP(GRASS_PROVIDER_MOC_SRCS ../qgsgrassprovidermodule.h)
|
||||
ADD_LIBRARY(grassprovider${GRASS_BUILD_VERSION} MODULE ../qgsgrassprovidermodule.cpp ${GRASS_PROVIDER_MOC_SRCS})
|
||||
SET (GRASS_VECTOR_PROVIDER_SRCS
|
||||
../qgsgrassvectormap.cpp
|
||||
../qgsgrassvectormaplayer.cpp
|
||||
../qgsgrassprovidermodule.cpp
|
||||
)
|
||||
QT4_WRAP_CPP(GRASS_VECTOR_PROVIDER_MOC_SRCS
|
||||
../qgsgrassfeatureiterator.h
|
||||
../qgsgrassprovidermodule.h
|
||||
)
|
||||
ADD_LIBRARY(grassprovider${GRASS_BUILD_VERSION} MODULE ${GRASS_VECTOR_PROVIDER_SRCS} ${GRASS_VECTOR_PROVIDER_MOC_SRCS})
|
||||
SET_TARGET_PROPERTIES(grassprovider${GRASS_BUILD_VERSION} PROPERTIES
|
||||
COMPILE_FLAGS "-DGRASS_BASE=\\\"${GRASS_PREFIX}\\\" \"-DGRASS_EXPORT=${DLLEXPORT}\" \"-DGRASS_LIB_EXPORT=${DLLIMPORT}\""
|
||||
)
|
||||
|
@ -593,6 +593,18 @@ QgsGrass *QgsGrass::instance()
|
||||
return &sInstance;
|
||||
}
|
||||
|
||||
void QgsGrass::lock()
|
||||
{
|
||||
QgsDebugMsg( "lock" );
|
||||
sMutex.lock();
|
||||
}
|
||||
|
||||
void QgsGrass::unlock()
|
||||
{
|
||||
QgsDebugMsg( "unlock" );
|
||||
sMutex.unlock();
|
||||
}
|
||||
|
||||
bool QgsGrass::activeMode()
|
||||
{
|
||||
return active;
|
||||
@ -895,7 +907,7 @@ QString QgsGrass::openMapset( const QString& gisdbase,
|
||||
out.close();
|
||||
|
||||
// Set GISRC environment variable
|
||||
|
||||
// Mapset must be set before Vect_close()
|
||||
/* _Correct_ putenv() implementation is not making copy! */
|
||||
putEnv( "GISRC", mGisrc );
|
||||
|
||||
|
@ -165,8 +165,8 @@ class GRASS_LIB_EXPORT QgsGrass : public QObject
|
||||
static QgsGrass* instance();
|
||||
|
||||
/** Global GRASS library lock */
|
||||
static void lock() { sMutex.lock(); }
|
||||
static void unlock() { sMutex.unlock(); }
|
||||
static void lock();
|
||||
static void unlock();
|
||||
|
||||
/** Path to where GRASS is installed (GISBASE) */
|
||||
static QString gisbase() { return mGisbase; }
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -18,9 +18,11 @@
|
||||
#include "qgsfeatureiterator.h"
|
||||
|
||||
#include <QMutex>
|
||||
#include <QBitArray>
|
||||
|
||||
class QgsGrassProvider;
|
||||
|
||||
#include "qgsgrassprovider.h"
|
||||
//class QgsGrassProvider;
|
||||
class QgsGrassVectorMapLayer;
|
||||
|
||||
class QgsGrassFeatureSource : public QgsAbstractFeatureSource
|
||||
{
|
||||
@ -31,11 +33,28 @@ class QgsGrassFeatureSource : public QgsAbstractFeatureSource
|
||||
virtual QgsFeatureIterator getFeatures( const QgsFeatureRequest& request ) override;
|
||||
|
||||
protected:
|
||||
struct Map_info* mMap;
|
||||
#if 0
|
||||
enum Selection
|
||||
{
|
||||
|
||||
NotSelected = 0, /*!< not selected */
|
||||
Selected = 1, /*!< line/area selected */
|
||||
Used = 2 /*!< the line was already used to create feature read in this cycle.
|
||||
* The codes Used must be reset to Selected if getFirstFeature() or select() is called.
|
||||
* Distinction between Selected and Used is used if attribute table exists, in which case
|
||||
* attributes are read from the table and line geometry is attached to attributes and selection
|
||||
* for that line is set to Used. In the end the selection is scanned for Selected (attributes missing)
|
||||
* and the geometry is returned without attributes. */
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
struct Map_info* map();
|
||||
QgsGrassVectorMapLayer * mLayer;
|
||||
int mLayerType; // layer type POINT, LINE, ...
|
||||
int mGrassType; // grass feature type: GV_POINT, GV_LINE | GV_BOUNDARY, GV_AREA,
|
||||
int mLayerId; // ID used in layers
|
||||
QGis::WkbType mQgisType;// WKBPoint, WKBLineString, ...
|
||||
|
||||
QGis::WkbType mQgisType; // WKBPoint, WKBLineString, ...
|
||||
|
||||
int mCidxFieldIndex; // !UPDATE! Index for layerField in category index or -1 if no such field
|
||||
int mCidxFieldNumCats; // !UPDATE! Number of records in field index
|
||||
@ -43,12 +62,14 @@ class QgsGrassFeatureSource : public QgsAbstractFeatureSource
|
||||
QgsFields mFields;
|
||||
QTextCodec* mEncoding;
|
||||
|
||||
bool mEditing; // Standard QGIS editing mode
|
||||
friend class QgsGrassFeatureIterator;
|
||||
};
|
||||
|
||||
|
||||
class QgsGrassFeatureIterator : public QgsAbstractFeatureIteratorFromSource<QgsGrassFeatureSource>
|
||||
class QgsGrassFeatureIterator : public QObject, public QgsAbstractFeatureIteratorFromSource<QgsGrassFeatureSource>
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QgsGrassFeatureIterator( QgsGrassFeatureSource* source, bool ownSource, const QgsFeatureRequest& request );
|
||||
|
||||
@ -63,60 +84,65 @@ class QgsGrassFeatureIterator : public QgsAbstractFeatureIteratorFromSource<QgsG
|
||||
//! end of iterating: free the resources / lock
|
||||
virtual bool close() override;
|
||||
|
||||
protected:
|
||||
|
||||
// create QgsFeatureId from GRASS geometry object id and cat
|
||||
static QgsFeatureId makeFeatureId( int grassId, int cat );
|
||||
|
||||
// Get GRASS line id from QGIS fid
|
||||
static int lidFormFid( QgsFeatureId fid );
|
||||
|
||||
// Get GRASS cat from QGIS fid
|
||||
static int catFormFid( QgsFeatureId fid );
|
||||
|
||||
public slots:
|
||||
/** Cancel iterator, iterator will be closed on next occasion, probably when next getFeature() gets called.
|
||||
* This function can be called directly from other threads (setting bool is atomic) */
|
||||
void cancel();
|
||||
|
||||
void doClose();
|
||||
|
||||
protected:
|
||||
//void lock();
|
||||
//void unlock();
|
||||
|
||||
/** Reset selection */
|
||||
void resetSelection( bool value );
|
||||
|
||||
void setSelectionRect( const QgsRectangle& rect, bool useIntersect );
|
||||
|
||||
void setFeatureGeometry( QgsFeature& feature, int id, int type );
|
||||
|
||||
|
||||
/** Set feature attributes.
|
||||
* @param feature
|
||||
* @param cat category number
|
||||
*/
|
||||
void setFeatureAttributes( int cat, QgsFeature *feature );
|
||||
void setFeatureAttributes( int cat, QgsFeature *feature, QgsGrassProvider::TopoSymbol symbol );
|
||||
|
||||
/** Set feature attributes.
|
||||
* @param feature
|
||||
* @param cat category number
|
||||
* @param attlist a list containing the index number of the fields to set
|
||||
*/
|
||||
void setFeatureAttributes( int cat, QgsFeature *feature, const QgsAttributeList & attlist );
|
||||
void setFeatureAttributes( int cat, QgsFeature *feature, const QgsAttributeList & attlist, QgsGrassProvider::TopoSymbol symbol );
|
||||
|
||||
struct line_pnts *mPoints; // points structure
|
||||
struct line_cats *mCats; // cats structure
|
||||
struct ilist *mList;
|
||||
/** Get topology symbol code
|
||||
* @param lid line or area number
|
||||
* @param type geometry type */
|
||||
QgsGrassProvider::TopoSymbol topoSymbol( int lid, int type );
|
||||
|
||||
// selection: array of size nlines or nareas + 1, set to 1 - selected or 0 - not selected, 2 - read
|
||||
// Code 2 means that the line was already read in this cycle, all 2 must be reset to 1
|
||||
// if getFirstFeature() or select() is calles.
|
||||
// Distinction between 1 and 2 is used if attribute table exists, in that case attributes are
|
||||
// read from the table and geometry is append and selection set to 2.
|
||||
// In the end the selection array is scanned for 1 (attributes missing), and the geometry
|
||||
// is returned without attributes
|
||||
char *mSelection; // !UPDATE!
|
||||
int mSelectionSize; // !UPDATE! Size of selection array
|
||||
/** Canceled -> close when possible */
|
||||
bool mCanceled;
|
||||
|
||||
// Either mNextCidx or mNextTopoId is used according to type
|
||||
int mNextCidx; // !UPDATE! Next index in cidxFieldIndex to be read, used to find nextFeature
|
||||
int mNextTopoId; // !UPDATE! Next topology id to be read, used to find nextFeature, starts from 1
|
||||
/** Selection array */
|
||||
QBitArray mSelection; // !UPDATE!
|
||||
|
||||
// Edit mode is using mNextLid + mNextCidx
|
||||
// Next index in cidxFieldIndex to be read in standard mode or next index of line Cats in editing mode
|
||||
int mNextCidx;
|
||||
// Next topology line/node id to be read in topo mode or next line id in edit mode, starts from 1
|
||||
int mNextLid;
|
||||
|
||||
/** Reset selection */
|
||||
void resetSelection( bool sel );
|
||||
|
||||
/** Allocate sellection array for given map id. The array is large enough for lines or areas
|
||||
* (bigger from num lines and num areas)
|
||||
* @param map pointer to map structure
|
||||
*/
|
||||
void allocateSelection( struct Map_info *map );
|
||||
|
||||
//! Mutex that protects GRASS library from parallel access from multiple iterators at once.
|
||||
//! The library uses static/global variables in various places when accessing vector data,
|
||||
//! making it non-reentrant and thus impossible to use from multiple threads.
|
||||
//! (e.g. static LocList in Vect_select_lines_by_box, global BranchBuf in RTreeGetBranches)
|
||||
static QMutex sMutex;
|
||||
};
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -16,15 +16,18 @@
|
||||
#ifndef QGSGRASSPROVIDER_H
|
||||
#define QGSGRASSPROVIDER_H
|
||||
|
||||
class QgsFeature;
|
||||
class QgsField;
|
||||
|
||||
class QgsGrassFeatureIterator;
|
||||
|
||||
#include <QDateTime>
|
||||
|
||||
#include "qgsvectordataprovider.h"
|
||||
#include <vector>
|
||||
|
||||
#include "qgsgrassvectormap.h"
|
||||
#include "qgsgrassvectormaplayer.h"
|
||||
|
||||
class QgsFeature;
|
||||
class QgsField;
|
||||
class QgsVectorLayerEditBuffer;
|
||||
|
||||
class QgsGrassFeatureIterator;
|
||||
|
||||
/* Update.
|
||||
* Vectors are updated (reloaded) if:
|
||||
@ -45,69 +48,6 @@ class QgsGrassFeatureIterator;
|
||||
* This is not however solution for multiple instances of QGIS.
|
||||
*/
|
||||
|
||||
/* Editing.
|
||||
* If editing is started by startEdit, vector map is reopened in update mode, and GMAP.update
|
||||
* is set to true. All data loaded from the map to QgsGrassProvider remain unchanged
|
||||
* untill closeEdit is called.
|
||||
* During editing:
|
||||
* nextFeature() and getFirstFeature() returns 0
|
||||
* featureCount() returns 0
|
||||
* fieldCount() returns original (old) number of fields
|
||||
*/
|
||||
|
||||
/* Attributes. Cache of database attributes (because selection from database is slow). */
|
||||
struct GATT
|
||||
{
|
||||
int cat; // category
|
||||
char **values; // pointer to array of pointers to values
|
||||
};
|
||||
|
||||
/* Grass layer (unique vector+field). */
|
||||
struct GLAYER
|
||||
{
|
||||
QString path; // path to the layer gisdbase+location+mapset+mapName
|
||||
int field; // field number
|
||||
bool valid; // valid is true if layer is opened, once the layer is closed,
|
||||
// valid is set to false and no more used
|
||||
int mapId; // map ID in maps vector
|
||||
struct Map_info *map; // map header
|
||||
struct field_info *fieldInfo; // field info
|
||||
int nColumns; // number of columns in database table, if 0, attributes are not available
|
||||
// and category (column name 'cat') is used instead
|
||||
int keyColumn; // number of key column
|
||||
QgsFields fields; // description of layer fields
|
||||
int nAttributes; // number of attributes read to the memory (may be < nRecords)
|
||||
GATT *attributes; // vector of attributes
|
||||
double( *minmax )[2]; // minimum and maximum values of attributes
|
||||
int nUsers; // number of instances using this layer, increased by open(),
|
||||
// decreased by close()
|
||||
};
|
||||
|
||||
/* Grass vector map. */
|
||||
struct GMAP
|
||||
{
|
||||
QString gisdbase; // map gisdabase
|
||||
QString location; // map location name (not path!)
|
||||
QString mapset; // map mapset
|
||||
QString mapName; // map name
|
||||
QString path; // path to the layer gisdbase+location+mapset+mapName
|
||||
bool valid; // true if map is opened, once the map is closed,
|
||||
// valid is set to false and no more used
|
||||
|
||||
// Vector temporally disabled. Necessary for GRASS Tools on Windows
|
||||
bool frozen;
|
||||
|
||||
struct Map_info *map; // map header
|
||||
int nUsers; // number layers using this map
|
||||
int update; // true if the map is opened in update mode -> disabled standard reading
|
||||
// through nextFeature(), featureCount() returns 0
|
||||
QDateTime lastModified; // last modified time of the vector directory, when the map was opened
|
||||
QDateTime lastAttributesModified; // last modified time of the vector 'dbln' file, when the map was opened
|
||||
// or attributes were updated. The 'dbln' file is updated by v.to.db etc.
|
||||
// when attributes are changed
|
||||
int version; // version, increased by each closeEdit() and updateMap()
|
||||
};
|
||||
|
||||
/**
|
||||
\class QgsGrassProvider
|
||||
\brief Data provider for GRASS vectors
|
||||
@ -117,11 +57,28 @@ class GRASS_LIB_EXPORT QgsGrassProvider : public QgsVectorDataProvider
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum TopoSymbol
|
||||
{
|
||||
TopoUndefined = 0,
|
||||
TopoPoint,
|
||||
TopoLine,
|
||||
TopoBoundary0,
|
||||
TopoBoundary1,
|
||||
TopoBoundary2,
|
||||
TopoCentroidIn,
|
||||
TopoCentroidOut,
|
||||
TopoCentroidDupl,
|
||||
TopoNode0,
|
||||
TopoNode1,
|
||||
TopoNode2
|
||||
};
|
||||
|
||||
QgsGrassProvider( QString uri = QString() );
|
||||
|
||||
virtual ~QgsGrassProvider();
|
||||
|
||||
virtual int capabilities() const override;
|
||||
|
||||
virtual QgsAbstractFeatureSource* featureSource() const override;
|
||||
|
||||
/**
|
||||
@ -182,6 +139,14 @@ class GRASS_LIB_EXPORT QgsGrassProvider : public QgsVectorDataProvider
|
||||
|
||||
QgsCoordinateReferenceSystem crs() override;
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
QgsGrassObject grassObject() const { return mGrassObject; }
|
||||
|
||||
// ----------------------------------- New edit --------------------------------
|
||||
bool changeGeometryValues( QgsGeometryMap & geometry_map ) override { Q_UNUSED( geometry_map ); return true; }
|
||||
|
||||
|
||||
// ----------------------------------- Edit ----------------------------------
|
||||
|
||||
/** Is the layer editable? I.e. the layer is valid and current user is owner of the mapset
|
||||
@ -203,11 +168,9 @@ class GRASS_LIB_EXPORT QgsGrassProvider : public QgsVectorDataProvider
|
||||
*/
|
||||
bool isFrozen();
|
||||
|
||||
/** Start editing. Reopen the vector for update and set GMAP.update = true
|
||||
* @return true is frozen
|
||||
* @return false is not frozen
|
||||
*/
|
||||
bool startEdit();
|
||||
/* Start standard QGIS editing */
|
||||
//void startEditing( QgsVectorLayerEditBuffer* buffer );
|
||||
void startEditing( QgsVectorLayer *vectorLayer );
|
||||
|
||||
/** Freeze vector.
|
||||
*/
|
||||
@ -352,13 +315,7 @@ class GRASS_LIB_EXPORT QgsGrassProvider : public QgsVectorDataProvider
|
||||
*/
|
||||
int findNode( double x, double y, double threshold );
|
||||
|
||||
/** Get columns' definitions
|
||||
* @param field
|
||||
* @param cat
|
||||
* @return vector of attributes
|
||||
*/
|
||||
QVector<QgsField> *columns( int field );
|
||||
|
||||
// TODO is it used?
|
||||
/** Read attributes from DB
|
||||
* @param field
|
||||
* @param cat
|
||||
@ -394,7 +351,7 @@ class GRASS_LIB_EXPORT QgsGrassProvider : public QgsVectorDataProvider
|
||||
* @param field
|
||||
* @param cat
|
||||
* @param update comma separated update string, e.g.: col1 = 5, col2 = 'Val d''Aosta'
|
||||
* @return empty string or error message
|
||||
* @return empty string or error messagemLayer
|
||||
*/
|
||||
QString updateAttributes( int field, int cat, const QString &values );
|
||||
|
||||
@ -459,40 +416,12 @@ class GRASS_LIB_EXPORT QgsGrassProvider : public QgsVectorDataProvider
|
||||
*/
|
||||
static int grassLayerType( QString );
|
||||
|
||||
/** Return a provider name
|
||||
|
||||
Essentially just returns the provider key. Should be used to build file
|
||||
dialogs so that providers can be shown with their supported types. Thus
|
||||
if more than one provider supports a given format, the user is able to
|
||||
select a specific provider to open that file.
|
||||
|
||||
@note
|
||||
|
||||
Instead of being pure virtual, might be better to generalize this
|
||||
behavior and presume that none of the sub-classes are going to do
|
||||
anything strange with regards to their name or description?
|
||||
|
||||
*/
|
||||
/** Return a provider name */
|
||||
QString name() const override;
|
||||
|
||||
|
||||
/** Return description
|
||||
|
||||
Return a terse string describing what the provider is.
|
||||
|
||||
@note
|
||||
|
||||
Instead of being pure virtual, might be better to generalize this
|
||||
behavior and presume that none of the sub-classes are going to do
|
||||
anything strange with regards to their name or description?
|
||||
|
||||
*/
|
||||
/** Return description */
|
||||
QString description() const override;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Layer type (layerType)
|
||||
enum TYPE // layer name:
|
||||
{
|
||||
@ -509,120 +438,45 @@ class GRASS_LIB_EXPORT QgsGrassProvider : public QgsVectorDataProvider
|
||||
TOPO_NODE // topology nodes
|
||||
};
|
||||
|
||||
public slots:
|
||||
void bufferGeometryChanged( QgsFeatureId fid, QgsGeometry &geom );
|
||||
void onBeforeCommitChanges();
|
||||
void onEditingStopped();
|
||||
void onUndoIndexChanged( int index );
|
||||
|
||||
protected:
|
||||
// used by QgsGrassFeatureSource
|
||||
QgsGrassVectorMapLayer *openLayer() const;
|
||||
|
||||
private:
|
||||
QString mGisdbase; // map gisdabase
|
||||
QString mLocation; // map location name (not path!)
|
||||
QString mMapset; // map mapset
|
||||
QString mMapName; // map name
|
||||
QString mLayer; // layer name
|
||||
int mLayerField; // field part of layer or -1 if no field specified
|
||||
int mLayerType; // layer type POINT, LINE, ...
|
||||
int mGrassType; // grass feature type: GV_POINT, GV_LINE | GV_BOUNDARY, GV_AREA,
|
||||
// ( GV_BOUNDARY, GV_CENTROID )
|
||||
QGis::WkbType mQgisType;// WKBPoint, WKBLineString, ...
|
||||
int mLayerId; // ID used in layers
|
||||
struct Map_info *mMap; // vector header pointer
|
||||
int mMapVersion; // The version of the map for which the instance was last time updated
|
||||
struct Map_info * map();
|
||||
void setMapset();
|
||||
|
||||
int mCidxFieldIndex; // !UPDATE! Index for layerField in category index or -1 if no such field
|
||||
int mCidxFieldNumCats; // !UPDATE! Number of records in field index
|
||||
QgsGrassObject mGrassObject;
|
||||
// field part of layer or -1 if no field specified
|
||||
int mLayerField;
|
||||
// layer type POINT, LINE, ...
|
||||
int mLayerType;
|
||||
// grass feature type: GV_POINT, GV_LINE | GV_BOUNDARY, GV_AREA, ( GV_BOUNDARY, GV_CENTROID )
|
||||
int mGrassType;
|
||||
// WKBPoint, WKBLineString, ...
|
||||
QGis::WkbType mQgisType;
|
||||
QString mLayerName;
|
||||
QgsGrassVectorMapLayer *mLayer;
|
||||
// The version of the map for which the instance was last time updated
|
||||
int mMapVersion;
|
||||
|
||||
bool mValid; // !UPDATE!
|
||||
long mNumberFeatures; // !UPDATE!
|
||||
// Index for layerField in category index or -1 if no such field
|
||||
int mCidxFieldIndex;
|
||||
// Number of records in field index
|
||||
int mCidxFieldNumCats;
|
||||
|
||||
bool mValid;
|
||||
long mNumberFeatures;
|
||||
|
||||
// create QgsFeatureId from GRASS geometry object id and cat
|
||||
static QgsFeatureId makeFeatureId( int grassId, int cat );
|
||||
|
||||
// Reopen map after edit or freeze
|
||||
bool reopenMap();
|
||||
|
||||
// -----------------------------------------------------------------------------------------
|
||||
/* Static variables and methods.
|
||||
* These methods opens GRASS vectors and loads some parts of vectors to the memory.
|
||||
* it maintains the list of opened layers so that sources are not duplicated in the memory.
|
||||
* Layers are identified by layer ID.
|
||||
* The layers have unique URI, if next layer of the same URI is requested,
|
||||
* nUsers is increased and ID of the layer which is already opened is returned.
|
||||
* Attributes are loaded from DB and stored in the memory when layer is opened.
|
||||
*/
|
||||
|
||||
/** Open layer. Layer for QgsGrassVector means Map+field
|
||||
* @param gisdbase
|
||||
* @param location
|
||||
* @param mapset
|
||||
* @param mapName
|
||||
* @param field
|
||||
* @return layer ID
|
||||
* @return -1 cannot open
|
||||
*/
|
||||
static int openLayer( QString gisdbase, QString location, QString mapset, QString mapName, int field );
|
||||
|
||||
/** Load sources from the map.
|
||||
* Must be set: layer.mapId, layer.map, layer.field
|
||||
* Updates: layer.fieldInfo, layer.nColumns, layer.nAttributes, layer.attributes, layer.keyColumn
|
||||
* Unchanged: layer.valid
|
||||
*
|
||||
* Old sources are released, namely: layer.fields and layer.attributes
|
||||
*
|
||||
* layer.attributes must be pointer to existing array or 0
|
||||
*/
|
||||
static void loadLayerSourcesFromMap( GLAYER &layer );
|
||||
|
||||
/** Load attributes from database table.
|
||||
* Must be set: layer.mapId, layer.map, layer.field
|
||||
* Updates: layer.fieldInfo, layer.nColumns, layer.nAttributes, layer.attributes, layer.keyColumn
|
||||
* Unchanged: layer.valid
|
||||
*
|
||||
* Old sources are released, namely: layer.attributes
|
||||
*
|
||||
* layer.attributes must be pointer to existing array or 0
|
||||
*/
|
||||
static void loadAttributes( GLAYER &layer );
|
||||
|
||||
/** Close layer.
|
||||
* @param layerId
|
||||
*/
|
||||
static void closeLayer( int layerId );
|
||||
|
||||
/** Open map.
|
||||
* @param gisdbase
|
||||
* @param location
|
||||
* @param mapset
|
||||
* @param mapName
|
||||
* @return map ID
|
||||
* @return -1 cannot open
|
||||
*/
|
||||
static int openMap( QString gisdbase, QString location, QString mapset, QString mapName );
|
||||
|
||||
/** Close map.
|
||||
* @param mapId
|
||||
*/
|
||||
static void closeMap( int mapId );
|
||||
|
||||
/** Update map. Close and reopen vector, all layers in mLayers using this map are also updated.
|
||||
* Instances of QgsGrassProvider are not updated and should call update() method.
|
||||
* @param mapId
|
||||
*/
|
||||
static void updateMap( int mapId );
|
||||
|
||||
/** The map is outdated. The map was for example rewritten by GRASS module outside QGIS.
|
||||
* This function checks internal timestamp stored in QGIS.
|
||||
* @param mapId
|
||||
*/
|
||||
static bool mapOutdated( int mapId );
|
||||
|
||||
/** The attributes are outdated. The table was for example updated by GRASS module outside QGIS.
|
||||
* This function checks internal timestamp stored in QGIS.
|
||||
* @param mapId
|
||||
*/
|
||||
static bool attributesOutdated( int mapId );
|
||||
|
||||
/** Get layer map.
|
||||
* @param layerId
|
||||
* @return pointer to Map_info structure
|
||||
*/
|
||||
static struct Map_info *layerMap( int layerId );
|
||||
|
||||
/** Get attribute by category(key) and attribute number.
|
||||
* @param layerId
|
||||
* @param category (key)
|
||||
@ -641,17 +495,15 @@ class GRASS_LIB_EXPORT QgsGrassProvider : public QgsVectorDataProvider
|
||||
|
||||
void setTopoFields();
|
||||
|
||||
/* Static arrays of opened layers and vectors */
|
||||
static QVector<GLAYER> mLayers; // Map + field/attributes
|
||||
static QVector<GMAP> mMaps; // Map
|
||||
|
||||
/** Fields used for topo layers */
|
||||
QgsFields mTopoFields;
|
||||
|
||||
QgsFields mEditFields;
|
||||
|
||||
QgsVectorLayerEditBuffer* mEditBuffer;
|
||||
|
||||
friend class QgsGrassFeatureSource;
|
||||
friend class QgsGrassFeatureIterator;
|
||||
|
||||
static int cmpAtt( const void *a, const void *b );
|
||||
};
|
||||
|
||||
#endif // QGSGRASSPROVIDER_H
|
||||
|
685
src/providers/grass/qgsgrassvectormap.cpp
Normal file
685
src/providers/grass/qgsgrassvectormap.cpp
Normal file
@ -0,0 +1,685 @@
|
||||
/***************************************************************************
|
||||
qgsgrassvectormap.cpp
|
||||
-------------------
|
||||
begin : September, 2015
|
||||
copyright : (C) 2015 by Radim Blazek
|
||||
email : radim.blazek@gmail.com
|
||||
***************************************************************************/
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "qgslinestringv2.h"
|
||||
#include "qgspolygonv2.h"
|
||||
#include "qgspointv2.h"
|
||||
|
||||
#include "qgslogger.h"
|
||||
#include "qgsgeometry.h"
|
||||
|
||||
#include "qgsgrass.h"
|
||||
#include "qgsgrassvectormap.h"
|
||||
#include "qgsgrassvectormaplayer.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <grass/version.h>
|
||||
#include <grass/gprojects.h>
|
||||
#include <grass/gis.h>
|
||||
#include <grass/dbmi.h>
|
||||
#if GRASS_VERSION_MAJOR < 7
|
||||
#include <grass/Vect.h>
|
||||
#else
|
||||
#include <grass/vector.h>
|
||||
#define BOUND_BOX bound_box
|
||||
#endif
|
||||
}
|
||||
|
||||
QgsGrassVectorMap::QgsGrassVectorMap( const QgsGrassObject & grassObject )
|
||||
: mGrassObject( grassObject )
|
||||
, mValid( false )
|
||||
, mOpen( false )
|
||||
, mFrozen( false )
|
||||
, mIsEdited( false )
|
||||
, mVersion( 0 )
|
||||
, mMap( 0 )
|
||||
, mIs3d( false )
|
||||
, mOldNumLines( 0 )
|
||||
{
|
||||
QgsDebugMsg( "grassObject = " + grassObject.toString() );
|
||||
openMap();
|
||||
mOpen = true;
|
||||
}
|
||||
|
||||
QgsGrassVectorMap::~QgsGrassVectorMap()
|
||||
{
|
||||
QgsDebugMsg( "grassObject = " + mGrassObject.toString() );
|
||||
// TODO close
|
||||
QgsGrass::vectDestroyMapStruct( mMap );
|
||||
}
|
||||
|
||||
int QgsGrassVectorMap::userCount() const
|
||||
{
|
||||
int count = 0;
|
||||
foreach ( QgsGrassVectorMapLayer *layer, mLayers )
|
||||
{
|
||||
count += layer->userCount();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
bool QgsGrassVectorMap::open()
|
||||
{
|
||||
QgsDebugMsg( toString() );
|
||||
if ( mOpen )
|
||||
{
|
||||
QgsDebugMsg( "already open" );
|
||||
return true;
|
||||
}
|
||||
lockOpenClose();
|
||||
bool result = openMap();
|
||||
mOpen = true;
|
||||
unlockOpenClose();
|
||||
return result;
|
||||
}
|
||||
|
||||
void QgsGrassVectorMap::close()
|
||||
{
|
||||
QgsDebugMsg( toString() );
|
||||
if ( mOpen )
|
||||
{
|
||||
QgsDebugMsg( "is not open" );
|
||||
return;
|
||||
}
|
||||
lockOpenClose();
|
||||
closeAllIterators(); // blocking
|
||||
closeMap();
|
||||
mOpen = false;
|
||||
unlockOpenClose();
|
||||
return;
|
||||
}
|
||||
|
||||
bool QgsGrassVectorMap::openMap()
|
||||
{
|
||||
// TODO: refresh layers (reopen)
|
||||
QgsDebugMsg( toString() );
|
||||
QgsGrass::lock();
|
||||
QgsGrass::setLocation( mGrassObject.gisdbase(), mGrassObject.location() );
|
||||
|
||||
// Find the vector
|
||||
const char *ms = G_find_vector2( mGrassObject.name().toUtf8().data(), mGrassObject.mapset().toUtf8().data() );
|
||||
|
||||
if ( !ms )
|
||||
{
|
||||
QgsDebugMsg( "Cannot find GRASS vector" );
|
||||
QgsGrass::unlock();
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Read the time of vector dir before Vect_open_old, because it may take long time (when the vector
|
||||
// could be owerwritten)
|
||||
QFileInfo di( mGrassObject.mapsetPath() + "/vector/" + mGrassObject.name() );
|
||||
mLastModified = di.lastModified();
|
||||
|
||||
di.setFile( mGrassObject.mapsetPath() + "/vector/" + mGrassObject.name() + "/dbln" );
|
||||
mLastAttributesModified = di.lastModified();
|
||||
|
||||
mMap = QgsGrass::vectNewMapStruct();
|
||||
// Do we have topology and cidx (level2)
|
||||
int level = -1;
|
||||
G_TRY
|
||||
{
|
||||
//Vect_set_open_level( 2 );
|
||||
level = Vect_open_old_head( mMap, mGrassObject.name().toUtf8().data(), mGrassObject.mapset().toUtf8().data() );
|
||||
Vect_close( mMap );
|
||||
}
|
||||
G_CATCH( QgsGrass::Exception &e )
|
||||
{
|
||||
QgsGrass::warning( e );
|
||||
level = -1;
|
||||
}
|
||||
|
||||
if ( level == -1 )
|
||||
{
|
||||
QgsDebugMsg( "Cannot open GRASS vector head" );
|
||||
QgsGrass::unlock();
|
||||
return -1;
|
||||
}
|
||||
else if ( level == 1 )
|
||||
{
|
||||
QMessageBox::StandardButton ret = QMessageBox::question( 0, "Warning",
|
||||
QObject::tr( "GRASS vector map %1 does not have topology. Build topology?" ).arg( mGrassObject.name() ),
|
||||
QMessageBox::Ok | QMessageBox::Cancel );
|
||||
|
||||
if ( ret == QMessageBox::Cancel )
|
||||
{
|
||||
QgsGrass::unlock();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Open vector
|
||||
G_TRY
|
||||
{
|
||||
Vect_set_open_level( level );
|
||||
Vect_open_old( mMap, mGrassObject.name().toUtf8().data(), mGrassObject.mapset().toUtf8().data() );
|
||||
}
|
||||
G_CATCH( QgsGrass::Exception &e )
|
||||
{
|
||||
QgsGrass::warning( QString( "Cannot open GRASS vector: %1" ).arg( e.what() ) );
|
||||
QgsGrass::unlock();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( level == 1 )
|
||||
{
|
||||
G_TRY
|
||||
{
|
||||
#if defined(GRASS_VERSION_MAJOR) && defined(GRASS_VERSION_MINOR) && \
|
||||
( ( GRASS_VERSION_MAJOR == 6 && GRASS_VERSION_MINOR >= 4 ) || GRASS_VERSION_MAJOR > 6 )
|
||||
Vect_build( mMap );
|
||||
#else
|
||||
Vect_build( mMap, stderr );
|
||||
#endif
|
||||
}
|
||||
G_CATCH( QgsGrass::Exception &e )
|
||||
{
|
||||
QgsGrass::warning( QString( "Cannot build topology: %1" ).arg( e.what() ) );
|
||||
QgsGrass::unlock();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
QgsDebugMsg( "GRASS map successfully opened" );
|
||||
|
||||
mIs3d = Vect_is_3d( mMap );
|
||||
|
||||
QgsGrass::unlock();
|
||||
mValid = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QgsGrassVectorMap::startEdit()
|
||||
{
|
||||
QgsDebugMsg( toString() );
|
||||
|
||||
lockOpenClose();
|
||||
|
||||
closeAllIterators(); // blocking
|
||||
|
||||
// TODO: Can it still happen? QgsGrassVectorMapStore singleton is used now.
|
||||
#if 0
|
||||
// Check number of maps (the problem may appear if static variables are not shared - runtime linker)
|
||||
if ( mMaps.size() == 0 )
|
||||
{
|
||||
QMessageBox::warning( 0, "Warning", "No maps opened in mMaps, probably problem in runtime linking, "
|
||||
"static variables are not shared by provider and plugin." );
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Close map */
|
||||
mValid = false;
|
||||
|
||||
QgsGrass::lock();
|
||||
// Mapset must be set before Vect_close()
|
||||
QgsGrass::setMapset( mGrassObject.gisdbase(), mGrassObject.location(), mGrassObject.mapset() );
|
||||
|
||||
int level = -1;
|
||||
G_TRY
|
||||
{
|
||||
Vect_close( mMap );
|
||||
level = Vect_open_update( mMap, mGrassObject.name().toUtf8().data(), mGrassObject.mapset().toUtf8().data() );
|
||||
if ( level < 2 )
|
||||
{
|
||||
QgsDebugMsg( "Cannot open GRASS vector for update on level 2." );
|
||||
}
|
||||
}
|
||||
G_CATCH( QgsGrass::Exception &e )
|
||||
{
|
||||
Q_UNUSED( e );
|
||||
QgsDebugMsg( QString( "Cannot open GRASS vector for update: %1" ).arg( e.what() ) );
|
||||
}
|
||||
|
||||
if ( level < 2 )
|
||||
{
|
||||
// reopen vector for reading
|
||||
G_TRY
|
||||
{
|
||||
Vect_set_open_level( 2 );
|
||||
level = Vect_open_old( mMap, mGrassObject.name().toUtf8().data(), mGrassObject.mapset().toUtf8().data() );
|
||||
if ( level < 2 )
|
||||
{
|
||||
QgsDebugMsg( QString( "Cannot reopen GRASS vector: %1" ).arg( QgsGrass::errorMessage() ) );
|
||||
}
|
||||
}
|
||||
G_CATCH( QgsGrass::Exception &e )
|
||||
{
|
||||
Q_UNUSED( e );
|
||||
QgsDebugMsg( QString( "Cannot reopen GRASS vector: %1" ).arg( e.what() ) );
|
||||
}
|
||||
|
||||
if ( level >= 2 )
|
||||
{
|
||||
mValid = true;
|
||||
}
|
||||
QgsGrass::unlock();
|
||||
unlockOpenClose();
|
||||
return false;
|
||||
}
|
||||
Vect_set_category_index_update( mMap );
|
||||
|
||||
// Write history
|
||||
Vect_hist_command( mMap );
|
||||
|
||||
mOldNumLines = Vect_get_num_lines( mMap );
|
||||
QgsDebugMsg( QString( "Vector successfully reopened for update mOldNumLines = %1" ).arg( mOldNumLines ) );
|
||||
|
||||
mIsEdited = true;
|
||||
mValid = true;
|
||||
QgsGrass::unlock();
|
||||
unlockOpenClose();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QgsGrassVectorMap::closeEdit( bool newMap )
|
||||
{
|
||||
Q_UNUSED( newMap );
|
||||
QgsDebugMsg( toString() );
|
||||
if ( !mValid || !mIsEdited )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// mValid = false; // close() is checking mValid
|
||||
|
||||
lockOpenClose();
|
||||
closeAllIterators(); // blocking
|
||||
|
||||
QgsGrass::lock();
|
||||
mOldLids.clear();
|
||||
mNewLids.clear();
|
||||
mOldGeometries.clear();
|
||||
|
||||
// Mapset must be set before Vect_close()
|
||||
QgsGrass::setMapset( mGrassObject.gisdbase(), mGrassObject.location(), mGrassObject.mapset() );
|
||||
|
||||
#if defined(GRASS_VERSION_MAJOR) && defined(GRASS_VERSION_MINOR) && \
|
||||
( ( GRASS_VERSION_MAJOR == 6 && GRASS_VERSION_MINOR >= 4 ) || GRASS_VERSION_MAJOR > 6 )
|
||||
Vect_build_partial( mMap, GV_BUILD_NONE );
|
||||
Vect_build( mMap );
|
||||
#else
|
||||
Vect_build_partial( mMap, GV_BUILD_NONE, NULL );
|
||||
Vect_build( mMap, stderr );
|
||||
#endif
|
||||
|
||||
// TODO?
|
||||
#if 0
|
||||
// If a new map was created close the map and return
|
||||
if ( newMap )
|
||||
{
|
||||
QgsDebugMsg( QString( "mLayers.size() = %1" ).arg( mLayers.size() ) );
|
||||
mUpdate = false;
|
||||
// Map must be set as valid otherwise it is not closed and topo is not written
|
||||
mValid = true;
|
||||
// TODO refresh layers ?
|
||||
//closeLayer( mLayerId );
|
||||
QgsGrass::unlock();
|
||||
unlockOpenClose();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
mIsEdited = false;
|
||||
QgsGrass::unlock();closeAllIterators(); // blocking
|
||||
|
||||
closeMap();
|
||||
openMap();
|
||||
mVersion++;
|
||||
unlockOpenClose();
|
||||
|
||||
QgsDebugMsg( "edit closed" );
|
||||
return mValid;
|
||||
}
|
||||
|
||||
QgsGrassVectorMapLayer * QgsGrassVectorMap::openLayer( int field )
|
||||
{
|
||||
QgsDebugMsg( QString( "%1 field = %2" ).arg( toString() ).arg( field ) );
|
||||
|
||||
// There are 2 locks on openLayer(), it must be locked when the map is being opened/closed/updated
|
||||
// but that lock must not block closeLayer() because close/update map closes first all iterators
|
||||
// which call closeLayer() and using single lock would result in dead lock.
|
||||
|
||||
lockOpenCloseLayer();
|
||||
lockOpenClose();
|
||||
QgsGrassVectorMapLayer *layer = 0;
|
||||
// Check if this layer is already open
|
||||
foreach ( QgsGrassVectorMapLayer *l, mLayers )
|
||||
{
|
||||
if ( l->field() == field )
|
||||
{
|
||||
QgsDebugMsg( "Layer exists" );
|
||||
layer = l;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !layer )
|
||||
{
|
||||
layer = new QgsGrassVectorMapLayer( this, field ) ;
|
||||
layer->load();
|
||||
mLayers << layer;
|
||||
}
|
||||
|
||||
layer->addUser();
|
||||
unlockOpenClose();
|
||||
unlockOpenCloseLayer();
|
||||
return layer;
|
||||
}
|
||||
|
||||
void QgsGrassVectorMap::closeLayer( QgsGrassVectorMapLayer * layer )
|
||||
{
|
||||
if ( !layer || !layer->map() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QgsDebugMsg( QString( "Close layer %1 usersCount = %2" ).arg( toString() ).arg( layer->userCount() ) );
|
||||
|
||||
lockOpenCloseLayer();
|
||||
layer->removeUser();
|
||||
|
||||
if ( layer->userCount() == 0 ) // No more users, free sources
|
||||
{
|
||||
QgsDebugMsg( "No more users -> clear" );
|
||||
layer->clear();
|
||||
}
|
||||
if ( layer->map()->userCount() == 0 )
|
||||
{
|
||||
QgsDebugMsg( "No more map users -> close" );
|
||||
// TODO: attention about dead lock, probably move to QgsGrassVectorMapStore
|
||||
//layer->map()->close();
|
||||
}
|
||||
|
||||
QgsDebugMsg( "layer closed" );
|
||||
unlockOpenCloseLayer();
|
||||
}
|
||||
|
||||
void QgsGrassVectorMap::closeMap()
|
||||
{
|
||||
QgsDebugMsg( toString() );
|
||||
QgsGrass::lock();
|
||||
if ( !mValid )
|
||||
{
|
||||
QgsDebugMsg( "map is not valid" );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Mapset must be set before Vect_close()
|
||||
QgsGrass::setMapset( mGrassObject.gisdbase(), mGrassObject.location(), mGrassObject.mapset() );
|
||||
|
||||
G_TRY
|
||||
{
|
||||
Vect_close( mMap );
|
||||
QgsDebugMsg( "map closed" );
|
||||
}
|
||||
G_CATCH( QgsGrass::Exception &e )
|
||||
{
|
||||
QgsDebugMsg( "Vect_close failed:" + QString( e.what() ) );
|
||||
}
|
||||
}
|
||||
QgsGrass::vectDestroyMapStruct( mMap );
|
||||
mMap = 0;
|
||||
mOldNumLines = 0;
|
||||
mValid = false;
|
||||
QgsGrass::unlock();
|
||||
}
|
||||
|
||||
void QgsGrassVectorMap::update()
|
||||
{
|
||||
QgsDebugMsg( toString() );
|
||||
lockOpenClose();
|
||||
closeAllIterators(); // blocking
|
||||
closeMap();
|
||||
openMap();
|
||||
unlockOpenClose();
|
||||
}
|
||||
|
||||
bool QgsGrassVectorMap::mapOutdated()
|
||||
{
|
||||
QgsDebugMsg( "entered" );
|
||||
|
||||
QString dp = mGrassObject.mapsetPath() + "/vector/" + mGrassObject.name();
|
||||
QFileInfo di( dp );
|
||||
|
||||
if ( mLastModified < di.lastModified() )
|
||||
{
|
||||
// If the cidx file has been deleted, the map is currently being modified
|
||||
// by an external tool. Do not update until the cidx file has been recreated.
|
||||
if ( !QFileInfo( dp + "/cidx" ).exists() )
|
||||
{
|
||||
QgsDebugMsg( "The map is being modified and is unavailable : " + mGrassObject.toString() );
|
||||
return false;
|
||||
}
|
||||
QgsDebugMsg( "The map was modified : " + mGrassObject.toString() );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QgsGrassVectorMap::attributesOutdated( )
|
||||
{
|
||||
QgsDebugMsg( "entered" );
|
||||
|
||||
|
||||
QString dp = mGrassObject.mapsetPath() + "/vector/" + mGrassObject.name() + "/dbln";
|
||||
QFileInfo di( dp );
|
||||
|
||||
if ( mLastAttributesModified < di.lastModified() )
|
||||
{
|
||||
QgsDebugMsg( "The attributes of the layer were modified : " + mGrassObject.toString() );
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int QgsGrassVectorMap::numLines()
|
||||
{
|
||||
QgsDebugMsg( "entered" );
|
||||
|
||||
return ( Vect_get_num_lines( mMap ) );
|
||||
}
|
||||
|
||||
QString QgsGrassVectorMap::toString()
|
||||
{
|
||||
return mGrassObject.mapsetPath() + "/" + mGrassObject.name();
|
||||
}
|
||||
|
||||
void QgsGrassVectorMap::lockOpenClose()
|
||||
{
|
||||
QgsDebugMsg( "lockOpenClose" );
|
||||
mOpenCloseMutex.lock();
|
||||
}
|
||||
|
||||
void QgsGrassVectorMap::unlockOpenClose()
|
||||
{
|
||||
QgsDebugMsg( "unlockOpenClose" );
|
||||
mOpenCloseMutex.unlock();
|
||||
}
|
||||
|
||||
void QgsGrassVectorMap::lockOpenCloseLayer()
|
||||
{
|
||||
QgsDebugMsg( "lockOpenCloseLayer" );
|
||||
mOpenCloseLayerMutex.lock();
|
||||
}
|
||||
|
||||
void QgsGrassVectorMap::unlockOpenCloseLayer()
|
||||
{
|
||||
QgsDebugMsg( "unlockOpenCloseLayer" );
|
||||
mOpenCloseLayerMutex.unlock();
|
||||
}
|
||||
|
||||
void QgsGrassVectorMap::lockReadWrite()
|
||||
{
|
||||
if ( isEdited() )
|
||||
{
|
||||
QgsDebugMsgLevel( "lockReadWrite", 3 );
|
||||
mReadWriteMutex.lock();
|
||||
}
|
||||
}
|
||||
|
||||
void QgsGrassVectorMap::unlockReadWrite()
|
||||
{
|
||||
if ( isEdited() )
|
||||
{
|
||||
QgsDebugMsgLevel( "unlockReadWrite", 3 );
|
||||
mReadWriteMutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
QgsAbstractGeometryV2 * QgsGrassVectorMap::lineGeometry( int id )
|
||||
{
|
||||
QgsDebugMsgLevel( QString( "id = %1" ).arg( id ), 3 );
|
||||
if ( !Vect_line_alive( mMap, id ) ) // should not happen (update mode!)?
|
||||
{
|
||||
QgsDebugMsg( QString( "line %1 is dead" ).arg( id ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct line_pnts *points = Vect_new_line_struct();
|
||||
|
||||
int type = Vect_read_line( mMap, points, 0, id );
|
||||
QList<QgsPointV2> pointList;
|
||||
for ( int i = 0; i < points->n_points; i++ )
|
||||
{
|
||||
pointList << QgsPointV2( is3d() ? QgsWKBTypes::PointZ : QgsWKBTypes::Point, points->x[i], points->y[i], points->z[i] );
|
||||
}
|
||||
|
||||
Vect_destroy_line_struct( points );
|
||||
|
||||
if ( type & GV_POINTS )
|
||||
{
|
||||
return pointList.first().clone();
|
||||
}
|
||||
else if ( type & GV_LINES )
|
||||
{
|
||||
QgsLineStringV2 * line = new QgsLineStringV2();
|
||||
line->setPoints( pointList );
|
||||
return line;
|
||||
}
|
||||
else if ( type & GV_FACE )
|
||||
{
|
||||
QgsPolygonV2 * polygon = new QgsPolygonV2();
|
||||
QgsLineStringV2 * ring = new QgsLineStringV2();
|
||||
ring->setPoints( pointList );
|
||||
polygon->setExteriorRing( ring );
|
||||
return polygon;
|
||||
}
|
||||
|
||||
QgsDebugMsg( QString( "unknown type = %1" ).arg( type ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
QgsAbstractGeometryV2 * QgsGrassVectorMap::nodeGeometry( int id )
|
||||
{
|
||||
QgsDebugMsgLevel( QString( "id = %1" ).arg( id ), 3 );
|
||||
double x, y, z;
|
||||
Vect_get_node_coor( mMap, id, &x, &y, &z );
|
||||
return new QgsPointV2( is3d() ? QgsWKBTypes::PointZ : QgsWKBTypes::Point, x, y, z );
|
||||
}
|
||||
|
||||
QgsAbstractGeometryV2 * QgsGrassVectorMap::areaGeometry( int id )
|
||||
{
|
||||
QgsDebugMsgLevel( QString( "id = %1" ).arg( id ), 3 );
|
||||
QgsPolygonV2 * polygon = new QgsPolygonV2();
|
||||
|
||||
struct line_pnts *points = Vect_new_line_struct();
|
||||
Vect_get_area_points( mMap, id, points );
|
||||
|
||||
QList<QgsPointV2> pointList;
|
||||
for ( int i = 0; i < points->n_points; i++ )
|
||||
{
|
||||
pointList << QgsPointV2( is3d() ? QgsWKBTypes::PointZ : QgsWKBTypes::Point, points->x[i], points->y[i], points->z[i] );
|
||||
}
|
||||
|
||||
QgsLineStringV2 * ring = new QgsLineStringV2();
|
||||
ring->setPoints( pointList );
|
||||
polygon->setExteriorRing( ring );
|
||||
|
||||
int nIsles = Vect_get_area_num_isles( mMap, id );
|
||||
for ( int i = 0; i < nIsles; i++ )
|
||||
{
|
||||
pointList.clear();
|
||||
int isle = Vect_get_area_isle( mMap, id, i );
|
||||
Vect_get_isle_points( mMap, isle, points );
|
||||
|
||||
for ( int i = 0; i < points->n_points; i++ )
|
||||
{
|
||||
pointList << QgsPointV2( is3d() ? QgsWKBTypes::PointZ : QgsWKBTypes::Point, points->x[i], points->y[i], points->z[i] );
|
||||
}
|
||||
ring = new QgsLineStringV2();
|
||||
ring->setPoints( pointList );
|
||||
polygon->addInteriorRing( ring );
|
||||
}
|
||||
Vect_destroy_line_struct( points );
|
||||
return polygon;
|
||||
}
|
||||
|
||||
void QgsGrassVectorMap::closeAllIterators()
|
||||
{
|
||||
QgsDebugMsg( toString() );
|
||||
// cancel and close all iterator
|
||||
// Iterators must be connected properly, otherwise may it result in dead lock!
|
||||
emit cancelIterators(); // non blocking
|
||||
emit closeIterators(); // blocking
|
||||
QgsDebugMsg( "iterators closed" );
|
||||
}
|
||||
|
||||
//------------------------------------ QgsGrassVectorMapStore ------------------------------------
|
||||
QgsGrassVectorMapStore::QgsGrassVectorMapStore()
|
||||
{
|
||||
}
|
||||
|
||||
QgsGrassVectorMapStore::~QgsGrassVectorMapStore()
|
||||
{
|
||||
QgsDebugMsg( "entered" );
|
||||
}
|
||||
|
||||
QgsGrassVectorMapStore *QgsGrassVectorMapStore::instance()
|
||||
{
|
||||
static QgsGrassVectorMapStore instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
QgsGrassVectorMap * QgsGrassVectorMapStore::openMap( const QgsGrassObject & grassObject )
|
||||
{
|
||||
QgsDebugMsg( "grassObject = " + grassObject.toString() );
|
||||
|
||||
mMutex.lock();
|
||||
QgsGrassVectorMap *map = 0;
|
||||
|
||||
// Check if this map is already open
|
||||
foreach ( QgsGrassVectorMap *m, mMaps )
|
||||
{
|
||||
if ( m->grassObject() == grassObject )
|
||||
{
|
||||
QgsDebugMsg( "The map is already open" );
|
||||
map = m;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !map )
|
||||
{
|
||||
map = new QgsGrassVectorMap( grassObject );
|
||||
mMaps << map;
|
||||
}
|
||||
|
||||
mMutex.unlock();
|
||||
return map;
|
||||
}
|
189
src/providers/grass/qgsgrassvectormap.h
Normal file
189
src/providers/grass/qgsgrassvectormap.h
Normal file
@ -0,0 +1,189 @@
|
||||
/***************************************************************************
|
||||
qgsgrassvectormap.cpp
|
||||
-------------------
|
||||
begin : September, 2015
|
||||
copyright : (C) 2015 by Radim Blazek
|
||||
email : radim.blazek@gmail.com
|
||||
***************************************************************************/
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSGRASSVECTORMAP_H
|
||||
#define QGSGRASSVECTORMAP_H
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QObject>
|
||||
|
||||
#include "qgsabstractgeometryv2.h"
|
||||
|
||||
#include "qgsgrass.h"
|
||||
#include "qgsgrassvectormaplayer.h"
|
||||
|
||||
class GRASS_LIB_EXPORT QgsGrassVectorMap : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QgsGrassVectorMap( const QgsGrassObject & grassObject );
|
||||
~QgsGrassVectorMap();
|
||||
|
||||
QgsGrassObject grassObject() const { return mGrassObject; }
|
||||
struct Map_info *map() { return mMap; }
|
||||
bool isValid() const { return mValid; }
|
||||
bool isFrozen() const { return mFrozen; }
|
||||
bool isEdited() const { return mIsEdited; }
|
||||
int version() const { return mVersion; }
|
||||
int oldNumLines() const { return mOldNumLines; }
|
||||
// number of instances using this map
|
||||
int userCount() const;
|
||||
/** Get current number of lines.
|
||||
* @return number of lines */
|
||||
int numLines();
|
||||
// 3D map with z coordinates
|
||||
bool is3d() { return mIs3d; }
|
||||
|
||||
// Lock open / close
|
||||
void lockOpenClose();
|
||||
void unlockOpenClose();
|
||||
|
||||
// Lock open / close
|
||||
void lockOpenCloseLayer();
|
||||
void unlockOpenCloseLayer();
|
||||
|
||||
// Lock reading and writing
|
||||
void lockReadWrite();
|
||||
void unlockReadWrite();
|
||||
|
||||
QHash<int, int> & oldLids() { return mOldLids; }
|
||||
QHash<int, int> & newLids() { return mNewLids; }
|
||||
QHash<int, QgsAbstractGeometryV2*> & oldGeometries() { return mOldGeometries; }
|
||||
|
||||
/** Get geometry of line.
|
||||
* @return geometry (point,line or polygon(GV_FACE)) or 0 */
|
||||
QgsAbstractGeometryV2 * lineGeometry( int id );
|
||||
QgsAbstractGeometryV2 * nodeGeometry( int id );
|
||||
QgsAbstractGeometryV2 * areaGeometry( int id );
|
||||
|
||||
/** Open map if not yet open. Open/close lock */
|
||||
bool open();
|
||||
|
||||
/** Close map. All iterators are closed first. Open/close lock. */
|
||||
void close();
|
||||
|
||||
/** Open GRASS map, no open/close locking */
|
||||
bool openMap();
|
||||
|
||||
/** Close GRASS map, no open/close locking */
|
||||
void closeMap();
|
||||
|
||||
bool startEdit();
|
||||
bool closeEdit( bool newMap );
|
||||
|
||||
/** Get layer, layer is created and loaded if not yet.
|
||||
* @param field
|
||||
* @return pointer to layer or 0 if layer doe not exist */
|
||||
QgsGrassVectorMapLayer * openLayer( int field );
|
||||
|
||||
/** Close layer and release cached data if there are no more users and close map
|
||||
* if there are no more map users.
|
||||
* @param layer */
|
||||
void closeLayer( QgsGrassVectorMapLayer * layer );
|
||||
|
||||
/** Update map. Close and reopen vector and refresh layers.
|
||||
* Instances of QgsGrassProvider are not updated and should call update() method */
|
||||
void update();
|
||||
|
||||
/** The map is outdated. The map was for example rewritten by GRASS module outside QGIS.
|
||||
* This function checks internal timestamp stored in QGIS.
|
||||
*/
|
||||
bool mapOutdated();
|
||||
|
||||
/** The attributes are outdated. The table was for example updated by GRASS module outside QGIS.
|
||||
* This function checks internal timestamp stored in QGIS.
|
||||
*/
|
||||
bool attributesOutdated();
|
||||
|
||||
/** Map descripton for debugging */
|
||||
QString toString();
|
||||
|
||||
signals:
|
||||
/** Ask all iterators to cancel iteration when possible. Connected to iterators with
|
||||
* Qt::DirectConnection (non blocking) */
|
||||
void cancelIterators();
|
||||
|
||||
/** Close all iterators. Connected to iterators in different threads with Qt::BlockingQueuedConnection */
|
||||
void closeIterators();
|
||||
|
||||
private:
|
||||
/** Close iterators, blocking */
|
||||
void closeAllIterators();
|
||||
|
||||
QgsGrassObject mGrassObject;
|
||||
// true if map is open, once the map is closed, valid is set to false and no more used
|
||||
bool mValid;
|
||||
// Indicates if map is open, it may be open but invalide
|
||||
bool mOpen;
|
||||
// Vector temporally disabled. Necessary for GRASS Tools on Windows
|
||||
bool mFrozen;
|
||||
// true if the map is opened in update mode
|
||||
bool mIsEdited;
|
||||
// version, increased by each closeEdit() and updateMap()
|
||||
int mVersion;
|
||||
// last modified time of the vector directory, when the map was opened
|
||||
QDateTime mLastModified;
|
||||
// last modified time of the vector 'dbln' file, when the map was opened
|
||||
// or attributes were updated. The 'dbln' file is updated by v.to.db etc.
|
||||
QDateTime mLastAttributesModified;
|
||||
// when attributes are changed
|
||||
// map header
|
||||
struct Map_info *mMap;
|
||||
// Is 3D, has z coordinates
|
||||
bool mIs3d;
|
||||
// Vector layers
|
||||
QList<QgsGrassVectorMapLayer*> mLayers;
|
||||
// Number of lines in vector before editing started
|
||||
int mOldNumLines;
|
||||
// Original line ids of rewritten GRASS lines (new lid -> old lid)
|
||||
QHash<int, int> mOldLids;
|
||||
// Current line ids for old line ids (old lid -> new lid)
|
||||
QHash<int, int> mNewLids;
|
||||
// Hash of original lines' geometries of lines which were changed, keys are GRASS lid
|
||||
QHash<int, QgsAbstractGeometryV2*> mOldGeometries;
|
||||
|
||||
// Mutex used to avoid concurrent read/write, used only in editing mode
|
||||
QMutex mReadWriteMutex;
|
||||
|
||||
// Open / close mutex
|
||||
QMutex mOpenCloseMutex;
|
||||
|
||||
// Open / close mutex
|
||||
QMutex mOpenCloseLayerMutex;
|
||||
};
|
||||
|
||||
class QgsGrassVectorMapStore
|
||||
{
|
||||
public:
|
||||
QgsGrassVectorMapStore();
|
||||
~QgsGrassVectorMapStore();
|
||||
|
||||
static QgsGrassVectorMapStore *instance();
|
||||
|
||||
/** Open map.
|
||||
* @param grassObject
|
||||
* @return map, the map may be invalide */
|
||||
QgsGrassVectorMap * openMap( const QgsGrassObject & grassObject );
|
||||
|
||||
private:
|
||||
/** Open vector maps */
|
||||
QList<QgsGrassVectorMap*> mMaps;
|
||||
|
||||
// Lock open/close map
|
||||
QMutex mMutex;
|
||||
};
|
||||
|
||||
#endif // QGSGRASSVECTORMAP_H
|
317
src/providers/grass/qgsgrassvectormaplayer.cpp
Normal file
317
src/providers/grass/qgsgrassvectormaplayer.cpp
Normal file
@ -0,0 +1,317 @@
|
||||
/***************************************************************************
|
||||
qgsgrassvectormaplayer.cpp
|
||||
-------------------
|
||||
begin : September, 2015
|
||||
copyright : (C) 2015 by Radim Blazek
|
||||
email : radim.blazek@gmail.com
|
||||
***************************************************************************/
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include <QFileInfo>
|
||||
|
||||
#include "qgslogger.h"
|
||||
|
||||
#include "qgsgrass.h"
|
||||
#include "qgsgrassvectormap.h"
|
||||
#include "qgsgrassvectormaplayer.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <grass/version.h>
|
||||
#include <grass/gprojects.h>
|
||||
#include <grass/gis.h>
|
||||
#include <grass/dbmi.h>
|
||||
#if GRASS_VERSION_MAJOR < 7
|
||||
#include <grass/Vect.h>
|
||||
#else
|
||||
#include <grass/vector.h>
|
||||
#define BOUND_BOX bound_box
|
||||
#endif
|
||||
}
|
||||
|
||||
QgsGrassVectorMapLayer::QgsGrassVectorMapLayer( QgsGrassVectorMap *map, int field )
|
||||
: mField( field )
|
||||
, mValid( false )
|
||||
, mMap( map )
|
||||
, mFieldInfo( 0 )
|
||||
, mHasTable( false )
|
||||
, mKeyColumn( -1 )
|
||||
, mUsers( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
void QgsGrassVectorMapLayer::clear()
|
||||
{
|
||||
QgsDebugMsg( "entered" );
|
||||
mFields.clear();
|
||||
mAttributes.clear();
|
||||
mMinMax.clear();
|
||||
mKeyColumn = -1;
|
||||
mValid = false;
|
||||
G_free( mFieldInfo );
|
||||
mFieldInfo = 0;
|
||||
}
|
||||
|
||||
void QgsGrassVectorMapLayer::load()
|
||||
{
|
||||
QgsDebugMsg( "entered" );
|
||||
clear();
|
||||
|
||||
if ( !mMap )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Attributes are not loaded for topo layers in which case field == 0
|
||||
if ( mField == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mFieldInfo = Vect_get_field( mMap->map(), mField ); // should work also with field = 0
|
||||
|
||||
if ( !mFieldInfo )
|
||||
{
|
||||
QgsDebugMsg( "No field info -> no attribute table" );
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsDebugMsg( "Field info found -> open database" );
|
||||
|
||||
QFileInfo di( mMap->grassObject().mapsetPath() + "/vector/" + mMap->grassObject().name() + "/dbln" );
|
||||
mLastLoaded = di.lastModified();
|
||||
|
||||
QgsGrass::lock();
|
||||
dbDriver *databaseDriver = 0;
|
||||
QString error = QString( "Cannot open database %1 by driver %2" ).arg( mFieldInfo->database ).arg( mFieldInfo->driver );
|
||||
G_TRY
|
||||
{
|
||||
databaseDriver = db_start_driver_open_database( mFieldInfo->driver, mFieldInfo->database );
|
||||
}
|
||||
G_CATCH( QgsGrass::Exception &e )
|
||||
{
|
||||
QgsGrass::warning( error + " : " + e.what() );
|
||||
}
|
||||
|
||||
if ( !databaseDriver )
|
||||
{
|
||||
QgsDebugMsg( error );
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsDebugMsg( "Database opened -> open select cursor" );
|
||||
dbString dbstr;
|
||||
db_init_string( &dbstr );
|
||||
db_set_string( &dbstr, ( char * )"select * from " );
|
||||
db_append_string( &dbstr, mFieldInfo->table );
|
||||
|
||||
QgsDebugMsg( QString( "SQL: %1" ).arg( db_get_string( &dbstr ) ) );
|
||||
dbCursor databaseCursor;
|
||||
if ( db_open_select_cursor( databaseDriver, &dbstr, &databaseCursor, DB_SCROLL ) != DB_OK )
|
||||
{
|
||||
db_close_database_shutdown_driver( databaseDriver );
|
||||
QgsGrass::warning( "Cannot select attributes from table '" + QString( mFieldInfo->table ) + "'" );
|
||||
}
|
||||
else
|
||||
{
|
||||
int nRecords = db_get_num_rows( &databaseCursor );
|
||||
QgsDebugMsg( QString( "Number of records: %1" ).arg( nRecords ) );
|
||||
|
||||
dbTable *databaseTable = db_get_cursor_table( &databaseCursor );
|
||||
int nColumns = db_get_table_number_of_columns( databaseTable );
|
||||
|
||||
// Read columns' description
|
||||
for ( int i = 0; i < nColumns; i++ )
|
||||
{
|
||||
QPair<double, double> minMax( DBL_MAX, -DBL_MAX );
|
||||
|
||||
dbColumn *column = db_get_table_column( databaseTable, i );
|
||||
|
||||
int ctype = db_sqltype_to_Ctype( db_get_column_sqltype( column ) );
|
||||
QVariant::Type qtype = QVariant::String; //default to string
|
||||
QgsDebugMsg( QString( "column = %1 ctype = %2" ).arg( db_get_column_name( column ) ).arg( ctype ) );
|
||||
|
||||
QString ctypeStr;
|
||||
switch ( ctype )
|
||||
{
|
||||
case DB_C_TYPE_INT:
|
||||
ctypeStr = "integer";
|
||||
qtype = QVariant::Int;
|
||||
break;
|
||||
case DB_C_TYPE_DOUBLE:
|
||||
ctypeStr = "double";
|
||||
qtype = QVariant::Double;
|
||||
break;
|
||||
case DB_C_TYPE_STRING:
|
||||
ctypeStr = "string";
|
||||
qtype = QVariant::String;
|
||||
break;
|
||||
case DB_C_TYPE_DATETIME:
|
||||
ctypeStr = "datetime";
|
||||
qtype = QVariant::String;
|
||||
break;
|
||||
}
|
||||
mFields.append( QgsField( db_get_column_name( column ), qtype, ctypeStr,
|
||||
db_get_column_length( column ), db_get_column_precision( column ) ) );
|
||||
mMinMax << minMax;
|
||||
if ( G_strcasecmp( db_get_column_name( column ), mFieldInfo->key ) == 0 )
|
||||
{
|
||||
mKeyColumn = i;
|
||||
}
|
||||
}
|
||||
|
||||
if ( mKeyColumn < 0 )
|
||||
{
|
||||
mFields.clear();
|
||||
QgsGrass::warning( QObject::tr( "Key column '%1' not found in the table '%2'" ).arg( mFieldInfo->key ).arg( mFieldInfo->table ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
mHasTable = true;
|
||||
// Read attributes to the memory
|
||||
while ( true )
|
||||
{
|
||||
int more;
|
||||
|
||||
if ( db_fetch( &databaseCursor, DB_NEXT, &more ) != DB_OK )
|
||||
{
|
||||
QgsDebugMsg( "Cannot fetch DB record" );
|
||||
break;
|
||||
}
|
||||
if ( !more )
|
||||
{
|
||||
break; // no more records
|
||||
}
|
||||
|
||||
// Check cat value
|
||||
dbColumn *column = db_get_table_column( databaseTable, mKeyColumn );
|
||||
dbValue *value = db_get_column_value( column );
|
||||
|
||||
if ( db_test_value_isnull( value ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
int cat = db_get_value_int( value );
|
||||
if ( cat < 0 )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
QList<QVariant> values;
|
||||
for ( int i = 0; i < nColumns; i++ )
|
||||
{
|
||||
column = db_get_table_column( databaseTable, i );
|
||||
int sqltype = db_get_column_sqltype( column );
|
||||
int ctype = db_sqltype_to_Ctype( sqltype );
|
||||
value = db_get_column_value( column );
|
||||
db_convert_value_to_string( value, sqltype, &dbstr );
|
||||
|
||||
QgsDebugMsgLevel( QString( "column = %1 value = %2" ).arg( db_get_column_name( column ) ).arg( db_get_string( &dbstr ) ), 3 );
|
||||
|
||||
QVariant variant;
|
||||
if ( !db_test_value_isnull( value ) )
|
||||
{
|
||||
int iv;
|
||||
double dv;
|
||||
//layer.mAttributes[layer.nAttributes].values[i] = strdup( db_get_string( &dbstr ) );
|
||||
switch ( ctype )
|
||||
{
|
||||
case DB_C_TYPE_INT:
|
||||
iv = db_get_value_int( value );
|
||||
variant = QVariant( iv );
|
||||
mMinMax[i].first = qMin( mMinMax[i].first, ( double )iv );
|
||||
mMinMax[i].second = qMin( mMinMax[i].second, ( double )iv );
|
||||
break;
|
||||
case DB_C_TYPE_DOUBLE:
|
||||
dv = db_get_value_double( value );
|
||||
variant = QVariant( dv );
|
||||
mMinMax[i].first = qMin( mMinMax[i].first, dv );
|
||||
mMinMax[i].second = qMin( mMinMax[i].second, dv );
|
||||
break;
|
||||
case DB_C_TYPE_STRING:
|
||||
// Store as byte array so that codec may be used later
|
||||
variant = QVariant( QByteArray( db_get_value_string( value ) ) );
|
||||
break;
|
||||
case DB_C_TYPE_DATETIME:
|
||||
variant = QVariant( QByteArray( db_get_string( &dbstr ) ) );
|
||||
default:
|
||||
variant = QVariant( QByteArray( db_get_string( &dbstr ) ) );
|
||||
}
|
||||
}
|
||||
QgsDebugMsgLevel( QString( "column = %1 variant = %2" ).arg( db_get_column_name( column ) ).arg( variant.toString() ), 3 );
|
||||
values << variant;
|
||||
}
|
||||
mAttributes.insert( cat, values );
|
||||
}
|
||||
}
|
||||
mValid = true;
|
||||
db_close_cursor( &databaseCursor );
|
||||
db_close_database_shutdown_driver( databaseDriver );
|
||||
db_free_string( &dbstr );
|
||||
|
||||
QgsDebugMsg( QString( "mFields.size = %1" ).arg( mFields.size() ) );
|
||||
QgsDebugMsg( QString( "number of attributes = %1" ).arg( mAttributes.size() ) );
|
||||
}
|
||||
}
|
||||
QgsGrass::unlock();
|
||||
}
|
||||
|
||||
// Add cat if no attribute fields exist (otherwise qgis crashes)
|
||||
if ( mFields.size() == 0 )
|
||||
{
|
||||
mKeyColumn = 0;
|
||||
mFields.append( QgsField( "cat", QVariant::Int, "integer" ) );
|
||||
QPair<double, double> minMax( 0, 0 );
|
||||
|
||||
int cidx = Vect_cidx_get_field_index( mMap->map(), mField );
|
||||
if ( cidx >= 0 )
|
||||
{
|
||||
int ncats, cat, type, id;
|
||||
|
||||
ncats = Vect_cidx_get_num_cats_by_index( mMap->map(), cidx );
|
||||
|
||||
if ( ncats > 0 )
|
||||
{
|
||||
Vect_cidx_get_cat_by_index( mMap->map(), cidx, 0, &cat, &type, &id );
|
||||
minMax.first = cat;
|
||||
|
||||
Vect_cidx_get_cat_by_index( mMap->map(), cidx, ncats - 1, &cat, &type, &id );
|
||||
minMax.second = cat;
|
||||
}
|
||||
}
|
||||
mMinMax << minMax;
|
||||
}
|
||||
|
||||
// TODO
|
||||
// add topo field for editing
|
||||
mFields.append( QgsField( "topo_symbol", QVariant::Int, "integer" ) );
|
||||
|
||||
QgsDebugMsg( QString( "layer loaded mFields.size() = %1 mAttributes.size() = %2" ).arg( mFields.size() ).arg( mAttributes.size() ) );
|
||||
mValid = true;
|
||||
}
|
||||
|
||||
void QgsGrassVectorMapLayer::addUser()
|
||||
{
|
||||
mUsers++;
|
||||
QgsDebugMsg( QString( "user added mUsers = %1" ).arg( mUsers ) );
|
||||
}
|
||||
|
||||
void QgsGrassVectorMapLayer::removeUser()
|
||||
{
|
||||
mUsers--;
|
||||
QgsDebugMsg( QString( "user removed mUsers = %1" ).arg( mUsers ) );
|
||||
}
|
||||
|
||||
void QgsGrassVectorMapLayer::close()
|
||||
{
|
||||
QgsDebugMsg( "close" );
|
||||
//removeUser(); // removed by map
|
||||
mMap->closeLayer( this );
|
||||
}
|
76
src/providers/grass/qgsgrassvectormaplayer.h
Normal file
76
src/providers/grass/qgsgrassvectormaplayer.h
Normal file
@ -0,0 +1,76 @@
|
||||
/***************************************************************************
|
||||
qgsgrassvectormaplayer.h
|
||||
-------------------
|
||||
begin : September, 2015
|
||||
copyright : (C) 2015 by Radim Blazek
|
||||
email : radim.blazek@gmail.com
|
||||
***************************************************************************/
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSGRASSVECTORMAPLAYER_H
|
||||
#define QGSGRASSVECTORMAPLAYER_H
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QMap>
|
||||
#include <QObject>
|
||||
#include <QPair>
|
||||
|
||||
#include "qgsfield.h"
|
||||
|
||||
class QgsGrassVectorMap;
|
||||
|
||||
class GRASS_LIB_EXPORT QgsGrassVectorMapLayer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QgsGrassVectorMapLayer( QgsGrassVectorMap *map, int field );
|
||||
|
||||
int field() const { return mField; }
|
||||
bool isValid() const { return mValid; }
|
||||
QgsGrassVectorMap *map() { return mMap; }
|
||||
QgsFields & fields() { return mFields; }
|
||||
QMap<int, QList<QVariant>> & attributes() { return mAttributes; }
|
||||
bool hasTable() { return mHasTable; }
|
||||
int keyColumn() { return mKeyColumn; }
|
||||
QList<QPair<double, double>> minMax() { return mMinMax; }
|
||||
int userCount() { return mUsers; }
|
||||
void addUser();
|
||||
void removeUser();
|
||||
|
||||
/** Load attributes from the map. Old sources are released. */
|
||||
void load();
|
||||
|
||||
/** Clear all cached data */
|
||||
void clear();
|
||||
|
||||
/** Decrease number of users and clear if no more users */
|
||||
void close();
|
||||
|
||||
private:
|
||||
|
||||
int mField;
|
||||
bool mValid;
|
||||
QgsGrassVectorMap *mMap;
|
||||
struct field_info *mFieldInfo;
|
||||
bool mHasTable;
|
||||
// index of key column
|
||||
int mKeyColumn;
|
||||
QgsFields mFields;
|
||||
// Map of attributes with cat as key
|
||||
QMap<int, QList<QVariant>> mAttributes;
|
||||
// minimum and maximum values of attributes
|
||||
QList<QPair<double, double>> mMinMax;
|
||||
// timestamp when attributes were loaded
|
||||
QDateTime mLastLoaded;
|
||||
// number of instances using this layer
|
||||
int mUsers;
|
||||
};
|
||||
|
||||
#endif // QGSGRASSVECTORMAPLAYER_H
|
Loading…
x
Reference in New Issue
Block a user