mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-13 00:03:09 -04:00
handling vector data geometry and attribute updates refactored
QgsVectorLayer: - move attribute part of editing to vector layer class and unify with geometry handling: * remove commitAttributeChanges(), addedFeatures(), deletedFeatureIds(), changedAttributes() and replace with changeAttributeValue(), deleteFeature(), addAttribute() and deleteAttribute() * add pendingFields(), pendingAttributeList(), pendingFeatureCount() * emit signals on start editing and commit, change of attribute values, adding/deleting of attributes and layer or feature removal (currently used in the attribute table) - new commitErrors() method to query errors from commitChanges() - replaced featuresInRectangle with select/getNextFeature combo - edit types added to support more input widgets and input constraints QgsFeature: - remove update aware ctor - unify geometry handling in ctors QgsVectorDataProvider: - add QVariant::Type to supportNativeTypes() QgisApp: - add instance() method to query QgisApp object - replace code at various place to use it instead of passing the pointer arround or searching it in the widget tree. - move toggleEditing() code from the legend here QgsAttributeTable/QgsAttributeTableDisplay: - move attribute table creation legend here - make attribute table dockable (from Tim) - most editing logic moved to QgsVectorLayer - adding/deleting attributes moved to QgsVectorLayerProperties QgsIdentifyResults: - add support for attribute editing when it edit mode QgsVectorLayerProperties: add a new tab to show attribute list: * start/stop editing * add/delete attributes * assign edit type to attributes (unique values, value map, ranges) QgsAttributeDialog: add support for attribute edit types: * selection from unique value render classes (combobox) * selection from unique values of existing features (combobox or line edits with completion) * spinboxes for ranges QgsPostgresProvider: - use read-only connection for cursors and read-write connection for updates - updated native types QgsOgrProvider: - remove unused references to GEOS geometry factory - updated native types git-svn-id: http://svn.osgeo.org/qgis/trunk@9092 c8812cc2-4d05-0410-92ff-de0c093fc19c
This commit is contained in:
parent
03ef707a0d
commit
43278d720b
@ -13,18 +13,6 @@ class QgsFeature
|
||||
//! Constructor
|
||||
QgsFeature(int id = 0, QString typeName = "" );
|
||||
|
||||
/** create a copy of this feature in its uncommitted state.
|
||||
To do this, you also pass in a reference to the feature's
|
||||
layer's uncommitted attribute and geometry changes.
|
||||
The resulting feature will have those changes applied.
|
||||
|
||||
This is useful in the cut/copy routine, where you'd
|
||||
want a copy of the "current" feature, not the on-disk feature.
|
||||
*/
|
||||
QgsFeature( const QgsFeature & rhs,
|
||||
const QMap<int, QMap<int, QVariant> >& changedAttributes,
|
||||
const QMap<int, QgsGeometry> & changedGeometries );
|
||||
|
||||
/** copy ctor needed due to internal pointer */
|
||||
QgsFeature(const QgsFeature & rhs );
|
||||
|
||||
|
@ -88,7 +88,6 @@ class QgsVectorDataProvider : QgsDataProvider
|
||||
*/
|
||||
virtual QGis::WKBTYPE geometryType() const = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Number of features in the layer
|
||||
* @return long containing number of features
|
||||
@ -230,7 +229,7 @@ class QgsVectorDataProvider : QgsDataProvider
|
||||
QList<int> allAttributesList();
|
||||
|
||||
/**Returns the names of the numerical types*/
|
||||
const QSet<QString>& supportedNativeTypes() const;
|
||||
const QMap<QString,QVariant::Type> &supportedNativeTypes() const;
|
||||
|
||||
/**
|
||||
* Set whether provider should return also features that don't have
|
||||
|
@ -1,12 +1,27 @@
|
||||
|
||||
|
||||
class QgsVectorLayer : QgsMapLayer
|
||||
{
|
||||
%TypeHeaderCode
|
||||
#include <qgsvectorlayer.h>
|
||||
#include "qgsvectorlayer.h"
|
||||
%End
|
||||
|
||||
public:
|
||||
enum EditType {
|
||||
LineEdit,
|
||||
UniqueValues,
|
||||
UniqueValuesEditable,
|
||||
ValueMap,
|
||||
Classification,
|
||||
Range,
|
||||
};
|
||||
|
||||
struct RangeData {
|
||||
RangeData();
|
||||
RangeData(QVariant theMin, QVariant theMax, QVariant theStep);
|
||||
|
||||
QVariant mMin;
|
||||
QVariant mMax;
|
||||
QVariant mStep;
|
||||
};
|
||||
|
||||
/** Constructor */
|
||||
QgsVectorLayer(QString baseName = 0, QString path = 0, QString providerLib = 0);
|
||||
@ -66,10 +81,6 @@ public:
|
||||
/** Returns the bounding box of the selected features. If there is no selection, QgsRect(0,0,0,0) is returned */
|
||||
QgsRect boundingBoxOfSelected();
|
||||
|
||||
|
||||
/** Insert a copy of the given features into the layer */
|
||||
bool addFeatures(QList<QgsFeature> features, bool makeSelected = TRUE);
|
||||
|
||||
/** Copies the symbology settings from another layer. Returns true in case of success */
|
||||
bool copySymbologySettings(const QgsMapLayer& other);
|
||||
|
||||
@ -92,12 +103,12 @@ public:
|
||||
QString providerType() const;
|
||||
|
||||
/** reads vector layer specific state from project file DOM node.
|
||||
* @note Called by QgsMapLayer::readXML().
|
||||
* @note Called by QgsMapLayer::readXml().
|
||||
*/
|
||||
virtual bool readXml( QDomNode & layer_node );
|
||||
|
||||
/** write vector layer specific state to project file DOM node.
|
||||
* @note Called by QgsMapLayer::writeXML().
|
||||
* @note Called by QgsMapLayer::writeXml().
|
||||
*/
|
||||
virtual bool writeXml( QDomNode & layer_node, QDomDocument & doc );
|
||||
|
||||
@ -130,17 +141,20 @@ public:
|
||||
*/
|
||||
virtual QString subsetString();
|
||||
|
||||
/**Returns the features contained in the rectangle. Considers the changed, added, deleted and permanent features
|
||||
@return 0 in case of success*/
|
||||
int featuresInRectangle(const QgsRect& searchRect, QList<QgsFeature>& features /Out/, bool fetchGeometries = true, bool fetchAttributes = true);
|
||||
void select(QList<int> fetchAttributes = QList<int>(),
|
||||
QgsRect rect = QgsRect(),
|
||||
bool fetchGeometry = true);
|
||||
|
||||
/**Gets the feature at the given feature id. Considers the changed, added, deleted and permanent features
|
||||
bool getNextFeature(QgsFeature& feature);
|
||||
|
||||
|
||||
/**Gets the feature at the given feature id. Considers the changed, added, deleted and permanent features
|
||||
@return 0 in case of success*/
|
||||
int getFeatureAtId(int featureId, QgsFeature& f, bool fetchGeometries = true, bool fetchAttributes = true);
|
||||
int getFeatureAtId(int featureId, QgsFeature& f, bool fetchGeometries = true, bool fetchAttributes = true);
|
||||
|
||||
/** Adds a feature
|
||||
@param lastFeatureInBatch If True, will also go to the effort of e.g. updating the extents.
|
||||
@return Irue in case of success and False in case of error
|
||||
@param alsoUpdateExtent If True, will also go to the effort of e.g. updating the extents.
|
||||
@return True in case of success and False in case of error
|
||||
*/
|
||||
bool addFeature(QgsFeature& f, bool alsoUpdateExtent = TRUE);
|
||||
|
||||
@ -168,49 +182,60 @@ public:
|
||||
bool deleteSelectedFeatures();
|
||||
|
||||
/**Adds a ring to polygon/multipolygon features
|
||||
@return 0 in case of success, 1 problem with feature type, 2 ring not closed, 3 ring not valid, 4 ring crosses \
|
||||
existing rings, 5 no feature found where ring can be inserted*/
|
||||
@return
|
||||
0 in case of success,
|
||||
1 problem with feature type,
|
||||
2 ring not closed,
|
||||
3 ring not valid,
|
||||
4 ring crosses existing rings,
|
||||
5 no feature found where ring can be inserted*/
|
||||
int addRing(const QList<QgsPoint>& ring);
|
||||
|
||||
/**Adds a new island polygon to a multipolygon feature
|
||||
@return 0 in case of success, 1 if selected feature is not multipolygon, 2 if ring is not a valid geometry, \
|
||||
3 if new polygon ring not disjoint with existing rings, 4 if no feature was selected, 5 if several features are selected, \
|
||||
6 if selected geometry not found*/
|
||||
@return
|
||||
0 in case of success,
|
||||
1 if selected feature is not multipolygon,
|
||||
2 if ring is not a valid geometry,
|
||||
3 if new polygon ring not disjoint with existing rings,
|
||||
4 if no feature was selected,
|
||||
5 if several features are selected,
|
||||
6 if selected geometry not found*/
|
||||
int addIsland(const QList<QgsPoint>& ring);
|
||||
|
||||
/**Translates feature by dx, dy
|
||||
/**Translates feature by dx, dy
|
||||
@param featureId id of the feature to translate
|
||||
@param dx translation of x-coordinate
|
||||
@param dy translation of y-coordinate
|
||||
@return 0 in case of success*/
|
||||
int translateFeature(int featureId, double dx, double dy);
|
||||
|
||||
/**Splits features cut by the given line
|
||||
/**Splits features cut by the given line
|
||||
@param splitLine line that splits the layer features
|
||||
@param topologicalEditing true if topological editing is enabled
|
||||
@return 0 in case of success, 1 if several intersections but only 1 split done, \
|
||||
2 if intersection too complex to be handled, else other error*/
|
||||
@return
|
||||
0 in case of success,
|
||||
1 if several intersections but only 1 split done,
|
||||
2 if intersection too complex to be handled, else other error*/
|
||||
int splitFeatures(const QList<QgsPoint>& splitLine, bool topologicalEditing = false);
|
||||
|
||||
/**Changes the specified geometry such that it has no intersections with other \
|
||||
/**Changes the specified geometry such that it has no intersections with other \
|
||||
polygon (or multipolygon) geometries in this vector layer
|
||||
@param geom geometry to modify
|
||||
@return 0 in case of success*/
|
||||
@param geom geometry to modify
|
||||
@return 0 in case of success*/
|
||||
int removePolygonIntersections(QgsGeometry* geom);
|
||||
|
||||
/**Adds topological points for every vertex of the
|
||||
geometry
|
||||
@param geom the geometry where each vertex is added to segments of other features
|
||||
Note: geom is not going to be modified by the function
|
||||
@return 0 in case of success*/
|
||||
/**Adds topological points for every vertex of the geometry
|
||||
@param geom the geometry where each vertex is added to segments of other features
|
||||
Note: geom is not going to be modified by the function
|
||||
@return 0 in case of success*/
|
||||
int addTopologicalPoints(QgsGeometry* geom);
|
||||
|
||||
/**Adds a vertex to segments which intersect point p but don't
|
||||
already have a vertex there. If a feature already has a vertex at position p,
|
||||
no additional vertex is inserted. This method is usefull for topological
|
||||
editing.
|
||||
@param p position of the vertex
|
||||
@return 0 in case of success*/
|
||||
/**Adds a vertex to segments which intersect point p but don't
|
||||
already have a vertex there. If a feature already has a vertex at position p,
|
||||
no additional vertex is inserted. This method is usefull for topological
|
||||
editing.
|
||||
@param p position of the vertex
|
||||
@return 0 in case of success*/
|
||||
int addTopologicalPoints(const QgsPoint& p);
|
||||
|
||||
/**Inserts vertices to the snapped segments.
|
||||
@ -246,29 +271,7 @@ existing rings, 5 no feature found where ring can be inserted*/
|
||||
@return 0 in case of success
|
||||
*/
|
||||
int snapWithContext(const QgsPoint& startPoint, double snappingTolerance, QMultiMap<double, QgsSnappingResult>& snappingResults /Out/,
|
||||
QgsSnapper::SNAP_TO snap_to);
|
||||
|
||||
/**
|
||||
Commits edited attributes. Depending on the feature id,
|
||||
the changes are written to not commited features or redirected to
|
||||
the data provider
|
||||
|
||||
The commits (in this version) occur in three distinct stages,
|
||||
(delete attributes, add attributes, change attribute values)
|
||||
so if a stage fails, it's difficult to roll back cleanly.
|
||||
|
||||
\todo Need to indicate at which stage the failed commit occurred,
|
||||
for better cleanup and recovery from the error.
|
||||
|
||||
\param deleted Set of attribute indices (i.e. columns) to delete
|
||||
\param added Map (name, type) of attribute names (i.e. columns) to add
|
||||
\param changed Map (feature ID, Map (attribute name, new value) )
|
||||
of attribute values to change
|
||||
|
||||
*/
|
||||
bool commitAttributeChanges(const QSet<int>& deleted,
|
||||
const QMap<QString, QString>& added,
|
||||
const QMap<int, QMap<int, QVariant> >& changed);
|
||||
QgsSnapper::SNAP_TO snap_to);
|
||||
|
||||
/** Draws the layer using coordinate transformation
|
||||
* @return FALSE if an error occurred during drawing
|
||||
@ -283,20 +286,36 @@ existing rings, 5 no feature found where ring can be inserted*/
|
||||
*/
|
||||
void drawLabels(QPainter * p, const QgsRect& viewExtent, const QgsMapToPixel* cXf, const QgsCoordinateTransform* ct, double scale);
|
||||
|
||||
/** returns array of added features */
|
||||
QList<QgsFeature>& addedFeatures();
|
||||
/** returns list of attributes */
|
||||
QList<int> pendingAllAttributesList();
|
||||
|
||||
/** returns array of deleted feature IDs */
|
||||
QSet<int>& deletedFeatureIds();
|
||||
|
||||
/** returns array of features with changed attributes */
|
||||
QMap<int, QMap<int, QVariant> >& changedAttributes();
|
||||
/** returns fields list which are not commited */
|
||||
const QMap<int, QgsField> &pendingFields();
|
||||
|
||||
/** returns feature count after commit */
|
||||
int pendingFeatureCount();
|
||||
|
||||
/** Sets whether some features are modified or not */
|
||||
void setModified(bool modified = TRUE, bool onlyGeometryWasModified = FALSE);
|
||||
|
||||
/** Make layer editable */
|
||||
bool startEditing();
|
||||
|
||||
/** changed an attribute value (but does not commit it */
|
||||
bool changeAttributeValue(int fid, int field, QVariant value, bool emitSignal = true);
|
||||
|
||||
/** add an attribute field (but does not commit it)
|
||||
returns the field index or -1 in case of failure */
|
||||
bool addAttribute(QString name, QString type);
|
||||
|
||||
/** delete an attribute field (but does not commit it) */
|
||||
bool deleteAttribute(int attr);
|
||||
|
||||
/** Insert a copy of the given features into the layer (but does not commit it) */
|
||||
bool addFeatures(QList<QgsFeature> features, bool makeSelected = TRUE);
|
||||
|
||||
/** delete a feature from the layer (but does not commit it) */
|
||||
bool deleteFeature(int fid);
|
||||
|
||||
/**
|
||||
Attempts to commit any changes to disk. Returns the result of the attempt.
|
||||
@ -314,10 +333,23 @@ existing rings, 5 no feature found where ring can be inserted*/
|
||||
|
||||
*/
|
||||
bool commitChanges();
|
||||
const QStringList &commitErrors();
|
||||
|
||||
/** Stop editing and discard the edits */
|
||||
bool rollBack();
|
||||
|
||||
/**get edit type*/
|
||||
EditType editType(int idx);
|
||||
|
||||
/**set edit type*/
|
||||
void setEditType(int idx, EditType edit);
|
||||
|
||||
/**access value map*/
|
||||
QMap<QString, QVariant> &valueMap(int idx);
|
||||
|
||||
/**access range */
|
||||
RangeData &range(int idx);
|
||||
|
||||
public slots:
|
||||
|
||||
/** Select feature by its ID, optionally emit signal selectionChanged() */
|
||||
@ -341,6 +373,15 @@ signals:
|
||||
/** This signal is emitted when modifications has been done on layer */
|
||||
void wasModified(bool onlyGeometry);
|
||||
|
||||
void editingStarted();
|
||||
void editingStopped();
|
||||
void attributeAdded(int idx);
|
||||
void attributeDeleted(int idx);
|
||||
void featureDeleted(int fid);
|
||||
void layerDeleted();
|
||||
|
||||
void attributeValueChanged(int fid, int idx, const QVariant &);
|
||||
|
||||
private: // Private methods
|
||||
|
||||
/** vector layers are not copyable */
|
||||
|
@ -36,9 +36,8 @@
|
||||
#include "qgsproject.h"
|
||||
#include "qgsrasterlayer.h"
|
||||
#include "qgsrasterlayerproperties.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsvectorlayerproperties.h"
|
||||
#include "qgsvectordataprovider.h"
|
||||
#include "qgsattributetabledisplay.h"
|
||||
|
||||
#include <cfloat>
|
||||
#include <iostream>
|
||||
@ -1811,29 +1810,39 @@ void QgsLegend::legendLayerZoomNative()
|
||||
void QgsLegend::legendLayerAttributeTable()
|
||||
{
|
||||
if(!mMapCanvas || mMapCanvas->isDrawing())
|
||||
{
|
||||
return;
|
||||
}
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QgsVectorLayer *vlayer = 0;
|
||||
|
||||
// try whether it's a legend layer
|
||||
QgsLegendLayer* ll = dynamic_cast<QgsLegendLayer*>(currentItem());
|
||||
if (ll)
|
||||
{
|
||||
ll->table();
|
||||
return;
|
||||
vlayer = dynamic_cast<QgsVectorLayer*>(ll->firstMapLayer());
|
||||
}
|
||||
|
||||
// try whether it's a legend layer file
|
||||
QgsLegendLayerFile* llf = dynamic_cast<QgsLegendLayerFile*>(currentItem());
|
||||
if (llf)
|
||||
{
|
||||
llf->table();
|
||||
return;
|
||||
if(!vlayer) {
|
||||
// try whether it's a legend layer file
|
||||
QgsLegendLayerFile* llf = dynamic_cast<QgsLegendLayerFile*>(currentItem());
|
||||
if (llf)
|
||||
{
|
||||
vlayer = dynamic_cast<QgsVectorLayer*>(llf->layer());
|
||||
}
|
||||
}
|
||||
|
||||
// nothing selected
|
||||
QMessageBox::information(this, tr("No Layer Selected"),
|
||||
tr("To open an attribute table, you must select a vector layer in the legend"));
|
||||
if(vlayer)
|
||||
{
|
||||
QgsAttributeTableDisplay::attributeTable( vlayer );
|
||||
}
|
||||
else
|
||||
{
|
||||
// nothing selected
|
||||
QMessageBox::information(this,
|
||||
tr("No Layer Selected"),
|
||||
tr("To open an attribute table, you must select a vector layer in the legend"));
|
||||
}
|
||||
}
|
||||
|
||||
void QgsLegend::readProject(const QDomDocument & doc)
|
||||
|
@ -43,7 +43,7 @@
|
||||
|
||||
|
||||
QgsLegendLayerFile::QgsLegendLayerFile(QTreeWidgetItem * theLegendItem, QString theString, QgsMapLayer* theLayer)
|
||||
: QgsLegendItem(theLegendItem, theString), mLyr(theLayer), mTableDisplay(NULL)
|
||||
: QgsLegendItem(theLegendItem, theString), mLyr(theLayer)
|
||||
{
|
||||
// Set the initial visibility flag for layers
|
||||
// This user option allows the user to turn off inital drawing of
|
||||
@ -69,23 +69,12 @@ QgsLegendLayerFile::QgsLegendLayerFile(QTreeWidgetItem * theLegendItem, QString
|
||||
QgsVectorLayer *isVectLyr = dynamic_cast < QgsVectorLayer * >(currentLayer);
|
||||
if (isVectLyr)
|
||||
{
|
||||
// get notifications of changed selection - used to update attribute table
|
||||
connect(mLyr.layer(), SIGNAL(selectionChanged()), this, SLOT(selectionChanged()));
|
||||
// get notifications of modified layer - used to close table as it's out of sync
|
||||
connect(mLyr.layer(), SIGNAL(wasModified(bool)), this, SLOT(closeTable(bool)));
|
||||
connect(mLyr.layer(), SIGNAL(editingStarted()), this, SLOT(updateLegendItem()));
|
||||
connect(mLyr.layer(), SIGNAL(editingStopped()), this, SLOT(updateLegendItem()));
|
||||
}
|
||||
connect(mLyr.layer(), SIGNAL(layerNameChanged()), this, SLOT(layerNameChanged()));
|
||||
}
|
||||
|
||||
QgsLegendLayerFile::~QgsLegendLayerFile()
|
||||
{
|
||||
if (mTableDisplay)
|
||||
{
|
||||
mTableDisplay->close();
|
||||
delete mTableDisplay;
|
||||
}
|
||||
}
|
||||
|
||||
QgsLegendItem::DRAG_ACTION QgsLegendLayerFile::accept(LEGEND_ITEM_TYPE type)
|
||||
{
|
||||
return NO_ACTION;
|
||||
@ -219,112 +208,16 @@ void QgsLegendLayerFile::showInOverview()
|
||||
legend()->updateOverview();
|
||||
}
|
||||
|
||||
|
||||
void QgsLegendLayerFile::table()
|
||||
{
|
||||
QgsVectorLayer* vlayer = dynamic_cast<QgsVectorLayer*>(mLyr.layer());
|
||||
if (!vlayer)
|
||||
{
|
||||
QMessageBox::information(0, tr("Not a vector layer"),
|
||||
tr("To open an attribute table, you must select a vector layer in the legend"));
|
||||
return;
|
||||
}
|
||||
|
||||
QgsAttributeAction& actions = *vlayer->actions();
|
||||
|
||||
if (mTableDisplay)
|
||||
{
|
||||
|
||||
mTableDisplay->raise();
|
||||
|
||||
// Give the table the most recent copy of the actions for this layer.
|
||||
mTableDisplay->table()->setAttributeActions(actions);
|
||||
}
|
||||
else
|
||||
{
|
||||
// display the attribute table
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
|
||||
// TODO: pointer to QgisApp should be passed instead of NULL
|
||||
// but we don't have pointer to it. [MD]
|
||||
// but be can get it using this ugly hack. [jef]
|
||||
// TODO: do this cleanly
|
||||
QgisApp *app = NULL;
|
||||
|
||||
QList<QWidget *> list = QApplication::topLevelWidgets();
|
||||
|
||||
int i;
|
||||
for(i=0; i<list.size(); i++)
|
||||
if( list[i]->windowTitle().startsWith("Quantum GIS") )
|
||||
{
|
||||
app=reinterpret_cast<QgisApp*>(list[i]);
|
||||
break;
|
||||
}
|
||||
|
||||
mTableDisplay = new QgsAttributeTableDisplay(vlayer, app);
|
||||
try
|
||||
{
|
||||
mTableDisplay->table()->fillTable(vlayer);
|
||||
}
|
||||
catch(std::bad_alloc& ba)
|
||||
{
|
||||
Q_UNUSED(ba);
|
||||
QMessageBox::critical(0, tr("bad_alloc exception"), tr("Filling the attribute table has been stopped because there was no more virtual memory left"));
|
||||
}
|
||||
|
||||
connect(mTableDisplay, SIGNAL(deleted()), this, SLOT(invalidateTableDisplay()));
|
||||
|
||||
mTableDisplay->setTitle(tr("Attribute table - ") + vlayer->name());
|
||||
mTableDisplay->show();
|
||||
|
||||
// Give the table the most recent copy of the actions for this layer.
|
||||
mTableDisplay->table()->setAttributeActions(actions);
|
||||
|
||||
// select rows which should be selected
|
||||
selectionChanged();
|
||||
|
||||
// etablish the necessary connections between the table and the vector layer
|
||||
connect(mTableDisplay->table(), SIGNAL(selected(int, bool)), mLyr.layer(), SLOT(select(int, bool)));
|
||||
connect(mTableDisplay->table(), SIGNAL(selectionRemoved(bool)), mLyr.layer(), SLOT(removeSelection(bool)));
|
||||
connect(mTableDisplay->table(), SIGNAL(repaintRequested()), mLyr.layer(), SLOT(triggerRepaint()));
|
||||
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void QgsLegendLayerFile::invalidateTableDisplay()
|
||||
{
|
||||
// from signal deleted() - table doesn't exist anymore, just erase our pointer
|
||||
mTableDisplay = 0;
|
||||
}
|
||||
|
||||
void QgsLegendLayerFile::selectionChanged()
|
||||
{
|
||||
if (!mTableDisplay)
|
||||
return;
|
||||
|
||||
QgsVectorLayer* vlayer = dynamic_cast<QgsVectorLayer*>(mLyr.layer());
|
||||
const QgsFeatureIds& ids = vlayer->selectedFeaturesIds();
|
||||
mTableDisplay->table()->selectRowsWithId(ids);
|
||||
|
||||
}
|
||||
|
||||
void QgsLegendLayerFile::closeTable(bool onlyGeometryWasChanged)
|
||||
{
|
||||
if (mTableDisplay)
|
||||
{
|
||||
mTableDisplay->close();
|
||||
delete mTableDisplay;
|
||||
mTableDisplay = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void QgsLegendLayerFile::saveAsShapefile()
|
||||
{
|
||||
saveAsShapefileGeneral(FALSE);
|
||||
}
|
||||
|
||||
void QgsLegendLayerFile::table()
|
||||
{
|
||||
QgsAttributeTableDisplay::attributeTable( dynamic_cast<QgsVectorLayer*>(mLyr.layer()) );
|
||||
}
|
||||
|
||||
void QgsLegendLayerFile::saveSelectionAsShapefile()
|
||||
{
|
||||
saveAsShapefileGeneral(TRUE);
|
||||
@ -413,69 +306,6 @@ void QgsLegendLayerFile::saveAsShapefileGeneral(bool saveOnlySelection)
|
||||
}
|
||||
}
|
||||
|
||||
void QgsLegendLayerFile::toggleEditing()
|
||||
{
|
||||
QgsVectorLayer* vlayer = dynamic_cast<QgsVectorLayer*>(mLyr.layer());
|
||||
if (!vlayer)
|
||||
return;
|
||||
|
||||
if (!vlayer->isEditable())
|
||||
{
|
||||
vlayer->startEditing();
|
||||
if(!(vlayer->getDataProvider()->capabilities() & QgsVectorDataProvider::AddFeatures))
|
||||
{
|
||||
QMessageBox::information(0,tr("Start editing failed"),
|
||||
tr("Provider cannot be opened for editing"));
|
||||
}
|
||||
else
|
||||
{
|
||||
vlayer->triggerRepaint();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(vlayer->isModified())
|
||||
{
|
||||
|
||||
// commit or roll back?
|
||||
QMessageBox::StandardButton commit = QMessageBox::information(0,tr("Stop editing"), tr("Do you want to save the changes?"), QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
|
||||
|
||||
if(commit==QMessageBox::Save)
|
||||
{
|
||||
if(!vlayer->commitChanges())
|
||||
{
|
||||
QMessageBox::information(0,tr("Error"),tr("Could not commit changes"));
|
||||
|
||||
// Leave the in-memory editing state alone,
|
||||
// to give the user a chance to enter different values
|
||||
// and try the commit again later
|
||||
}
|
||||
}
|
||||
else if(commit==QMessageBox::Discard)
|
||||
{
|
||||
if(!vlayer->rollBack())
|
||||
{
|
||||
QMessageBox::information(0,tr("Error"),
|
||||
tr("Problems during roll back"));
|
||||
}
|
||||
}
|
||||
else //cancel
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
else //layer not modified
|
||||
{
|
||||
vlayer->rollBack();
|
||||
}
|
||||
vlayer->triggerRepaint();
|
||||
|
||||
}
|
||||
|
||||
updateLegendItem();
|
||||
|
||||
}
|
||||
|
||||
bool QgsLegendLayerFile::isEditing()
|
||||
{
|
||||
QgsVectorLayer* vlayer = dynamic_cast<QgsVectorLayer*>(mLyr.layer());
|
||||
@ -491,7 +321,6 @@ void QgsLegendLayerFile::layerNameChanged()
|
||||
legend()->setName(this, name);
|
||||
}
|
||||
|
||||
|
||||
void QgsLegendLayerFile::addToPopupMenu(QMenu& theMenu, QAction* toggleEditingAction)
|
||||
{
|
||||
QgsMapLayer* lyr = layer();
|
||||
@ -526,9 +355,9 @@ void QgsLegendLayerFile::addToPopupMenu(QMenu& theMenu, QAction* toggleEditingAc
|
||||
||(cap & QgsVectorDataProvider::DeleteFeatures))
|
||||
{
|
||||
if(toggleEditingAction)
|
||||
{
|
||||
theMenu.addAction(toggleEditingAction);
|
||||
}
|
||||
{
|
||||
theMenu.addAction(toggleEditingAction);
|
||||
}
|
||||
}
|
||||
|
||||
// save as shapefile
|
||||
|
@ -1,6 +1,6 @@
|
||||
/***************************************************************************
|
||||
* Copyright (C) 2005 by Tim Sutton *
|
||||
* aps02ts@macbuntu *
|
||||
* Copyright (C) 2005 by Tim Sutton *
|
||||
* aps02ts@macbuntu *
|
||||
* *
|
||||
* 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 *
|
||||
@ -26,7 +26,6 @@
|
||||
#include "qgsmapcanvas.h"
|
||||
|
||||
class QgsMapLayer;
|
||||
class QgsAttributeTableDisplay;
|
||||
|
||||
/**
|
||||
@author Tim Sutton
|
||||
@ -37,7 +36,7 @@ class QgsLegendLayerFile : public QgsLegendItem
|
||||
|
||||
public:
|
||||
QgsLegendLayerFile(QTreeWidgetItem * theLegendItem, QString theString, QgsMapLayer* theLayer);
|
||||
~QgsLegendLayerFile();
|
||||
|
||||
bool isLeafNode() {return true;}
|
||||
DRAG_ACTION accept(LEGEND_ITEM_TYPE type);
|
||||
QgsLegendItem::DRAG_ACTION accept(const QgsLegendItem* li) const;
|
||||
@ -47,16 +46,12 @@ public:
|
||||
|
||||
QPixmap getOriginalPixmap() const;
|
||||
|
||||
/** updates item to the current state of the layer */
|
||||
void updateLegendItem();
|
||||
|
||||
void setIconAppearance(bool inOverview, bool editable);
|
||||
|
||||
/**Returns a label for a layer. Is static such that
|
||||
the name can be passed to the constructor of QgsLegendLayerFile*/
|
||||
static QString nameFromLayer(QgsMapLayer* layer);
|
||||
|
||||
|
||||
void setVisible(bool visible = TRUE);
|
||||
bool isVisible();
|
||||
|
||||
@ -67,28 +62,18 @@ public:
|
||||
void addToPopupMenu(QMenu& theMenu, QAction* toggleEditingAction);
|
||||
|
||||
public slots:
|
||||
/** updates item to the current state of the layer */
|
||||
void updateLegendItem();
|
||||
|
||||
/**Open attribute table*/
|
||||
void table();
|
||||
|
||||
/**Connected to deleted() signal of attribute table*/
|
||||
void invalidateTableDisplay();
|
||||
|
||||
/**Connected to layer's selectionChanged() */
|
||||
void selectionChanged();
|
||||
|
||||
/**Connected to layer's wasModified() */
|
||||
void closeTable(bool onlyGeometryWasChanged);
|
||||
|
||||
/**Save as shapefile*/
|
||||
void saveAsShapefile();
|
||||
|
||||
/**Save selection as shapefile*/
|
||||
void saveSelectionAsShapefile();
|
||||
|
||||
/**Toggle editing for layer*/
|
||||
void toggleEditing();
|
||||
|
||||
/**Return editing status for layer*/
|
||||
bool isEditing();
|
||||
|
||||
@ -97,7 +82,7 @@ public:
|
||||
|
||||
/**Layer name has changed - set it also in legend*/
|
||||
void layerNameChanged();
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
/**Save as shapefile (called from saveAsShapefile and saveSelectionAsShapefile)*/
|
||||
@ -105,10 +90,6 @@ public:
|
||||
|
||||
/** layer identified by its layer id */
|
||||
QgsMapCanvasLayer mLyr;
|
||||
|
||||
/** Pointer to the table display object if there is one, otherwise NULL */
|
||||
QgsAttributeTableDisplay* mTableDisplay;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -156,25 +156,20 @@ OSErr openDocumentsAEHandler(const AppleEvent *event, AppleEvent *reply, SRefCon
|
||||
}
|
||||
}
|
||||
|
||||
// Open files now if application has been initialized
|
||||
QWidgetList wl = QApplication::topLevelWidgets();
|
||||
for (QWidgetList::iterator it = wl.begin(); it != wl.end(); ++it)
|
||||
QgisApp *qgis = QgisApp::instance();
|
||||
if(qgis)
|
||||
{
|
||||
QgisApp *qgis = dynamic_cast<QgisApp *>(*it);
|
||||
if (qgis && qgis->objectName() == "QgisApp")
|
||||
if (!myProjectFileName.isEmpty())
|
||||
{
|
||||
if (!myProjectFileName.isEmpty())
|
||||
{
|
||||
qgis->openProject(myProjectFileName);
|
||||
}
|
||||
for (QStringList::Iterator myIterator = myFileList.begin();
|
||||
myIterator != myFileList.end(); ++myIterator )
|
||||
{
|
||||
QString fileName = *myIterator;
|
||||
qgis->openLayer(fileName);
|
||||
}
|
||||
break;
|
||||
qgis->openProject(myProjectFileName);
|
||||
}
|
||||
for (QStringList::Iterator myIterator = myFileList.begin();
|
||||
myIterator != myFileList.end(); ++myIterator )
|
||||
{
|
||||
QString fileName = *myIterator;
|
||||
qgis->openLayer(fileName);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return noErr;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -163,6 +163,9 @@ class QgisApp : public QMainWindow
|
||||
* (as documented in Qt documentation.
|
||||
*/
|
||||
void setupProxy();
|
||||
|
||||
static QgisApp *instance() { return smInstance; }
|
||||
|
||||
//! Helper to get a theme icon. It will fall back to the
|
||||
//default theme if the active theme does not have the required
|
||||
//icon.
|
||||
@ -320,6 +323,7 @@ public slots:
|
||||
void refreshMapCanvas();
|
||||
//! returns pointer to map legend
|
||||
QgsLegend *legend() { return mMapLegend; }
|
||||
|
||||
//! starts/stops editing mode of the current layer
|
||||
void toggleEditing();
|
||||
|
||||
@ -330,7 +334,6 @@ public slots:
|
||||
Is called from the legend when the current legend item has changed*/
|
||||
void activateDeactivateLayerRelatedActions(QgsMapLayer* layer);
|
||||
|
||||
|
||||
public slots:
|
||||
/** Add a dock widget to the main window. Overloaded from QMainWindow.
|
||||
* After adding the dock widget to the ui (by delegating to the QMainWindow
|
||||
@ -368,9 +371,13 @@ public slots:
|
||||
void measure();
|
||||
//! Measure area
|
||||
void measureArea();
|
||||
|
||||
//! show the attribute table for the currently selected layer
|
||||
void attributeTable();
|
||||
|
||||
|
||||
//! starts/stops editing mode of a layer
|
||||
void toggleEditing(QgsMapLayer *layer);
|
||||
|
||||
//! show python console
|
||||
void showPythonDialog();
|
||||
|
||||
@ -644,8 +651,6 @@ class Tools
|
||||
QString mStartupPath;
|
||||
//! full path name of the current map file (if it has been saved or loaded)
|
||||
QString mFullPathName;
|
||||
//! A dock to show the attribute table (user optional)
|
||||
QPointer<QDockWidget> mpTableDockWidget;
|
||||
|
||||
//! interface to QgisApp for plugins
|
||||
QgisAppInterface *mQgisInterface;
|
||||
@ -697,6 +702,8 @@ class Tools
|
||||
bool mFullScreenMode;
|
||||
QgsPythonDialog* mPythonConsole;
|
||||
QgsPythonUtils* mPythonUtils;
|
||||
|
||||
static QgisApp *smInstance;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -21,34 +21,34 @@
|
||||
QgsAddAttrDialog::QgsAddAttrDialog(QgsVectorDataProvider* provider, QWidget *parent, Qt::WFlags fl)
|
||||
: QDialog(parent, fl), mDataProvider(provider)
|
||||
{
|
||||
setupUi(this);
|
||||
setupUi(this);
|
||||
|
||||
//fill data types into the combo box
|
||||
const QSet<QString>& typelist=mDataProvider->supportedNativeTypes();
|
||||
//fill data types into the combo box
|
||||
const QgsNativeTypeMap &typelist=mDataProvider->supportedNativeTypes();
|
||||
|
||||
for(QSet<QString>::const_iterator it = typelist.constBegin(); it != typelist.constEnd(); ++it)
|
||||
{
|
||||
mTypeBox->addItem(*it);
|
||||
}
|
||||
for(QgsNativeTypeMap::const_iterator it = typelist.constBegin(); it != typelist.constEnd(); ++it)
|
||||
{
|
||||
mTypeBox->addItem(it.key());
|
||||
}
|
||||
}
|
||||
|
||||
QgsAddAttrDialog::QgsAddAttrDialog(const std::list<QString>& typelist, QWidget *parent, Qt::WFlags fl)
|
||||
: QDialog(parent, fl), mDataProvider(0)
|
||||
{
|
||||
setupUi(this);
|
||||
setupUi(this);
|
||||
|
||||
for(std::list<QString>::const_iterator iter=typelist.begin();iter!=typelist.end();++iter)
|
||||
{
|
||||
mTypeBox->addItem(*iter);
|
||||
}
|
||||
for(std::list<QString>::const_iterator iter=typelist.begin();iter!=typelist.end();++iter)
|
||||
{
|
||||
mTypeBox->addItem(*iter);
|
||||
}
|
||||
}
|
||||
|
||||
QString QgsAddAttrDialog::name() const
|
||||
{
|
||||
return mNameEdit->text();
|
||||
return mNameEdit->text();
|
||||
}
|
||||
|
||||
QString QgsAddAttrDialog::type() const
|
||||
{
|
||||
return mTypeBox->currentText();
|
||||
return mTypeBox->currentText();
|
||||
}
|
||||
|
@ -30,8 +30,6 @@ back to QgsVectorLayer.
|
||||
|
||||
class QgsAttributeAction;
|
||||
|
||||
typedef QMap<int, QgsField> QgsFieldMap;
|
||||
|
||||
class QgsAttributeActionDialog: public QWidget, private Ui::QgsAttributeActionDialogBase
|
||||
{
|
||||
Q_OBJECT;
|
||||
|
@ -31,8 +31,11 @@
|
||||
#include <QLabel>
|
||||
#include <QFrame>
|
||||
#include <QScrollArea>
|
||||
#include <QCompleter>
|
||||
#include <QSpinBox>
|
||||
#include <QDoubleSpinBox>
|
||||
|
||||
QgsAttributeDialog::QgsAttributeDialog(QgsVectorLayer *vl, QgsFeature * thepFeature)
|
||||
QgsAttributeDialog::QgsAttributeDialog(QgsVectorLayer *vl, QgsFeature *thepFeature)
|
||||
: QDialog(),
|
||||
mSettingsPath("/Windows/AttributeDialog/"),
|
||||
mpFeature(thepFeature),
|
||||
@ -67,7 +70,7 @@ QgsAttributeDialog::QgsAttributeDialog(QgsVectorLayer *vl, QgsFeature * thepFeat
|
||||
|
||||
|
||||
int classificationField = -1;
|
||||
QStringList values;
|
||||
QMap<QString,QString> classes;
|
||||
|
||||
const QgsUniqueValueRenderer *uvr = dynamic_cast<const QgsUniqueValueRenderer *>( mLayer->renderer() );
|
||||
if( uvr )
|
||||
@ -78,7 +81,13 @@ QgsAttributeDialog::QgsAttributeDialog(QgsVectorLayer *vl, QgsFeature * thepFeat
|
||||
|
||||
for(int i=0; i<symbols.size(); i++)
|
||||
{
|
||||
values.append( symbols[i]->lowerValue() );
|
||||
QString label = symbols[i]->label();
|
||||
QString name = symbols[i]->lowerValue();
|
||||
|
||||
if(label=="")
|
||||
label=name;
|
||||
|
||||
classes.insert(name, label);
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,49 +96,135 @@ QgsAttributeDialog::QgsAttributeDialog(QgsVectorLayer *vl, QgsFeature * thepFeat
|
||||
it != myAttributes.end();
|
||||
++it)
|
||||
{
|
||||
QString myFieldName = theFieldMap[it.key()].name();
|
||||
int myFieldType = theFieldMap[it.key()].type();
|
||||
const QgsField &field = theFieldMap[it.key()];
|
||||
QString myFieldName = field.name();
|
||||
int myFieldType = field.type();
|
||||
QLabel * mypLabel = new QLabel();
|
||||
mypInnerLayout->addWidget(mypLabel,index,0);
|
||||
QVariant myFieldValue = it.value();
|
||||
|
||||
|
||||
QWidget *myWidget;
|
||||
if(classificationField!=it.key())
|
||||
|
||||
QgsVectorLayer::EditType editType = vl->editType( it.key() );
|
||||
|
||||
switch( editType )
|
||||
{
|
||||
QLineEdit *le = new QLineEdit();
|
||||
|
||||
//the provider may have provided a default value so use it
|
||||
le->setText(myFieldValue.toString());
|
||||
|
||||
if( myFieldType==QVariant::Int )
|
||||
case QgsVectorLayer::Range:
|
||||
{
|
||||
le->setValidator( new QIntValidator(le) );
|
||||
if( myFieldType==QVariant::Int )
|
||||
{
|
||||
int min = vl->range( it.key() ).mMin.toInt();
|
||||
int max = vl->range( it.key() ).mMax.toInt();
|
||||
int step = vl->range( it.key() ).mStep.toInt();
|
||||
|
||||
QSpinBox *sb = new QSpinBox();
|
||||
sb->setMinimum(min);
|
||||
sb->setMaximum(max);
|
||||
sb->setSingleStep(step);
|
||||
sb->setValue( it.value().toInt() );
|
||||
|
||||
myWidget = sb;
|
||||
break;
|
||||
} else if( myFieldType==QVariant::Double ) {
|
||||
double min = vl->range( it.key() ).mMin.toDouble();
|
||||
double max = vl->range( it.key() ).mMax.toDouble();
|
||||
double step = vl->range( it.key() ).mStep.toDouble();
|
||||
QDoubleSpinBox *dsb = new QDoubleSpinBox();
|
||||
|
||||
dsb->setMinimum(min);
|
||||
dsb->setMaximum(max);
|
||||
dsb->setSingleStep(step);
|
||||
dsb->setValue( it.value().toDouble() );
|
||||
|
||||
myWidget = dsb;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
else if( myFieldType==QVariant::Double )
|
||||
|
||||
// fall-through
|
||||
|
||||
|
||||
case QgsVectorLayer::LineEdit:
|
||||
case QgsVectorLayer::UniqueValuesEditable:
|
||||
{
|
||||
le->setValidator( new QIntValidator(le) );
|
||||
QLineEdit *le = new QLineEdit( myFieldValue.toString() );
|
||||
|
||||
if( editType == QgsVectorLayer::UniqueValuesEditable )
|
||||
{
|
||||
QStringList values;
|
||||
mLayer->getDataProvider()->getUniqueValues(it.key(), values);
|
||||
|
||||
QCompleter *c = new QCompleter(values);
|
||||
c->setCompletionMode(QCompleter::PopupCompletion);
|
||||
le->setCompleter(c);
|
||||
}
|
||||
|
||||
if( myFieldType==QVariant::Int )
|
||||
{
|
||||
le->setValidator( new QIntValidator(le) );
|
||||
}
|
||||
else if( myFieldType==QVariant::Double )
|
||||
{
|
||||
le->setValidator( new QIntValidator(le) );
|
||||
}
|
||||
|
||||
myWidget = le;
|
||||
}
|
||||
break;
|
||||
|
||||
myWidget = le;
|
||||
}
|
||||
else
|
||||
{
|
||||
QComboBox *cb = new QComboBox();
|
||||
cb->addItems(values);
|
||||
cb->setEditable(true);
|
||||
|
||||
//the provider may have provided a default value so use it
|
||||
cb->setEditText(myFieldValue.toString());
|
||||
|
||||
if( myFieldType==QVariant::Int ) {
|
||||
cb->setValidator( new QIntValidator(cb) );
|
||||
}
|
||||
else if( myFieldType==QVariant::Double )
|
||||
case QgsVectorLayer::UniqueValues:
|
||||
{
|
||||
cb->setValidator( new QIntValidator(cb) );
|
||||
}
|
||||
QStringList values;
|
||||
mLayer->getDataProvider()->getUniqueValues(it.key(), values);
|
||||
|
||||
myWidget = cb;
|
||||
QComboBox *cb = new QComboBox();
|
||||
cb->setEditable(true);
|
||||
cb->addItems(values);
|
||||
|
||||
int idx = cb->findText( myFieldValue.toString() );
|
||||
if( idx>= 0 )
|
||||
cb->setCurrentIndex( idx );
|
||||
|
||||
myWidget = cb;
|
||||
}
|
||||
break;
|
||||
|
||||
case QgsVectorLayer::ValueMap:
|
||||
{
|
||||
const QMap<QString,QVariant> &map = vl->valueMap( it.key() );
|
||||
|
||||
QComboBox *cb = new QComboBox();
|
||||
|
||||
for(QMap<QString,QVariant>::const_iterator it=map.begin(); it!=map.end(); it++)
|
||||
{
|
||||
cb->addItem( it.key(), it.value() );
|
||||
}
|
||||
|
||||
int idx = cb->findData( myFieldValue );
|
||||
if( idx>= 0 )
|
||||
cb->setCurrentIndex( idx );
|
||||
|
||||
myWidget = cb;
|
||||
}
|
||||
break;
|
||||
|
||||
case QgsVectorLayer::Classification:
|
||||
{
|
||||
QComboBox *cb = new QComboBox();
|
||||
for(QMap<QString,QString>::const_iterator it=classes.begin(); it!=classes.end(); it++)
|
||||
{
|
||||
cb->addItem( it.value(), it.key() );
|
||||
}
|
||||
|
||||
int idx = cb->findData( myFieldValue );
|
||||
if( idx>=0 )
|
||||
cb->setCurrentIndex( idx );
|
||||
|
||||
myWidget = cb;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if( myFieldType==QVariant::Int )
|
||||
@ -168,10 +263,9 @@ void QgsAttributeDialog::accept()
|
||||
it != myAttributes.end();
|
||||
++it)
|
||||
{
|
||||
const QgsFieldMap &theFieldMap = mLayer->getDataProvider()->fields();
|
||||
|
||||
//Q_ASSERT(myIndex <= mpWidgets.size());
|
||||
QString myFieldName = theFieldMap[it.key()].name();
|
||||
const QgsField &theField = mLayer->pendingFields()[it.key()];
|
||||
QgsVectorLayer::EditType editType = mLayer->editType( it.key() );
|
||||
QString myFieldName = theField.name();
|
||||
bool myFlag=false;
|
||||
QString myFieldValue;
|
||||
|
||||
@ -184,40 +278,62 @@ void QgsAttributeDialog::accept()
|
||||
QComboBox *cb = dynamic_cast<QComboBox *>(mpWidgets.value(myIndex));
|
||||
if(cb)
|
||||
{
|
||||
myFieldValue = cb->currentText();
|
||||
if( editType==QgsVectorLayer::UniqueValues ||
|
||||
editType==QgsVectorLayer::ValueMap ||
|
||||
editType==QgsVectorLayer::Classification)
|
||||
{
|
||||
myFieldValue = cb->itemData( cb->currentIndex() ).toString();
|
||||
}
|
||||
else
|
||||
{
|
||||
myFieldValue = cb->currentText();
|
||||
}
|
||||
}
|
||||
|
||||
switch( theFieldMap[it.key()].type() )
|
||||
|
||||
QSpinBox *sb = dynamic_cast<QSpinBox *>(mpWidgets.value(myIndex));
|
||||
if(sb)
|
||||
{
|
||||
case QVariant::Int:
|
||||
myFieldValue = QString::number(sb->value());
|
||||
}
|
||||
|
||||
QDoubleSpinBox *dsb = dynamic_cast<QDoubleSpinBox *>(mpWidgets.value(myIndex));
|
||||
if(dsb)
|
||||
{
|
||||
myFieldValue = QString::number(dsb->value());
|
||||
}
|
||||
|
||||
switch( theField.type() )
|
||||
{
|
||||
case QVariant::Int:
|
||||
{
|
||||
int myIntValue = myFieldValue.toInt(&myFlag);
|
||||
if (myFlag && ! myFieldValue.isEmpty())
|
||||
{
|
||||
int myIntValue = myFieldValue.toInt(&myFlag);
|
||||
if (myFlag && ! myFieldValue.isEmpty())
|
||||
{
|
||||
mpFeature->changeAttribute( it.key(), QVariant(myIntValue) );
|
||||
}
|
||||
else
|
||||
{
|
||||
mpFeature->changeAttribute( it.key(), QVariant(QString::null) );
|
||||
}
|
||||
mpFeature->changeAttribute( it.key(), QVariant(myIntValue) );
|
||||
}
|
||||
break;
|
||||
case QVariant::Double:
|
||||
else
|
||||
{
|
||||
double myDblValue = myFieldValue.toDouble(&myFlag);
|
||||
if (myFlag && ! myFieldValue.isEmpty())
|
||||
{
|
||||
mpFeature->changeAttribute( it.key(), QVariant(myDblValue) );
|
||||
}
|
||||
else
|
||||
{
|
||||
mpFeature->changeAttribute( it.key(), QVariant(QString::null) );
|
||||
}
|
||||
mpFeature->changeAttribute( it.key(), QVariant(QString::null) );
|
||||
}
|
||||
break;
|
||||
default: //string
|
||||
mpFeature->changeAttribute(it.key(),QVariant( myFieldValue ) );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case QVariant::Double:
|
||||
{
|
||||
double myDblValue = myFieldValue.toDouble(&myFlag);
|
||||
if (myFlag && ! myFieldValue.isEmpty())
|
||||
{
|
||||
mpFeature->changeAttribute( it.key(), QVariant(myDblValue) );
|
||||
}
|
||||
else
|
||||
{
|
||||
mpFeature->changeAttribute( it.key(), QVariant(QString::null) );
|
||||
}
|
||||
}
|
||||
break;
|
||||
default: //string
|
||||
mpFeature->changeAttribute(it.key(),QVariant( myFieldValue ) );
|
||||
break;
|
||||
}
|
||||
++myIndex;
|
||||
}
|
||||
@ -235,4 +351,3 @@ void QgsAttributeDialog::restoreGeometry()
|
||||
QSettings settings;
|
||||
QDialog::restoreGeometry(settings.value(mSettingsPath+"geometry").toByteArray());
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include <QValidator>
|
||||
|
||||
#include "qgsattributetable.h"
|
||||
#include "qgsfeature.h"
|
||||
#include "qgsfield.h"
|
||||
#include "qgslogger.h"
|
||||
#include "qgsvectordataprovider.h"
|
||||
@ -33,31 +32,44 @@
|
||||
#include <QMenu>
|
||||
|
||||
|
||||
QgsAttributeTableItemDelegate::QgsAttributeTableItemDelegate(const QgsFieldMap & fields, QObject *parent)
|
||||
: QItemDelegate(parent), mFields(fields)
|
||||
{}
|
||||
QgsAttributeTableItemDelegate::QgsAttributeTableItemDelegate(QgsAttributeTable *table, QObject *parent)
|
||||
: mTable(table), QItemDelegate(parent)
|
||||
{
|
||||
}
|
||||
|
||||
QWidget * QgsAttributeTableItemDelegate::createEditor( QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index ) const
|
||||
QWidget *QgsAttributeTableItemDelegate::createEditor(
|
||||
QWidget *parent,
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index ) const
|
||||
{
|
||||
QWidget *editor = QItemDelegate::createEditor(parent, option, index);
|
||||
QLineEdit *le = dynamic_cast<QLineEdit*>(editor);
|
||||
if (le)
|
||||
if (!le)
|
||||
return editor;
|
||||
|
||||
int col = index.column();
|
||||
QTableWidgetItem *twi = mTable->horizontalHeaderItem(col);
|
||||
if(!twi)
|
||||
{
|
||||
int col = index.column();
|
||||
if( mFields[col-1].type()==QVariant::Int )
|
||||
{
|
||||
le->setValidator( new QIntValidator(le) );
|
||||
}
|
||||
else if( mFields[col-1].type()==QVariant::Double )
|
||||
{
|
||||
le->setValidator( new QDoubleValidator(le) );
|
||||
}
|
||||
QgsDebugMsg( QString("horizontalHeaderItem %1 not found").arg(col) );
|
||||
return editor;
|
||||
}
|
||||
|
||||
int type = twi->data(QgsAttributeTable::AttributeType).toInt();
|
||||
if( type==QVariant::Int )
|
||||
{
|
||||
le->setValidator( new QIntValidator(le) );
|
||||
}
|
||||
else if( type==QVariant::Double )
|
||||
{
|
||||
le->setValidator( new QDoubleValidator(le) );
|
||||
}
|
||||
|
||||
return editor;
|
||||
}
|
||||
|
||||
|
||||
QgsAttributeTable::QgsAttributeTable(QWidget * parent):
|
||||
QgsAttributeTable::QgsAttributeTable(QWidget * parent) :
|
||||
QTableWidget(parent),
|
||||
lockKeyPressed(false),
|
||||
mEditable(false),
|
||||
@ -69,14 +81,12 @@ QgsAttributeTable::QgsAttributeTable(QWidget * parent):
|
||||
f.setFamily("Helvetica");
|
||||
f.setPointSize(9);
|
||||
setFont(f);
|
||||
mDelegate = new QgsAttributeTableItemDelegate(mFields, this);
|
||||
mDelegate = new QgsAttributeTableItemDelegate(this);
|
||||
setItemDelegate(mDelegate);
|
||||
setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
connect(this, SIGNAL(itemSelectionChanged()), this, SLOT(handleChangedSelections()));
|
||||
connect(this, SIGNAL(cellChanged(int, int)), this, SLOT(storeChangedValue(int,int)));
|
||||
connect(horizontalHeader(), SIGNAL(sectionClicked(int)), this, SLOT(columnClicked(int)));
|
||||
connect(verticalHeader(), SIGNAL(sectionClicked(int)), this, SLOT(rowClicked(int)));
|
||||
setReadOnly(true);
|
||||
setFocus();
|
||||
}
|
||||
|
||||
@ -90,14 +100,17 @@ void QgsAttributeTable::setReadOnly(bool b)
|
||||
{
|
||||
setEditTriggers(b ? QAbstractItemView::NoEditTriggers :
|
||||
QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed);
|
||||
if(!b) {
|
||||
setColumnReadOnly(0, true);
|
||||
}
|
||||
}
|
||||
|
||||
void QgsAttributeTable::setColumnReadOnly(int col, bool ro)
|
||||
{
|
||||
for (int i = 0; i < rowCount(); ++i)
|
||||
{
|
||||
QTableWidgetItem *item = this->item(i, col);
|
||||
item->setFlags(ro ? item->flags() & ~Qt::ItemIsEditable : item->flags() | Qt::ItemIsEditable);
|
||||
QTableWidgetItem *twi = item(i, col);
|
||||
twi->setFlags(ro ? twi->flags() & ~Qt::ItemIsEditable : twi->flags() | Qt::ItemIsEditable);
|
||||
}
|
||||
}
|
||||
|
||||
@ -173,16 +186,16 @@ void QgsAttributeTable::keyReleaseEvent(QKeyEvent * ev)
|
||||
|
||||
void QgsAttributeTable::handleChangedSelections()
|
||||
{
|
||||
emit selectionRemoved(false);
|
||||
emit selectionRemoved(false);
|
||||
|
||||
QList<QTableWidgetSelectionRange> selectedItemRanges = selectedRanges();
|
||||
QList<QTableWidgetSelectionRange>::const_iterator range_it = selectedItemRanges.constBegin();
|
||||
for (; range_it != selectedItemRanges.constEnd(); ++range_it)
|
||||
{
|
||||
for (int index = range_it->topRow(); index <= range_it->bottomRow(); index++)
|
||||
{
|
||||
emit selected(item(index, 0)->text().toInt(), false);
|
||||
}
|
||||
{
|
||||
emit selected(item(index, 0)->text().toInt(), false);
|
||||
}
|
||||
}
|
||||
|
||||
//don't send the signal repaintRequested() from here
|
||||
@ -203,19 +216,8 @@ void QgsAttributeTable::selectRowWithId(int id)
|
||||
|
||||
void QgsAttributeTable::sortColumn(int col, bool ascending)
|
||||
{
|
||||
//if the first entry contains a letter, sort alphanumerically, otherwise numerically
|
||||
QString firstentry = item(0, col)->text();
|
||||
bool containsletter = false;
|
||||
for (int i = 0; i < firstentry.length(); i++)
|
||||
{
|
||||
if (firstentry[i].isLetter())
|
||||
{
|
||||
containsletter = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
qsort(0, rowCount() - 1, col, ascending, containsletter);
|
||||
int type = horizontalHeaderItem(col)->data(QgsAttributeTable::AttributeType).toInt();
|
||||
qsort(0, rowCount() - 1, col, ascending, type!=QVariant::Int && type==QVariant::Double);
|
||||
}
|
||||
|
||||
|
||||
@ -302,7 +304,8 @@ void QgsAttributeTable::qsort(int lower, int upper, int col, bool ascending, boo
|
||||
j = upper;
|
||||
for (;;)
|
||||
{
|
||||
while (compareItems(item(++i, col)->text(), v, ascending, alphanumeric) == -1);
|
||||
while (compareItems(item(++i, col)->text(), v, ascending, alphanumeric) == -1)
|
||||
;
|
||||
while (compareItems(item(--j, col)->text(), v, ascending, alphanumeric) == 1 && j > 0); //make sure that j does not get negative
|
||||
if (i >= j)
|
||||
{
|
||||
@ -381,45 +384,6 @@ void QgsAttributeTable::popupItemSelected(QAction* menuAction)
|
||||
mActions.doAction(id, mActionValues, mClickedOnValue);
|
||||
}
|
||||
|
||||
bool QgsAttributeTable::addAttribute(const QString& name, const QString& type)
|
||||
{
|
||||
//first test if an attribute with the same name is already in the table
|
||||
for(int i=0;i<columnCount();++i)
|
||||
{
|
||||
if(horizontalHeaderItem(i)->text()==name)
|
||||
{
|
||||
//name conflict
|
||||
return false;
|
||||
}
|
||||
}
|
||||
mAddedAttributes.insert(name,type);
|
||||
|
||||
QgsDebugMsg("inserting attribute " + name + " of type " + type + ", numCols: " + QString::number(columnCount()) );
|
||||
//add a new column at the end of the table
|
||||
insertColumn(columnCount());
|
||||
setHorizontalHeaderItem(columnCount()-1, new QTableWidgetItem(name));
|
||||
mEdited=true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void QgsAttributeTable::deleteAttribute(const QString& name)
|
||||
{
|
||||
//check, if there is already an attribute with this name in mAddedAttributes
|
||||
QgsNewAttributesMap::iterator iter = mAddedAttributes.find(name);
|
||||
if(iter!=mAddedAttributes.end())
|
||||
{
|
||||
mAddedAttributes.erase(iter);
|
||||
removeAttrColumn(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
mDeletedAttributes.insert(name);
|
||||
removeAttrColumn(name);
|
||||
}
|
||||
mEdited=true;
|
||||
}
|
||||
|
||||
|
||||
/* Deprecated: See QgisApp::editCopy() instead */
|
||||
void QgsAttributeTable::copySelectedRows()
|
||||
{
|
||||
@ -463,157 +427,60 @@ void QgsAttributeTable::copySelectedRows()
|
||||
clipboard->setText(toClipboard, QClipboard::Clipboard);
|
||||
}
|
||||
|
||||
bool QgsAttributeTable::commitChanges(QgsVectorLayer* layer)
|
||||
void QgsAttributeTable::fillTable(QgsVectorLayer *layer)
|
||||
{
|
||||
bool isSuccessful = false;
|
||||
int row = 0;
|
||||
|
||||
if(layer)
|
||||
const QgsFieldMap &fields = layer->pendingFields();
|
||||
|
||||
// set up the column headers
|
||||
setColumnCount(fields.size()+1);
|
||||
|
||||
setHorizontalHeaderItem(0, new QTableWidgetItem("id")); //label for the id-column
|
||||
|
||||
int h = 1;
|
||||
for (QgsFieldMap::const_iterator fldIt = fields.begin(); fldIt!=fields.end(); fldIt++, h++)
|
||||
{
|
||||
//convert strings of deleted attributes to ids
|
||||
QgsDebugMsg( QString("%1: field %2: %3 | %4")
|
||||
.arg(h).arg(fldIt.key()).arg(fldIt->name()).arg( QVariant::typeToName(fldIt->type()) ) );
|
||||
|
||||
QgsVectorDataProvider* provider = layer->getDataProvider();
|
||||
QTableWidgetItem *twi = new QTableWidgetItem(fldIt->name());
|
||||
twi->setData( AttributeIndex, fldIt.key() );
|
||||
twi->setData( AttributeName, fldIt->name() );
|
||||
twi->setData( AttributeType, fldIt->type() );
|
||||
setHorizontalHeaderItem(h, twi);
|
||||
|
||||
if(provider)
|
||||
{
|
||||
|
||||
QgsAttributeIds deletedIds;
|
||||
QSet<QString>::const_iterator it = mDeletedAttributes.constBegin();
|
||||
|
||||
for(; it != mDeletedAttributes.constEnd(); ++it)
|
||||
{
|
||||
deletedIds.insert(provider->indexFromFieldName(*it));
|
||||
}
|
||||
|
||||
isSuccessful = true;
|
||||
if( !mAddedAttributes.empty() )
|
||||
{
|
||||
// add new attributes beforehand, so attribute changes can be applied
|
||||
isSuccessful = layer->commitAttributeChanges(QgsAttributeIds(), mAddedAttributes, QgsChangedAttributesMap());
|
||||
|
||||
if(isSuccessful)
|
||||
// forget added attributes on successful addition
|
||||
mAddedAttributes.clear();
|
||||
}
|
||||
|
||||
if(isSuccessful)
|
||||
{
|
||||
QgsChangedAttributesMap attributeChanges; //convert mChangedValues to QgsChangedAttributesMap
|
||||
int fieldIndex;
|
||||
|
||||
QMap<int, QMap<QString, QString> >::const_iterator att_it = mChangedValues.constBegin();
|
||||
for(; att_it != mChangedValues.constEnd(); ++att_it)
|
||||
{
|
||||
QgsAttributeMap newAttMap;
|
||||
QMap<QString, QString>::const_iterator record_it = att_it->constBegin();
|
||||
for(; record_it != att_it->constEnd(); ++record_it)
|
||||
{
|
||||
fieldIndex = provider->indexFromFieldName(record_it.key());
|
||||
if(fieldIndex != -1)
|
||||
{
|
||||
if( record_it.value()=="NULL" ||
|
||||
( record_it.value().isEmpty() &&
|
||||
(provider->fields()[fieldIndex].type()==QVariant::Int ||
|
||||
provider->fields()[fieldIndex].type()==QVariant::Double) ) )
|
||||
newAttMap.insert(fieldIndex, QVariant(QString::null) );
|
||||
else
|
||||
newAttMap.insert(fieldIndex, record_it.value());
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsDebugMsg("Changed attribute " + record_it.key() + " not found");
|
||||
}
|
||||
}
|
||||
attributeChanges.insert(att_it.key(), newAttMap);
|
||||
}
|
||||
|
||||
isSuccessful = layer->commitAttributeChanges(deletedIds,
|
||||
QgsNewAttributesMap(),
|
||||
attributeChanges);
|
||||
}
|
||||
}
|
||||
mAttrIdxMap.insert(fldIt.key(), h);
|
||||
}
|
||||
|
||||
if (isSuccessful)
|
||||
QgsFeatureList features;
|
||||
if( layer->selectedFeatureCount()==0 )
|
||||
{
|
||||
mEdited=false;
|
||||
clearEditingStructures();
|
||||
layer->select(layer->pendingAllAttributesList(), QgsRect(), false);
|
||||
|
||||
QgsFeature f;
|
||||
while( layer->getNextFeature(f) )
|
||||
features << f;
|
||||
}
|
||||
else
|
||||
{
|
||||
features = layer->selectedFeatures();
|
||||
}
|
||||
|
||||
return isSuccessful;
|
||||
}
|
||||
|
||||
bool QgsAttributeTable::rollBack(QgsVectorLayer* layer)
|
||||
{
|
||||
if(layer)
|
||||
{
|
||||
fillTable(layer);
|
||||
}
|
||||
mEdited=false;
|
||||
clearEditingStructures();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void QgsAttributeTable::fillTable(QgsVectorLayer* layer)
|
||||
{
|
||||
QgsVectorDataProvider* provider=layer->getDataProvider();
|
||||
if(provider)
|
||||
{
|
||||
QgsFeature fet;
|
||||
int row = 0;
|
||||
|
||||
QgsFeatureList& addedFeatures = layer->addedFeatures();
|
||||
QgsFeatureIds& deletedFeatures = layer->deletedFeatureIds();
|
||||
|
||||
// set up the column headers
|
||||
mFields = provider->fields();
|
||||
int fieldcount=provider->fieldCount();
|
||||
setRowCount( features.size() );
|
||||
|
||||
setRowCount(provider->featureCount() + addedFeatures.size() - deletedFeatures.size());
|
||||
setColumnCount(fieldcount+1);
|
||||
setHorizontalHeaderItem(0, new QTableWidgetItem("id")); //label for the id-column
|
||||
for(int i=0; i<features.size(); i++)
|
||||
putFeatureInTable(i, features[i]);
|
||||
|
||||
int h = 1;
|
||||
QgsFieldMap::const_iterator fldIt;
|
||||
for (fldIt = mFields.begin(); fldIt != mFields.end(); ++fldIt)
|
||||
{
|
||||
QgsDebugMsg("field " + QString::number(fldIt.key()) + ": " + fldIt->name() +
|
||||
" | " + QString(QVariant::typeToName(fldIt->type())) );
|
||||
// Default row height is too tall
|
||||
resizeRowsToContents();
|
||||
|
||||
setHorizontalHeaderItem(h++, new QTableWidgetItem(fldIt->name()));
|
||||
}
|
||||
|
||||
//go through the features and fill the values into the table
|
||||
QgsAttributeList all = provider->allAttributesList();
|
||||
provider->select(all, QgsRect(), false);
|
||||
|
||||
while (provider->getNextFeature(fet))
|
||||
{
|
||||
if (!deletedFeatures.contains(fet.featureId()))
|
||||
{
|
||||
putFeatureInTable(row, fet);
|
||||
row++;
|
||||
}
|
||||
}
|
||||
|
||||
//also consider the not commited features
|
||||
for(QgsFeatureList::iterator it = addedFeatures.begin(); it != addedFeatures.end(); it++)
|
||||
{
|
||||
putFeatureInTable(row, *it);
|
||||
row++;
|
||||
}
|
||||
|
||||
// Default row height is too tall
|
||||
resizeRowsToContents();
|
||||
// Make each column wide enough to show all the contents
|
||||
for (int i = 0; i < columnCount(); ++i)
|
||||
{
|
||||
resizeColumnToContents(i);
|
||||
}
|
||||
}
|
||||
// Make each column wide enough to show all the contents
|
||||
for (int i=0; i<columnCount(); i++)
|
||||
resizeColumnToContents(i);
|
||||
}
|
||||
|
||||
void QgsAttributeTable::putFeatureInTable(int row, QgsFeature& fet)
|
||||
void QgsAttributeTable::putFeatureInTable(int row, const QgsFeature& fet)
|
||||
{
|
||||
// Prevent a crash if a provider doesn't update the feature count properly
|
||||
if(row >= rowCount())
|
||||
@ -623,21 +490,35 @@ void QgsAttributeTable::putFeatureInTable(int row, QgsFeature& fet)
|
||||
|
||||
//id-field
|
||||
int id = fet.featureId();
|
||||
QTableWidgetItem *item = new QTableWidgetItem(QString::number(id));
|
||||
item->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
||||
setItem(row, 0, item);
|
||||
QTableWidgetItem *twi = new QTableWidgetItem(QString::number(id));
|
||||
twi->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
||||
setItem(row, 0, twi);
|
||||
insertFeatureId(id, row); //insert the id into the search tree of qgsattributetable
|
||||
const QgsAttributeMap& attr = fet.attributeMap();
|
||||
QgsAttributeMap::const_iterator it;
|
||||
int h = 1;
|
||||
for (it = attr.begin(); it != attr.end(); ++it)
|
||||
{
|
||||
QString value;
|
||||
|
||||
const QgsAttributeMap& attr = fet.attributeMap();
|
||||
|
||||
for (QgsAttributeMap::const_iterator it = attr.begin(); it != attr.end(); ++it)
|
||||
{
|
||||
if( !mAttrIdxMap.contains( it.key() ) )
|
||||
continue;
|
||||
|
||||
int h = mAttrIdxMap[ it.key() ];
|
||||
|
||||
twi = horizontalHeaderItem(h);
|
||||
if(!twi)
|
||||
{
|
||||
QgsDebugMsg("header item not found.");
|
||||
continue;
|
||||
}
|
||||
|
||||
int type = twi->data(AttributeType).toInt();
|
||||
bool isNum = (type == QVariant::Double || type == QVariant::Int);
|
||||
|
||||
QString value;
|
||||
// get the field values
|
||||
if( it->isNull() )
|
||||
{
|
||||
if( mFields[h-1].type()==QVariant::Int || mFields[h-1].type()==QVariant::Double )
|
||||
if( isNum )
|
||||
value="";
|
||||
else
|
||||
value="NULL";
|
||||
@ -645,58 +526,10 @@ void QgsAttributeTable::putFeatureInTable(int row, QgsFeature& fet)
|
||||
value = it->toString();
|
||||
}
|
||||
|
||||
bool isNum;
|
||||
value.toFloat(&isNum);
|
||||
item = new QTableWidgetItem(value);
|
||||
if (isNum) item->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
||||
setItem(row, h++, item);
|
||||
}
|
||||
}
|
||||
|
||||
void QgsAttributeTable::storeChangedValue(int row, int column)
|
||||
{
|
||||
//id column is not editable
|
||||
if(column>0)
|
||||
{
|
||||
//find feature id
|
||||
int id=item(row,0)->text().toInt();
|
||||
QString field = horizontalHeaderItem(column)->text();
|
||||
|
||||
if(id>=0)
|
||||
{
|
||||
// add empty map for feature if doesn't exist
|
||||
if (!mChangedValues.contains(id))
|
||||
{
|
||||
mChangedValues.insert(id, QMap<QString, QString>());
|
||||
}
|
||||
|
||||
mChangedValues[id].insert(field, item(row,column)->text());
|
||||
mEdited=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// added feature attribute changed
|
||||
emit featureAttributeChanged(row,column);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsAttributeTable::clearEditingStructures()
|
||||
{
|
||||
mDeletedAttributes.clear();
|
||||
mAddedAttributes.clear();
|
||||
mChangedValues.clear();
|
||||
}
|
||||
|
||||
void QgsAttributeTable::removeAttrColumn(const QString& name)
|
||||
{
|
||||
for(int i=0;i<columnCount();++i)
|
||||
{
|
||||
if(horizontalHeaderItem(i)->text()==name)
|
||||
{
|
||||
removeColumn(i);
|
||||
break;
|
||||
}
|
||||
twi = new QTableWidgetItem(value);
|
||||
if (isNum)
|
||||
twi->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
||||
setItem(row, h, twi);
|
||||
}
|
||||
}
|
||||
|
||||
@ -852,3 +685,54 @@ bool QgsAttributeTable::checkSelectionChanges()
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void QgsAttributeTable::attributeValueChanged(int fid, int idx, const QVariant &value)
|
||||
{
|
||||
if( !rowIdMap.contains(fid) )
|
||||
return;
|
||||
|
||||
if( !mAttrIdxMap.contains(idx) )
|
||||
return;
|
||||
|
||||
item( rowIdMap[fid], mAttrIdxMap[idx] )->setText( value.toString() );
|
||||
}
|
||||
|
||||
void QgsAttributeTable::featureDeleted(int fid)
|
||||
{
|
||||
if( !rowIdMap.contains(fid) )
|
||||
return;
|
||||
|
||||
int row = rowIdMap[fid];
|
||||
|
||||
removeRow(row);
|
||||
|
||||
for(QMap<int,int>::iterator it=rowIdMap.begin(); it!=rowIdMap.end(); it++)
|
||||
if( it.value() > row )
|
||||
rowIdMap[ it.key() ]--;
|
||||
}
|
||||
|
||||
void QgsAttributeTable::addAttribute(int attr, const QgsField &fld)
|
||||
{
|
||||
QTableWidgetItem *twi = new QTableWidgetItem( fld.name() );
|
||||
twi->setData( AttributeIndex, attr );
|
||||
twi->setData( AttributeName, fld.name() );
|
||||
twi->setData( AttributeType, fld.type() );
|
||||
|
||||
insertColumn( columnCount() );
|
||||
setHorizontalHeaderItem(columnCount()-1, twi);
|
||||
|
||||
mAttrIdxMap.insert(attr, columnCount()-1);
|
||||
}
|
||||
|
||||
void QgsAttributeTable::deleteAttribute(int attr)
|
||||
{
|
||||
int column = mAttrIdxMap[attr];
|
||||
|
||||
removeColumn( column );
|
||||
mAttrIdxMap.remove(attr);
|
||||
for(QMap<int, int>::iterator it=mAttrIdxMap.begin(); it!=mAttrIdxMap.end(); it++)
|
||||
{
|
||||
if( it.value()>column )
|
||||
mAttrIdxMap[ it.key() ]--;
|
||||
}
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
|
||||
#include "qgsattributeaction.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsfield.h"
|
||||
|
||||
#include <QItemDelegate>
|
||||
#include <QTableWidget>
|
||||
@ -31,18 +32,21 @@
|
||||
*@author Gary E.Sherman
|
||||
*/
|
||||
|
||||
class QgsAttributeTable;
|
||||
|
||||
class QgsAttributeTableItemDelegate: public QItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QgsAttributeTableItemDelegate(const QgsFieldMap & fields, QObject * parent = 0);
|
||||
QgsAttributeTableItemDelegate(QgsAttributeTable *table, QObject * parent = 0);
|
||||
QWidget * createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index ) const;
|
||||
|
||||
private:
|
||||
const QgsFieldMap & mFields;
|
||||
QgsAttributeTable *mTable;
|
||||
};
|
||||
|
||||
class QgsAttributeTable:public QTableWidget
|
||||
class QgsAttributeTable : public QTableWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@ -50,9 +54,17 @@ class QgsAttributeTable:public QTableWidget
|
||||
QgsAttributeTable(QWidget * parent = 0);
|
||||
~QgsAttributeTable();
|
||||
|
||||
enum {
|
||||
AttributeIndex = Qt::UserRole,
|
||||
AttributeName = Qt::UserRole+1,
|
||||
AttributeType = Qt::UserRole+2,
|
||||
};
|
||||
|
||||
void setReadOnly(bool b);
|
||||
void setColumnReadOnly(int col, bool ro);
|
||||
/**Inserts the feature with the specified id into rowIdMap. This function has to be called (e.g. from QgsShapeFileLayer) when a row is inserted into the table*/
|
||||
|
||||
/* Inserts the feature with the specified id into rowIdMap. This function has to be called
|
||||
(e.g. from QgsShapeFileLayer) when a row is inserted into the table */
|
||||
void insertFeatureId(int id, int row);
|
||||
/**Selects the row which belongs to the feature with the specified id*/
|
||||
void selectRowWithId(int id);
|
||||
@ -66,38 +78,11 @@ class QgsAttributeTable:public QTableWidget
|
||||
bool edited() const {return mEdited;}
|
||||
/**Switches editing mode on and off*/
|
||||
void setEditable(bool enabled){mEditable=enabled;}
|
||||
/**Adds an attribute to the table (but does not commit it yet)
|
||||
@param name attribute name
|
||||
@param type attribute type
|
||||
@return false in case of a name conflict, true in case of success*/
|
||||
bool addAttribute(const QString& name, const QString& type);
|
||||
/**Deletes an attribute (but does not commit it)
|
||||
@param name attribute name*/
|
||||
void deleteAttribute(const QString& name);
|
||||
|
||||
/** Copies the selected rows to the clipboard
|
||||
Deprecated: See QgisApp::editCopy() instead */
|
||||
void copySelectedRows();
|
||||
|
||||
/**
|
||||
Attempts to commit any changes to disk. Returns the result of the attempt.
|
||||
If a commit fails, the in-memory changes are left alone.
|
||||
|
||||
This allows editing to continue if the commit failed on e.g. a
|
||||
disallowed value in a Postgres database - the user can re-edit and try
|
||||
again.
|
||||
|
||||
Delegates to QgsVectorLayer to decide, which changes
|
||||
belong to not commited features or to commited ones.
|
||||
|
||||
*/
|
||||
bool commitChanges(QgsVectorLayer* layer);
|
||||
|
||||
/**Discard all changes and restore
|
||||
the state before editing was started*/
|
||||
bool rollBack(QgsVectorLayer* layer);
|
||||
/**Fills the contents of a provider into this table*/
|
||||
void fillTable(QgsVectorLayer* layer);
|
||||
/**Swaps the selected rows such that the selected ones are on the top of the table*/
|
||||
void bringSelectedToTop();
|
||||
/** Selects rows with chosen feature IDs */
|
||||
@ -107,38 +92,42 @@ class QgsAttributeTable:public QTableWidget
|
||||
/** Shows all rows */
|
||||
void showAllRows();
|
||||
|
||||
/**Fills the contents of a provider into this table*/
|
||||
void fillTable(QgsVectorLayer *layer);
|
||||
void addAttribute(int idx, const QgsField &fld);
|
||||
void deleteAttribute(int idx);
|
||||
|
||||
public slots:
|
||||
void columnClicked(int col);
|
||||
void rowClicked(int row);
|
||||
|
||||
// Called when the user chooses an item on the popup menu
|
||||
void popupItemSelected(QAction * menuAction);
|
||||
|
||||
void attributeValueChanged(int fid, int idx, const QVariant &value);
|
||||
void featureDeleted(int fid);
|
||||
|
||||
protected slots:
|
||||
void handleChangedSelections();
|
||||
/**Writes changed values to 'mChangedValues'*/
|
||||
void storeChangedValue(int row, int column);
|
||||
|
||||
protected:
|
||||
/**Flag telling if the ctrl-button or the shift-button is pressed*/
|
||||
bool lockKeyPressed;
|
||||
/**Search tree to find a row corresponding to a feature id*/
|
||||
QMap<int,int> rowIdMap;
|
||||
/**Map attribute index to columns*/
|
||||
QMap<int,int> mAttrIdxMap;
|
||||
bool mEditable;
|
||||
/**True if table has been edited and contains uncommited changes*/
|
||||
bool mEdited;
|
||||
/**Map containing the added attributes. The key is the attribute name
|
||||
and the value the attribute type*/
|
||||
QgsNewAttributesMap mAddedAttributes;
|
||||
/**Set containing the attribute names of deleted attributes*/
|
||||
QSet<QString> mDeletedAttributes;
|
||||
/**Nested map containing the changed attribute values. The int is the feature id,
|
||||
the first QString the attribute name and the second QString the new value*/
|
||||
QMap<int, QMap<QString, QString> > mChangedValues;
|
||||
|
||||
/**Stors the numbers of the last selected rows. This is used to check for selection changes before emit repaintRequested()*/
|
||||
std::set<int> mLastSelectedRows;
|
||||
|
||||
/**Compares the content of two cells either alphanumeric or numeric. If 'ascending' is true, -1 means s1 is less, 0 equal, 1 greater. If 'ascending' is false, -1 means s1 is more, 0 equal, 1 greater. This method is used mainly to sort a column*/
|
||||
/* Compares the content of two cells either alphanumeric or numeric.
|
||||
If 'ascending' is true, -1 means s1 is less, 0 equal, 1 greater.
|
||||
If 'ascending' is false, -1 means s1 is more, 0 equal, 1 greater.
|
||||
This method is used mainly to sort a column*/
|
||||
int compareItems(QString s1, QString s2, bool ascending, bool alphanumeric);
|
||||
void keyPressEvent(QKeyEvent* ev);
|
||||
void keyReleaseEvent(QKeyEvent* ev);
|
||||
@ -146,16 +135,15 @@ class QgsAttributeTable:public QTableWidget
|
||||
void qsort(int lower, int upper, int col, bool ascending, bool alphanumeric);
|
||||
/**Called when the user requests a popup menu*/
|
||||
void contextMenuEvent(QContextMenuEvent* event);
|
||||
/**Clears mAddedAttributes, mDeletedAttributes and mChangedValues*/
|
||||
void clearEditingStructures();
|
||||
/**Removes the column belonging to an attribute from the table
|
||||
@name attribut name*/
|
||||
void removeAttrColumn(const QString& name);
|
||||
/** puts attributes of feature to the chosen table row */
|
||||
void putFeatureInTable(int row, QgsFeature& fet);
|
||||
void putFeatureInTable(int row, const QgsFeature& fet);
|
||||
void mouseReleaseEvent(QMouseEvent* e);
|
||||
/**This function compares the current selection and the selection of the last repaint. Returns true if there are differences in the selection.
|
||||
Also, mLastSelectedRows is updated*/
|
||||
/**This function compares the current selection and the selection of the last repaint.
|
||||
Returns true if there are differences in the selection.
|
||||
Also, mLastSelectedRows is updated*/
|
||||
bool checkSelectionChanges();
|
||||
|
||||
signals:
|
||||
@ -165,8 +153,6 @@ class QgsAttributeTable:public QTableWidget
|
||||
void selectionRemoved(bool);
|
||||
/**Is emitted when a set of related selection and deselection signals have been emitted*/
|
||||
void repaintRequested();
|
||||
/**Is emitted when a attribute of a added feature is changed*/
|
||||
void featureAttributeChanged(int row, int column);
|
||||
|
||||
private:
|
||||
void swapRows(int row1, int row2);
|
||||
@ -179,10 +165,10 @@ class QgsAttributeTable:public QTableWidget
|
||||
|
||||
QgsAttributeTableItemDelegate *mDelegate;
|
||||
|
||||
QgsFieldMap mFields;
|
||||
|
||||
// Track previous columm for QTableView sortIndicator wrong direction workaround
|
||||
int mPreviousSortIndicatorColumn;
|
||||
|
||||
QgsVectorLayer *mLayer;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -21,8 +21,6 @@
|
||||
|
||||
#include "qgisapp.h"
|
||||
#include "qgsapplication.h"
|
||||
#include "qgsaddattrdialog.h"
|
||||
#include "qgsdelattrdialog.h"
|
||||
#include "qgsfeature.h"
|
||||
#include "qgsfield.h"
|
||||
#include "qgslogger.h"
|
||||
@ -39,249 +37,174 @@
|
||||
#include <QPixmap>
|
||||
#include <QSettings>
|
||||
#include <QToolButton>
|
||||
#include <QDockWidget>
|
||||
|
||||
QgsAttributeTableDisplay::QgsAttributeTableDisplay(QgsVectorLayer* layer, QgisApp * qgisApp)
|
||||
QgsAttributeTableDisplay::QgsAttributeTableDisplay(QgsVectorLayer* layer)
|
||||
: QDialog(0, Qt::Window),
|
||||
mLayer(layer),
|
||||
mQgisApp(qgisApp)
|
||||
mDock(NULL)
|
||||
{
|
||||
setupUi(this);
|
||||
restorePosition();
|
||||
setTheme();
|
||||
|
||||
mToggleEditingButton->setEnabled( layer->getDataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues );
|
||||
mToggleEditingButton->setChecked( layer->isEditable() );
|
||||
|
||||
connect(mRemoveSelectionButton, SIGNAL(clicked()), this, SLOT(removeSelection()));
|
||||
connect(mSelectedToTopButton, SIGNAL(clicked()), this, SLOT(selectedToTop()));
|
||||
connect(mInvertSelectionButton, SIGNAL(clicked()), this, SLOT(invertSelection()));
|
||||
connect(mCopySelectedRowsButton, SIGNAL(clicked()), this, SLOT(copySelectedRowsToClipboard()));
|
||||
connect(mZoomMapToSelectedRowsButton, SIGNAL(clicked()), this, SLOT(zoomMapToSelectedRows()));
|
||||
connect(mAddAttributeButton, SIGNAL(clicked()), this, SLOT(addAttribute()));
|
||||
connect(mDeleteAttributeButton, SIGNAL(clicked()), this, SLOT(deleteAttributes()));
|
||||
connect(mSearchButton, SIGNAL(clicked()), this, SLOT(search()));
|
||||
connect(mSearchShowResults, SIGNAL(activated(int)), this, SLOT(searchShowResultsChanged(int)));
|
||||
connect(btnAdvancedSearch, SIGNAL(clicked()), this, SLOT(advancedSearch()));
|
||||
connect(buttonBox, SIGNAL(helpRequested()), this, SLOT(showHelp()));
|
||||
connect(buttonBox->button(QDialogButtonBox::Close), SIGNAL(clicked()),
|
||||
this, SLOT(close()));
|
||||
connect(tblAttributes, SIGNAL(featureAttributeChanged(int,int)), this, SLOT(changeFeatureAttribute(int,int)));
|
||||
|
||||
//disable those buttons until start editing has been pressed and provider supports it
|
||||
mAddAttributeButton->setEnabled(false);
|
||||
mDeleteAttributeButton->setEnabled(false);
|
||||
connect(buttonBox->button(QDialogButtonBox::Close), SIGNAL(clicked()), this, SLOT(close()));
|
||||
|
||||
int cap=layer->getDataProvider()->capabilities();
|
||||
if((cap&QgsVectorDataProvider::ChangeAttributeValues)
|
||||
||(cap&QgsVectorDataProvider::AddAttributes)
|
||||
||(cap&QgsVectorDataProvider::DeleteAttributes))
|
||||
{
|
||||
btnEdit->setEnabled(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
btnEdit->setEnabled(false);
|
||||
}
|
||||
connect(mToggleEditingButton, SIGNAL(clicked()), this, SLOT(toggleEditing()));
|
||||
connect(this, SIGNAL(editingToggled(QgsMapLayer *)), QgisApp::instance(), SLOT(toggleEditing(QgsMapLayer *)));
|
||||
|
||||
// etablish connection to table
|
||||
connect(tblAttributes, SIGNAL(cellChanged(int, int)), this, SLOT(changeFeatureAttribute(int,int)));
|
||||
|
||||
// etablish connections to layer
|
||||
connect(mLayer, SIGNAL(layerDeleted()), this, SLOT(close()));
|
||||
|
||||
connect(mLayer, SIGNAL(selectionChanged()), this, SLOT(selectionChanged()));
|
||||
|
||||
connect(mLayer, SIGNAL(editingStarted()), this, SLOT(editingToggled()));
|
||||
connect(mLayer, SIGNAL(editingStopped()), this, SLOT(editingToggled()));
|
||||
|
||||
connect(mLayer, SIGNAL(attributeAdded(int)), this, SLOT(attributeAdded(int)));
|
||||
connect(mLayer, SIGNAL(attributeDeleted(int)), this, SLOT(attributeDeleted(int)));
|
||||
|
||||
connect(mLayer, SIGNAL(attributeValueChanged(int,int,const QVariant &)),
|
||||
tblAttributes, SLOT(attributeValueChanged(int,int,const QVariant &)) );
|
||||
|
||||
connect(mLayer, SIGNAL(featureDeleted(int)),
|
||||
tblAttributes, SLOT(featureDeleted(int)));
|
||||
|
||||
// etablish connections between table and vector layer
|
||||
connect(tblAttributes, SIGNAL(selected(int, bool)), mLayer, SLOT(select(int, bool)));
|
||||
connect(tblAttributes, SIGNAL(selectionRemoved(bool)), mLayer, SLOT(removeSelection(bool)));
|
||||
connect(tblAttributes, SIGNAL(repaintRequested()), mLayer, SLOT(triggerRepaint()));
|
||||
|
||||
// fill in mSearchColumns with available columns
|
||||
QgsVectorDataProvider* provider = mLayer->getDataProvider();
|
||||
if (provider)
|
||||
const QgsFieldMap& xfields = mLayer->pendingFields();
|
||||
QgsFieldMap::const_iterator fldIt;
|
||||
for (fldIt = xfields.constBegin(); fldIt != xfields.constEnd(); ++fldIt)
|
||||
{
|
||||
const QgsFieldMap& xfields = provider->fields();
|
||||
QgsFieldMap::const_iterator fldIt;
|
||||
for (fldIt = xfields.constBegin(); fldIt != xfields.constEnd(); ++fldIt)
|
||||
{
|
||||
mSearchColumns->addItem(fldIt->name());
|
||||
}
|
||||
mSearchColumns->addItem(fldIt->name());
|
||||
}
|
||||
|
||||
// TODO: create better labels
|
||||
mSearchShowResults->addItem(tr("select"));
|
||||
mSearchShowResults->addItem(tr("select and bring to top"));
|
||||
mSearchShowResults->addItem(tr("show only matching"));
|
||||
|
||||
QSettings mySettings;
|
||||
bool myDockFlag = mySettings.value("/qgis/dockAttributeTable",false).toBool();
|
||||
if (myDockFlag )
|
||||
{
|
||||
mDock = new QDockWidget(tr("Attribute table - ") + layer->name(), QgisApp::instance());
|
||||
mDock->setAllowedAreas(Qt::BottomDockWidgetArea | Qt::TopDockWidgetArea);
|
||||
mDock->setWidget(this);
|
||||
QgisApp::instance()->addDockWidget(Qt::BottomDockWidgetArea, mDock);
|
||||
buttonBox->setVisible(false);
|
||||
}
|
||||
|
||||
setWindowTitle(tr("Attribute table - ") + layer->name());
|
||||
}
|
||||
|
||||
QgsAttributeTableDisplay::~QgsAttributeTableDisplay()
|
||||
{
|
||||
smTables.remove(mLayer);
|
||||
}
|
||||
QgsAttributeTable *QgsAttributeTableDisplay::table()
|
||||
|
||||
void QgsAttributeTableDisplay::closeEvent(QCloseEvent *ev)
|
||||
{
|
||||
return tblAttributes;
|
||||
saveWindowLocation();
|
||||
ev->ignore();
|
||||
delete this;
|
||||
}
|
||||
|
||||
void QgsAttributeTableDisplay::fillTable()
|
||||
{
|
||||
tblAttributes->fillTable( mLayer );
|
||||
tblAttributes->setReadOnly( !mLayer->isEditable() );
|
||||
|
||||
selectionChanged();
|
||||
|
||||
// Give the table the most recent copy of the actions for this layer.
|
||||
setAttributeActions(*mLayer->actions());
|
||||
}
|
||||
|
||||
void QgsAttributeTableDisplay::toggleEditing()
|
||||
{
|
||||
emit editingToggled(mLayer);
|
||||
}
|
||||
|
||||
void QgsAttributeTableDisplay::setAttributeActions(const QgsAttributeAction &action)
|
||||
{
|
||||
tblAttributes->setAttributeActions(action);
|
||||
}
|
||||
|
||||
void QgsAttributeTableDisplay::selectRowsWithId(const QgsFeatureIds &ids)
|
||||
{
|
||||
tblAttributes->selectRowsWithId(ids);
|
||||
}
|
||||
|
||||
void QgsAttributeTableDisplay::setTheme()
|
||||
{
|
||||
mAddAttributeButton->setIcon(QgisApp::getThemeIcon("/mActionNewAttribute.png"));
|
||||
mRemoveSelectionButton->setIcon(QgisApp::getThemeIcon("/mActionUnselectAttributes.png"));
|
||||
mSelectedToTopButton->setIcon(QgisApp::getThemeIcon("/mActionSelectedToTop.png"));
|
||||
mInvertSelectionButton->setIcon(QgisApp::getThemeIcon("/mActionInvertSelection.png"));
|
||||
mCopySelectedRowsButton->setIcon(QgisApp::getThemeIcon("/mActionCopySelected.png"));
|
||||
mZoomMapToSelectedRowsButton->setIcon(QgisApp::getThemeIcon("/mActionZoomToSelected.png"));
|
||||
mAddAttributeButton->setIcon(QgisApp::getThemeIcon("/mActionNewAttribute.png"));
|
||||
mDeleteAttributeButton->setIcon(QgisApp::getThemeIcon("/mActionDeleteAttribute.png"));
|
||||
btnEdit->setIcon(QgisApp::getThemeIcon("/mActionToggleEditing.png"));
|
||||
mToggleEditingButton->setIcon(QgisApp::getThemeIcon("/mActionToggleEditing.png"));
|
||||
}
|
||||
|
||||
void QgsAttributeTableDisplay::setTitle(QString title)
|
||||
void QgsAttributeTableDisplay::editingToggled()
|
||||
{
|
||||
setWindowTitle(title);
|
||||
}
|
||||
|
||||
void QgsAttributeTableDisplay::deleteAttributes()
|
||||
{
|
||||
QgsDelAttrDialog dialog(table()->horizontalHeader());
|
||||
if(dialog.exec()==QDialog::Accepted)
|
||||
{
|
||||
const std::list<QString>* attlist=dialog.selectedAttributes();
|
||||
for(std::list<QString>::const_iterator iter=attlist->begin();iter!=attlist->end();++iter)
|
||||
{
|
||||
table()->deleteAttribute(*iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsAttributeTableDisplay::addAttribute()
|
||||
{
|
||||
QgsAddAttrDialog dialog(mLayer->getDataProvider(), this);
|
||||
if(dialog.exec()==QDialog::Accepted)
|
||||
{
|
||||
if(!table()->addAttribute(dialog.name(),dialog.type()))
|
||||
{
|
||||
QMessageBox::information(this,tr("Name conflict"),tr("The attribute could not be inserted. The name already exists in the table."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsAttributeTableDisplay::startEditing()
|
||||
{
|
||||
QgsVectorDataProvider* provider=mLayer->getDataProvider();
|
||||
bool editing=false;
|
||||
|
||||
if(provider)
|
||||
{
|
||||
if(provider->capabilities()&QgsVectorDataProvider::AddAttributes)
|
||||
{
|
||||
mAddAttributeButton->setEnabled(true);
|
||||
editing=true;
|
||||
}
|
||||
if(provider->capabilities()&QgsVectorDataProvider::DeleteAttributes)
|
||||
{
|
||||
|
||||
mDeleteAttributeButton->setEnabled(true);
|
||||
editing=true;
|
||||
}
|
||||
if(provider->capabilities()&QgsVectorDataProvider::ChangeAttributeValues)
|
||||
{
|
||||
table()->setReadOnly(false);
|
||||
table()->setColumnReadOnly(0,true);//id column is not editable
|
||||
editing=true;
|
||||
}
|
||||
if(editing)
|
||||
{
|
||||
btnEdit->setText(tr("Stop editing"));
|
||||
buttonBox->button(QDialogButtonBox::Close)->setEnabled(false);
|
||||
//make the dialog modal when in editable
|
||||
//otherwise map editing and table editing
|
||||
//may disturb each other
|
||||
//hide();
|
||||
//setModal(true);
|
||||
//show();
|
||||
}
|
||||
else
|
||||
{
|
||||
//revert button
|
||||
QMessageBox::information(this,tr("Editing not permitted"),tr("The data provider is read only, editing is not allowed."));
|
||||
btnEdit->setChecked(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsAttributeTableDisplay::on_btnEdit_toggled(bool theFlag)
|
||||
{
|
||||
if (theFlag)
|
||||
{
|
||||
startEditing();
|
||||
}
|
||||
else
|
||||
{
|
||||
stopEditing();
|
||||
}
|
||||
}
|
||||
|
||||
void QgsAttributeTableDisplay::stopEditing()
|
||||
{
|
||||
if(table()->edited())
|
||||
{
|
||||
//commit or roll back?
|
||||
QMessageBox::StandardButton commit=QMessageBox::information(this,tr("Stop editing"),
|
||||
tr("Do you want to save the changes?"),
|
||||
QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
|
||||
if(commit==QMessageBox::Save)
|
||||
{
|
||||
if(!table()->commitChanges(mLayer))
|
||||
{
|
||||
QMessageBox::information(this,tr("Error"),tr("Could not commit changes - changes are still pending"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if(commit == QMessageBox::Discard)
|
||||
{
|
||||
table()->rollBack(mLayer);
|
||||
}
|
||||
else //cancel
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
btnEdit->setText(tr("Start editing"));
|
||||
buttonBox->button(QDialogButtonBox::Close)->setEnabled(true);
|
||||
mAddAttributeButton->setEnabled(false);
|
||||
mDeleteAttributeButton->setEnabled(false);
|
||||
table()->setReadOnly(true);
|
||||
//make this dialog modeless again
|
||||
hide();
|
||||
setModal(false);
|
||||
show();
|
||||
mToggleEditingButton->setChecked( mLayer->isEditable() );
|
||||
tblAttributes->setReadOnly( !mLayer->isEditable() );
|
||||
}
|
||||
|
||||
void QgsAttributeTableDisplay::selectedToTop()
|
||||
{
|
||||
table()->bringSelectedToTop();
|
||||
tblAttributes->bringSelectedToTop();
|
||||
}
|
||||
|
||||
void QgsAttributeTableDisplay::invertSelection()
|
||||
{
|
||||
if(mLayer)
|
||||
{
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
mLayer->invertSelection();
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
if(!mLayer)
|
||||
return;
|
||||
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
mLayer->invertSelection();
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
|
||||
void QgsAttributeTableDisplay::removeSelection()
|
||||
{
|
||||
table()->clearSelection();
|
||||
mLayer->triggerRepaint();
|
||||
tblAttributes->clearSelection();
|
||||
mLayer->triggerRepaint();
|
||||
}
|
||||
|
||||
void QgsAttributeTableDisplay::copySelectedRowsToClipboard()
|
||||
{
|
||||
// Deprecated
|
||||
// table()->copySelectedRows();
|
||||
|
||||
// Use the Application's copy method instead
|
||||
mQgisApp->editCopy(mLayer);
|
||||
QgisApp::instance()->editCopy(mLayer);
|
||||
}
|
||||
|
||||
void QgsAttributeTableDisplay::zoomMapToSelectedRows()
|
||||
{
|
||||
mQgisApp->zoomToSelected();
|
||||
QgisApp::instance()->zoomToSelected();
|
||||
}
|
||||
|
||||
void QgsAttributeTableDisplay::search()
|
||||
{
|
||||
// if selected field is numeric, numeric comparison will be used
|
||||
// else attributes containing entered text will be matched
|
||||
|
||||
QgsVectorDataProvider* provider = mLayer->getDataProvider();
|
||||
int item = mSearchColumns->currentIndex();
|
||||
QVariant::Type type = provider->fields()[item].type();
|
||||
int type = tblAttributes->item(0, mSearchColumns->currentIndex())->data(QgsAttributeTable::AttributeType).toInt();
|
||||
bool numeric = (type == QVariant::Int || type == QVariant::Double);
|
||||
|
||||
QString str;
|
||||
@ -314,25 +237,25 @@ void QgsAttributeTableDisplay::searchShowResultsChanged(int item)
|
||||
|
||||
if (item == 2) // show only matching
|
||||
{
|
||||
table()->showRowsWithId(mSearchIds);
|
||||
tblAttributes->showRowsWithId(mSearchIds);
|
||||
}
|
||||
else
|
||||
{
|
||||
// make sure that all rows are shown
|
||||
table()->showAllRows();
|
||||
tblAttributes->showAllRows();
|
||||
|
||||
// select matching
|
||||
mLayer->setSelectedFeatures(mSearchIds);
|
||||
|
||||
if (item == 1) // select matching and bring to top
|
||||
table()->bringSelectedToTop();
|
||||
tblAttributes->bringSelectedToTop();
|
||||
}
|
||||
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
|
||||
|
||||
void QgsAttributeTableDisplay::doSearch(const QString& searchString)
|
||||
void QgsAttributeTableDisplay::doSearch(QString searchString)
|
||||
{
|
||||
mSearchString = searchString;
|
||||
|
||||
@ -343,6 +266,7 @@ void QgsAttributeTableDisplay::doSearch(const QString& searchString)
|
||||
QMessageBox::critical(this, tr("Search string parsing error"), search.parserErrorMsg());
|
||||
return;
|
||||
}
|
||||
|
||||
QgsSearchTreeNode* searchTree = search.tree();
|
||||
if (searchTree == NULL)
|
||||
{
|
||||
@ -354,24 +278,19 @@ void QgsAttributeTableDisplay::doSearch(const QString& searchString)
|
||||
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
|
||||
// TODO: need optimized getNextFeature which won't extract geometry
|
||||
// or search by traversing table ... which one is quicker?
|
||||
QgsFeature fet;
|
||||
QgsVectorDataProvider* provider = mLayer->getDataProvider();
|
||||
mSearchIds.clear();
|
||||
const QgsFieldMap& fields = provider->fields();
|
||||
QgsAttributeList all = provider->allAttributesList();
|
||||
|
||||
provider->select(all, QgsRect(), false);
|
||||
|
||||
while (provider->getNextFeature(fet))
|
||||
mLayer->select(mLayer->pendingAllAttributesList(), true, false);
|
||||
|
||||
QgsFeature f;
|
||||
while( mLayer->getNextFeature(f) )
|
||||
{
|
||||
if (searchTree->checkAgainst(fields, fet.attributeMap()))
|
||||
if (searchTree->checkAgainst(mLayer->pendingFields(), f.attributeMap()))
|
||||
{
|
||||
mSearchIds.insert(fet.featureId());
|
||||
mSearchIds << f.featureId();
|
||||
}
|
||||
|
||||
// check if there were errors during evaulating
|
||||
|
||||
// check if there were errors during evaluating
|
||||
if (searchTree->hasError())
|
||||
break;
|
||||
}
|
||||
@ -386,22 +305,13 @@ void QgsAttributeTableDisplay::doSearch(const QString& searchString)
|
||||
|
||||
// update table
|
||||
searchShowResultsChanged(mSearchShowResults->currentIndex());
|
||||
|
||||
|
||||
QString str;
|
||||
if (mSearchIds.size())
|
||||
str.sprintf(tr("Found %d matching features.","", mSearchIds.size()).toUtf8(), mSearchIds.size());
|
||||
else
|
||||
str = tr("No matching features found.");
|
||||
QMessageBox::information(this, tr("Search results"), str);
|
||||
|
||||
}
|
||||
|
||||
void QgsAttributeTableDisplay::closeEvent(QCloseEvent* ev)
|
||||
{
|
||||
saveWindowLocation();
|
||||
ev->ignore();
|
||||
emit deleted();
|
||||
delete this;
|
||||
}
|
||||
|
||||
void QgsAttributeTableDisplay::restorePosition()
|
||||
@ -423,16 +333,77 @@ void QgsAttributeTableDisplay::showHelp()
|
||||
|
||||
void QgsAttributeTableDisplay::changeFeatureAttribute(int row, int column)
|
||||
{
|
||||
QgsFeatureList &flist = mLayer->addedFeatures();
|
||||
|
||||
int id = table()->item(row,0)->text().toInt();
|
||||
|
||||
int i;
|
||||
for(i=0; i<flist.size() && flist[i].featureId()!=id; i++)
|
||||
;
|
||||
|
||||
if(i==flist.size())
|
||||
if(column==0)
|
||||
return;
|
||||
|
||||
flist[i].changeAttribute(column-1, table()->item(row,column)->text());
|
||||
if( !mLayer->isEditable() )
|
||||
return;
|
||||
|
||||
mLayer->changeAttributeValue(
|
||||
tblAttributes->item(row,0)->text().toInt(),
|
||||
tblAttributes->horizontalHeaderItem(column)->data(QgsAttributeTable::AttributeIndex).toInt(),
|
||||
tblAttributes->item(row, column)->text(),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
QMap<QgsVectorLayer *, QgsAttributeTableDisplay *> QgsAttributeTableDisplay::smTables;
|
||||
|
||||
QgsAttributeTableDisplay *QgsAttributeTableDisplay::attributeTable(QgsVectorLayer *layer)
|
||||
{
|
||||
if(!layer)
|
||||
return NULL;
|
||||
|
||||
if( smTables.contains(layer) ) {
|
||||
QgsAttributeTableDisplay *td = smTables[layer];
|
||||
td->setAttributeActions(*layer->actions());
|
||||
td->raise();
|
||||
|
||||
return td;
|
||||
}
|
||||
|
||||
QgsAttributeTableDisplay *td = new QgsAttributeTableDisplay(layer);
|
||||
if(!td)
|
||||
return NULL;
|
||||
|
||||
// display the attribute table
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
|
||||
try
|
||||
{
|
||||
td->fillTable();
|
||||
}
|
||||
catch(std::bad_alloc& ba)
|
||||
{
|
||||
Q_UNUSED(ba);
|
||||
QMessageBox::critical(0, tr("bad_alloc exception"), tr("Filling the attribute table has been stopped because there was no more virtual memory left"));
|
||||
delete td;
|
||||
td=NULL;
|
||||
}
|
||||
|
||||
QApplication::restoreOverrideCursor();
|
||||
|
||||
if(!td)
|
||||
return NULL;
|
||||
|
||||
smTables[layer] = td;
|
||||
td->show();
|
||||
|
||||
return td;
|
||||
}
|
||||
|
||||
void QgsAttributeTableDisplay::selectionChanged()
|
||||
{
|
||||
// select rows which should be selected
|
||||
selectRowsWithId( mLayer->selectedFeaturesIds() );
|
||||
}
|
||||
|
||||
void QgsAttributeTableDisplay::attributeAdded(int attr)
|
||||
{
|
||||
tblAttributes->addAttribute(attr, mLayer->pendingFields()[attr]);
|
||||
}
|
||||
|
||||
void QgsAttributeTableDisplay::attributeDeleted(int attr)
|
||||
{
|
||||
tblAttributes->deleteAttribute(attr);
|
||||
}
|
||||
|
@ -22,47 +22,41 @@
|
||||
|
||||
#include "ui_qgsattributetablebase.h"
|
||||
|
||||
|
||||
class QDockWidget;
|
||||
class QgsAttributeTable;
|
||||
class QgsVectorLayer;
|
||||
class QgisApp;
|
||||
class QgsAttributeActions;
|
||||
|
||||
/**
|
||||
*@author Gary E.Sherman
|
||||
*/
|
||||
|
||||
class QgsAttributeTableDisplay:public QDialog, private Ui::QgsAttributeTableBase
|
||||
class QgsAttributeTableDisplay : public QDialog, private Ui::QgsAttributeTableBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
\param qgisApp This should be the QgisApp that spawned this table.
|
||||
Otherwise the Copy button on this QgsAttributeTableDisplay
|
||||
will not work.
|
||||
*/
|
||||
QgsAttributeTableDisplay(QgsVectorLayer* layer, QgisApp * qgisApp);
|
||||
static QgsAttributeTableDisplay *attributeTable(QgsVectorLayer *layer);
|
||||
|
||||
~QgsAttributeTableDisplay();
|
||||
|
||||
QgsAttributeTable *table();
|
||||
void setTitle(QString title);
|
||||
void fillTable();
|
||||
|
||||
protected:
|
||||
QgsAttributeTableDisplay(QgsVectorLayer* layer);
|
||||
|
||||
QgsVectorLayer* mLayer;
|
||||
|
||||
QgisApp * mQgisApp;
|
||||
void doSearch(QString searchString);
|
||||
void setAttributeActions(const QgsAttributeAction &actions);
|
||||
void selectRowsWithId(const QgsFeatureIds &ids);
|
||||
|
||||
void doSearch(const QString& searchString);
|
||||
|
||||
virtual void closeEvent(QCloseEvent* ev);
|
||||
virtual void closeEvent(QCloseEvent *ev);
|
||||
|
||||
/** array of feature IDs that match last searched condition */
|
||||
QgsFeatureIds mSearchIds;
|
||||
|
||||
protected slots:
|
||||
void deleteAttributes();
|
||||
void addAttribute();
|
||||
void on_btnEdit_toggled(bool theFlag);
|
||||
void startEditing();
|
||||
void stopEditing();
|
||||
void selectedToTop();
|
||||
void invertSelection();
|
||||
void removeSelection();
|
||||
@ -72,12 +66,18 @@ class QgsAttributeTableDisplay:public QDialog, private Ui::QgsAttributeTableBase
|
||||
void advancedSearch();
|
||||
void searchShowResultsChanged(int item);
|
||||
void showHelp();
|
||||
void toggleEditing();
|
||||
|
||||
void attributeAdded(int idx);
|
||||
void attributeDeleted(int idx);
|
||||
|
||||
public slots:
|
||||
void changeFeatureAttribute(int row, int column);
|
||||
|
||||
void editingToggled();
|
||||
void selectionChanged();
|
||||
|
||||
signals:
|
||||
void deleted();
|
||||
void editingToggled(QgsMapLayer *);
|
||||
|
||||
private:
|
||||
/** Set the icon theme for this dialog */
|
||||
@ -88,7 +88,11 @@ class QgsAttributeTableDisplay:public QDialog, private Ui::QgsAttributeTableBase
|
||||
|
||||
QString mSearchString;
|
||||
|
||||
QDockWidget *mDock;
|
||||
|
||||
static const int context_id = 831088384;
|
||||
|
||||
static QMap<QgsVectorLayer *, QgsAttributeTableDisplay *> smTables;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -227,14 +227,12 @@ void QgsBookmarks::zoomToBookmark()
|
||||
QString xmax = QString::fromUtf8((const char *)sqlite3_column_text(ppStmt, 2));
|
||||
QString ymax = QString::fromUtf8((const char *)sqlite3_column_text(ppStmt, 3));
|
||||
// set the extent to the bookmark
|
||||
dynamic_cast<QgisApp*>(mParent)->setExtent(QgsRect(xmin.toDouble(),
|
||||
QgisApp::instance()->setExtent(QgsRect(xmin.toDouble(),
|
||||
ymin.toDouble(),
|
||||
xmax.toDouble(),
|
||||
ymax.toDouble()));
|
||||
// redraw the map
|
||||
dynamic_cast<QgisApp*>(mParent)->getMapCanvas()->refresh();
|
||||
|
||||
|
||||
QgisApp::instance()->getMapCanvas()->refresh();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,11 +23,9 @@
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
|
||||
class QgsFeature;
|
||||
class QgsField;
|
||||
#include "qgsfield.h"
|
||||
#include "qgsfeature.h"
|
||||
|
||||
typedef QList<QgsFeature> QgsFeatureList;
|
||||
typedef QMap<int, QgsField> QgsFieldMap;
|
||||
|
||||
/**
|
||||
|
||||
@ -74,18 +72,18 @@ public:
|
||||
* when it's done with it.
|
||||
*/
|
||||
QgsFeatureList copyOf();
|
||||
|
||||
|
||||
/*
|
||||
* Clears the internal clipboard.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
|
||||
/*
|
||||
* Inserts a copy of the feature on the internal clipboard.
|
||||
*/
|
||||
void insert( QgsFeature& feature );
|
||||
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/** QGIS-internal vector feature clipboard.
|
||||
|
@ -38,8 +38,8 @@ email : sherman at mrcc.com
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
QgsDbSourceSelect::QgsDbSourceSelect(QgisApp *app, Qt::WFlags fl)
|
||||
: QDialog(app, fl), mColumnTypeThread(NULL), qgisApp(app), pd(0)
|
||||
QgsDbSourceSelect::QgsDbSourceSelect(QWidget *parent, Qt::WFlags fl)
|
||||
: QDialog(parent, fl), mColumnTypeThread(NULL), pd(0)
|
||||
{
|
||||
setupUi(this);
|
||||
btnAdd->setEnabled(false);
|
||||
|
@ -54,7 +54,7 @@ class QgsDbSourceSelect : public QDialog, private Ui::QgsDbSourceSelectBase
|
||||
public:
|
||||
|
||||
//! Constructor
|
||||
QgsDbSourceSelect(QgisApp *app, Qt::WFlags fl = QgisGui::ModalDialogFlags);
|
||||
QgsDbSourceSelect(QWidget *parent = 0, Qt::WFlags fl = QgisGui::ModalDialogFlags);
|
||||
//! Destructor
|
||||
~QgsDbSourceSelect();
|
||||
//! Opens the create connection dialog to build a new connection
|
||||
@ -136,8 +136,6 @@ class QgsDbSourceSelect : public QDialog, private Ui::QgsDbSourceSelectBase
|
||||
QStringList m_selectedTables;
|
||||
// Storage for the range of layer type icons
|
||||
QMap<QString, QPair<QString, QIcon> > mLayerIcons;
|
||||
//! Pointer to the qgis application mainwindow
|
||||
QgisApp *qgisApp;
|
||||
PGconn *pd;
|
||||
static const int context_id = 939347163;
|
||||
//! Model that acts as datasource for mTableTreeWidget
|
||||
|
@ -186,6 +186,15 @@ void QgsIdentifyResults::addDerivedAttribute(QTreeWidgetItem * fnode, QString fi
|
||||
new QTreeWidgetItem(daRootNode, labels);
|
||||
}
|
||||
|
||||
void QgsIdentifyResults::addEdit(QTreeWidgetItem * fnode, int id)
|
||||
{
|
||||
QStringList labels;
|
||||
labels << "edit" << QString::number(id);
|
||||
QTreeWidgetItem *item = new QTreeWidgetItem(fnode, labels );
|
||||
|
||||
item->setIcon ( 0, QgisApp::getThemeIcon("/mIconEditable.png") );
|
||||
}
|
||||
|
||||
void QgsIdentifyResults::addAction(QTreeWidgetItem * fnode, int id, QString field, QString value)
|
||||
{
|
||||
QStringList labels;
|
||||
@ -198,7 +207,7 @@ void QgsIdentifyResults::addAction(QTreeWidgetItem * fnode, int id, QString fiel
|
||||
/** Add a feature node to the list */
|
||||
QTreeWidgetItem *QgsIdentifyResults::addNode(QString label)
|
||||
{
|
||||
return (new QTreeWidgetItem(lstResults, QStringList(label)));
|
||||
return new QTreeWidgetItem(lstResults, QStringList(label));
|
||||
}
|
||||
|
||||
void QgsIdentifyResults::setTitle(QString title)
|
||||
@ -251,15 +260,21 @@ void QgsIdentifyResults::setActions( const QgsAttributeAction& actions )
|
||||
|
||||
void QgsIdentifyResults::clicked ( QTreeWidgetItem *item )
|
||||
{
|
||||
if ( !item ) return;
|
||||
if ( !item )
|
||||
return;
|
||||
|
||||
if ( item->text(2) != "action" ) return;
|
||||
if ( item->text(2) == "action" )
|
||||
{
|
||||
int id = item->text(3).toInt();
|
||||
|
||||
int id = item->text(3).toInt();
|
||||
extractAllItemData(item);
|
||||
|
||||
extractAllItemData(item);
|
||||
|
||||
mActions.doAction(id, mValues, mClickedOnValue);
|
||||
mActions.doAction(id, mValues, mClickedOnValue);
|
||||
}
|
||||
else if( item->text(0) == "edit" )
|
||||
{
|
||||
emit editFeature( item->text(1).toInt() );
|
||||
}
|
||||
}
|
||||
void QgsIdentifyResults::on_buttonHelp_clicked()
|
||||
{
|
||||
@ -325,7 +340,7 @@ void QgsIdentifyResults::extractAllItemData(QTreeWidgetItem* item)
|
||||
parent = child;
|
||||
|
||||
mValues.clear();
|
||||
|
||||
|
||||
// For the code below we
|
||||
// need to do the comparison on the text strings rather than the
|
||||
// pointers because if the user clicked on the parent, we need
|
||||
@ -341,27 +356,27 @@ void QgsIdentifyResults::extractAllItemData(QTreeWidgetItem* item)
|
||||
if (parent->child(j)->text(0) == mDerivedLabel ) {
|
||||
for (int k = 0; k < parent->child(j)->childCount(); ++k)
|
||||
{
|
||||
mValues.push_back(
|
||||
std::make_pair(mDerivedLabel + "."
|
||||
+ parent->child(j)->child(k)->text(0),
|
||||
parent->child(j)->child(k)->text(1)));
|
||||
mValues.push_back(
|
||||
std::make_pair(mDerivedLabel + "."
|
||||
+ parent->child(j)->child(k)->text(0),
|
||||
parent->child(j)->child(k)->text(1)));
|
||||
|
||||
if (item == parent->child(j)->child(k))
|
||||
{
|
||||
mClickedOnValue = valuesIndex;
|
||||
}
|
||||
if (item == parent->child(j)->child(k))
|
||||
{
|
||||
mClickedOnValue = valuesIndex;
|
||||
}
|
||||
|
||||
valuesIndex++;
|
||||
valuesIndex++;
|
||||
}
|
||||
}
|
||||
else // do the actual feature attributes
|
||||
{
|
||||
mValues.push_back(std::make_pair(parent->child(j)->text(0),
|
||||
parent->child(j)->text(1)));
|
||||
parent->child(j)->text(1)));
|
||||
|
||||
if (item == parent->child(j))
|
||||
{
|
||||
mClickedOnValue = valuesIndex;
|
||||
mClickedOnValue = valuesIndex;
|
||||
}
|
||||
|
||||
valuesIndex++;
|
||||
|
@ -57,6 +57,9 @@ class QgsIdentifyResults: public QDialog, private Ui::QgsIdentifyResultsBase
|
||||
/** Add an action to the feature display node */
|
||||
void addAction(QTreeWidgetItem *parent, int id, QString field, QString value);
|
||||
|
||||
/** Add an edit action to the feature display node */
|
||||
void addEdit(QTreeWidgetItem *parent, int id);
|
||||
|
||||
/** Add a feature node to the feature display */
|
||||
QTreeWidgetItem * addNode(QString label);
|
||||
/** Set the title for the identify results dialog */
|
||||
@ -85,6 +88,7 @@ class QgsIdentifyResults: public QDialog, private Ui::QgsIdentifyResultsBase
|
||||
|
||||
signals:
|
||||
void selectedFeatureChanged(int featureId);
|
||||
void editFeature(int featureId);
|
||||
|
||||
public slots:
|
||||
|
||||
@ -110,26 +114,27 @@ class QgsIdentifyResults: public QDialog, private Ui::QgsIdentifyResultsBase
|
||||
|
||||
private:
|
||||
|
||||
QgsAttributeAction mActions;
|
||||
int mClickedOnValue;
|
||||
QMenu* mActionPopup;
|
||||
std::vector<std::pair<QString, QString> > mValues;
|
||||
static const int context_id = 689216579;
|
||||
int mCurrentFeatureId;
|
||||
QString mDerivedLabel;
|
||||
bool mEditable;
|
||||
QgsAttributeAction mActions;
|
||||
int mClickedOnValue;
|
||||
QMenu* mActionPopup;
|
||||
std::vector<std::pair<QString, QString> > mValues;
|
||||
static const int context_id = 689216579;
|
||||
int mCurrentFeatureId;
|
||||
QString mDerivedLabel;
|
||||
|
||||
/**
|
||||
Keeps track of what derived-attribute (e.g. Length, Area)
|
||||
root nodes have been generated for each feature in this widget.
|
||||
/**
|
||||
Keeps track of what derived-attribute (e.g. Length, Area)
|
||||
root nodes have been generated for each feature in this widget.
|
||||
|
||||
First item: Feature root node
|
||||
Second item: Derived-attribute root node for that feature
|
||||
*/
|
||||
std::map<QTreeWidgetItem *, QTreeWidgetItem *> mDerivedAttributeRootNodes;
|
||||
First item: Feature root node
|
||||
Second item: Derived-attribute root node for that feature
|
||||
*/
|
||||
std::map<QTreeWidgetItem *, QTreeWidgetItem *> mDerivedAttributeRootNodes;
|
||||
|
||||
// Convenience function to populate mValues with all of the item names and
|
||||
// values for a item, including the derived ones.
|
||||
void extractAllItemData(QTreeWidgetItem* item);
|
||||
// Convenience function to populate mValues with all of the item names and
|
||||
// values for a item, including the derived ones.
|
||||
void extractAllItemData(QTreeWidgetItem* item);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -42,419 +42,420 @@ QgsMapToolAddFeature::~QgsMapToolAddFeature()
|
||||
void QgsMapToolAddFeature::canvasReleaseEvent(QMouseEvent * e)
|
||||
{
|
||||
QgsVectorLayer *vlayer = dynamic_cast <QgsVectorLayer*>(mCanvas->currentLayer());
|
||||
|
||||
|
||||
if (!vlayer)
|
||||
{
|
||||
QMessageBox::information(0, QObject::tr("Not a vector layer"),
|
||||
QObject::tr("The current layer is not a vector layer"));
|
||||
return;
|
||||
}
|
||||
{
|
||||
QMessageBox::information(0, QObject::tr("Not a vector layer"),
|
||||
QObject::tr("The current layer is not a vector layer"));
|
||||
return;
|
||||
}
|
||||
|
||||
QGis::WKBTYPE layerWKBType = vlayer->geometryType();
|
||||
|
||||
//no support for adding features to 2.5D types yet
|
||||
if(layerWKBType == QGis::WKBLineString25D || layerWKBType == QGis::WKBPolygon25D || \
|
||||
layerWKBType == QGis::WKBMultiLineString25D || layerWKBType == QGis::WKBPoint25D || layerWKBType == QGis::WKBMultiPoint25D)
|
||||
{
|
||||
QMessageBox::critical(0, QObject::tr("2.5D shape type not supported"), QObject::tr("Adding features to 2.5D shapetypes is not supported yet"));
|
||||
delete mRubberBand;
|
||||
mRubberBand = NULL;
|
||||
mCapturing = FALSE;
|
||||
mCaptureList.clear();
|
||||
mCanvas->refresh();
|
||||
return;
|
||||
}
|
||||
|
||||
layerWKBType == QGis::WKBMultiLineString25D || layerWKBType == QGis::WKBPoint25D || layerWKBType == QGis::WKBMultiPoint25D)
|
||||
{
|
||||
QMessageBox::critical(0, QObject::tr("2.5D shape type not supported"), QObject::tr("Adding features to 2.5D shapetypes is not supported yet"));
|
||||
delete mRubberBand;
|
||||
mRubberBand = NULL;
|
||||
mCapturing = FALSE;
|
||||
mCaptureList.clear();
|
||||
mCanvas->refresh();
|
||||
return;
|
||||
}
|
||||
|
||||
QgsVectorDataProvider* provider = vlayer->getDataProvider();
|
||||
|
||||
|
||||
if(!(provider->capabilities() & QgsVectorDataProvider::AddFeatures))
|
||||
{
|
||||
QMessageBox::information(0, QObject::tr("Layer cannot be added to"),
|
||||
QObject::tr("The data provider for this layer does not support the addition of features."));
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
QMessageBox::information(0, QObject::tr("Layer cannot be added to"),
|
||||
QObject::tr("The data provider for this layer does not support the addition of features."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!vlayer->isEditable())
|
||||
{
|
||||
QMessageBox::information(0, QObject::tr("Layer not editable"),
|
||||
QObject::tr("Cannot edit the vector layer. To make it editable, go to the file item "
|
||||
"of the layer, right click and check 'Allow Editing'."));
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
QMessageBox::information(0, QObject::tr("Layer not editable"),
|
||||
QObject::tr("Cannot edit the vector layer. To make it editable, go to the file item "
|
||||
"of the layer, right click and check 'Allow Editing'."));
|
||||
return;
|
||||
}
|
||||
|
||||
// POINT CAPTURING
|
||||
if (mTool == CapturePoint)
|
||||
{
|
||||
//check we only use this tool for point/multipoint layers
|
||||
if(vlayer->vectorType() != QGis::Point)
|
||||
{
|
||||
//check we only use this tool for point/multipoint layers
|
||||
if(vlayer->vectorType() != QGis::Point)
|
||||
{
|
||||
QMessageBox::information(0, QObject::tr("Wrong editing tool"),
|
||||
QObject::tr("Cannot apply the 'capture point' tool on this vector layer"));
|
||||
return;
|
||||
}
|
||||
QMessageBox::information(0, QObject::tr("Wrong editing tool"),
|
||||
QObject::tr("Cannot apply the 'capture point' tool on this vector layer"));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
QgsPoint idPoint; //point in map coordinates
|
||||
QList<QgsSnappingResult> snapResults;
|
||||
QgsPoint savePoint; //point in layer coordinates
|
||||
|
||||
if(mSnapper.snapToBackgroundLayers(e->pos(), snapResults) == 0)
|
||||
|
||||
QgsPoint idPoint; //point in map coordinates
|
||||
QList<QgsSnappingResult> snapResults;
|
||||
QgsPoint savePoint; //point in layer coordinates
|
||||
|
||||
if(mSnapper.snapToBackgroundLayers(e->pos(), snapResults) == 0)
|
||||
{
|
||||
idPoint = snapPointFromResults(snapResults, e->pos());
|
||||
try
|
||||
{
|
||||
idPoint = snapPointFromResults(snapResults, e->pos());
|
||||
try
|
||||
{
|
||||
savePoint = toLayerCoords(vlayer, idPoint);
|
||||
QgsDebugMsg("savePoint = " + savePoint.stringRep());
|
||||
}
|
||||
catch(QgsCsException &cse)
|
||||
{
|
||||
Q_UNUSED(cse);
|
||||
QMessageBox::information(0, QObject::tr("Coordinate transform error"), \
|
||||
QObject::tr("Cannot transform the point to the layers coordinate system"));
|
||||
return;
|
||||
}
|
||||
savePoint = toLayerCoords(vlayer, idPoint);
|
||||
QgsDebugMsg("savePoint = " + savePoint.stringRep());
|
||||
}
|
||||
catch(QgsCsException &cse)
|
||||
{
|
||||
Q_UNUSED(cse);
|
||||
QMessageBox::information(0, QObject::tr("Coordinate transform error"), \
|
||||
QObject::tr("Cannot transform the point to the layers coordinate system"));
|
||||
return;
|
||||
}
|
||||
|
||||
// emit signal - QgisApp can catch it and save point position to clipboard
|
||||
// FIXME: is this still actual or something old that's not used anymore?
|
||||
//emit xyClickCoordinates(idPoint);
|
||||
|
||||
//only do the rest for provider with feature addition support
|
||||
//note that for the grass provider, this will return false since
|
||||
//grass provider has its own mechanism of feature addition
|
||||
if(provider->capabilities() & QgsVectorDataProvider::AddFeatures)
|
||||
{
|
||||
QgsFeature* f = new QgsFeature(0,"WKBPoint");
|
||||
|
||||
int size = 0;
|
||||
char end=QgsApplication::endian();
|
||||
unsigned char *wkb = NULL;
|
||||
int wkbtype = 0;
|
||||
double x = savePoint.x();
|
||||
double y = savePoint.y();
|
||||
|
||||
if(layerWKBType == QGis::WKBPoint)
|
||||
{
|
||||
size=1+sizeof(int)+2*sizeof(double);
|
||||
wkb = new unsigned char[size];
|
||||
wkbtype=QGis::WKBPoint;
|
||||
memcpy(&wkb[0],&end,1);
|
||||
memcpy(&wkb[1],&wkbtype, sizeof(int));
|
||||
memcpy(&wkb[5], &x, sizeof(double));
|
||||
memcpy(&wkb[5]+sizeof(double), &y, sizeof(double));
|
||||
}
|
||||
else if(layerWKBType == QGis::WKBMultiPoint)
|
||||
{
|
||||
size = 2+3*sizeof(int)+2*sizeof(double);
|
||||
wkb = new unsigned char[size];
|
||||
wkbtype=QGis::WKBMultiPoint;
|
||||
int position = 0;
|
||||
memcpy(&wkb[position], &end, 1);
|
||||
position += 1;
|
||||
memcpy(&wkb[position], &wkbtype, sizeof(int));
|
||||
position += sizeof(int);
|
||||
int npoint = 1;
|
||||
memcpy(&wkb[position], &npoint, sizeof(int));
|
||||
position += sizeof(int);
|
||||
memcpy(&wkb[position], &end, 1);
|
||||
position += 1;
|
||||
int pointtype = QGis::WKBPoint;
|
||||
memcpy(&wkb[position],&pointtype, sizeof(int));
|
||||
position += sizeof(int);
|
||||
memcpy(&wkb[position], &x, sizeof(double));
|
||||
position += sizeof(double);
|
||||
memcpy(&wkb[position], &y, sizeof(double));
|
||||
}
|
||||
|
||||
f->setGeometryAndOwnership(&wkb[0],size);
|
||||
// add the fields to the QgsFeature
|
||||
const QgsFieldMap fields=provider->fields();
|
||||
for(QgsFieldMap::const_iterator it = fields.constBegin(); it != fields.constEnd(); ++it)
|
||||
{
|
||||
f->addAttribute(it.key(), provider->getDefaultValue(it.key()) );
|
||||
}
|
||||
|
||||
// show the dialog to enter attribute values
|
||||
QgsAttributeDialog * mypDialog = new QgsAttributeDialog( vlayer, f );
|
||||
if (mypDialog->exec())
|
||||
|
||||
// emit signal - QgisApp can catch it and save point position to clipboard
|
||||
// FIXME: is this still actual or something old that's not used anymore?
|
||||
//emit xyClickCoordinates(idPoint);
|
||||
|
||||
//only do the rest for provider with feature addition support
|
||||
//note that for the grass provider, this will return false since
|
||||
//grass provider has its own mechanism of feature addition
|
||||
if(provider->capabilities() & QgsVectorDataProvider::AddFeatures)
|
||||
{
|
||||
qDebug("Adding feature to layer");
|
||||
vlayer->addFeature(*f);
|
||||
QgsFeature* f = new QgsFeature(0,"WKBPoint");
|
||||
|
||||
int size = 0;
|
||||
char end=QgsApplication::endian();
|
||||
unsigned char *wkb = NULL;
|
||||
int wkbtype = 0;
|
||||
double x = savePoint.x();
|
||||
double y = savePoint.y();
|
||||
|
||||
if(layerWKBType == QGis::WKBPoint)
|
||||
{
|
||||
size=1+sizeof(int)+2*sizeof(double);
|
||||
wkb = new unsigned char[size];
|
||||
wkbtype=QGis::WKBPoint;
|
||||
memcpy(&wkb[0],&end,1);
|
||||
memcpy(&wkb[1],&wkbtype, sizeof(int));
|
||||
memcpy(&wkb[5], &x, sizeof(double));
|
||||
memcpy(&wkb[5]+sizeof(double), &y, sizeof(double));
|
||||
}
|
||||
else if(layerWKBType == QGis::WKBMultiPoint)
|
||||
{
|
||||
size = 2+3*sizeof(int)+2*sizeof(double);
|
||||
wkb = new unsigned char[size];
|
||||
wkbtype=QGis::WKBMultiPoint;
|
||||
int position = 0;
|
||||
memcpy(&wkb[position], &end, 1);
|
||||
position += 1;
|
||||
memcpy(&wkb[position], &wkbtype, sizeof(int));
|
||||
position += sizeof(int);
|
||||
int npoint = 1;
|
||||
memcpy(&wkb[position], &npoint, sizeof(int));
|
||||
position += sizeof(int);
|
||||
memcpy(&wkb[position], &end, 1);
|
||||
position += 1;
|
||||
int pointtype = QGis::WKBPoint;
|
||||
memcpy(&wkb[position],&pointtype, sizeof(int));
|
||||
position += sizeof(int);
|
||||
memcpy(&wkb[position], &x, sizeof(double));
|
||||
position += sizeof(double);
|
||||
memcpy(&wkb[position], &y, sizeof(double));
|
||||
}
|
||||
|
||||
f->setGeometryAndOwnership(&wkb[0],size);
|
||||
// add the fields to the QgsFeature
|
||||
const QgsFieldMap fields=vlayer->pendingFields();
|
||||
for(QgsFieldMap::const_iterator it = fields.constBegin(); it != fields.constEnd(); ++it)
|
||||
{
|
||||
f->addAttribute(it.key(), provider->getDefaultValue(it.key()) );
|
||||
}
|
||||
|
||||
// show the dialog to enter attribute values
|
||||
QgsAttributeDialog * mypDialog = new QgsAttributeDialog( vlayer, f );
|
||||
if (mypDialog->exec())
|
||||
{
|
||||
qDebug("Adding feature to layer");
|
||||
vlayer->addFeature(*f);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug("Adding feature to layer failed");
|
||||
delete f;
|
||||
}
|
||||
delete mypDialog;
|
||||
mCanvas->refresh();
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug("Adding feature to layer failed");
|
||||
delete f;
|
||||
}
|
||||
delete mypDialog;
|
||||
mCanvas->refresh();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
else if (mTool == CaptureLine || mTool == CapturePolygon)
|
||||
{
|
||||
//check we only use the line tool for line/multiline layers
|
||||
if(mTool == CaptureLine && vlayer->vectorType() != QGis::Line)
|
||||
{
|
||||
//check we only use the line tool for line/multiline layers
|
||||
if(mTool == CaptureLine && vlayer->vectorType() != QGis::Line)
|
||||
{
|
||||
QMessageBox::information(0, QObject::tr("Wrong editing tool"),
|
||||
QObject::tr("Cannot apply the 'capture line' tool on this vector layer"));
|
||||
return;
|
||||
}
|
||||
|
||||
//check we only use the polygon tool for polygon/multipolygon layers
|
||||
if(mTool == CapturePolygon && vlayer->vectorType() != QGis::Polygon)
|
||||
{
|
||||
QMessageBox::information(0, QObject::tr("Wrong editing tool"),
|
||||
QObject::tr("Cannot apply the 'capture polygon' tool on this vector layer"));
|
||||
return;
|
||||
}
|
||||
QMessageBox::information(0, QObject::tr("Wrong editing tool"),
|
||||
QObject::tr("Cannot apply the 'capture line' tool on this vector layer"));
|
||||
return;
|
||||
}
|
||||
|
||||
//add point to list and to rubber band
|
||||
int error = addVertex(e->pos());
|
||||
if(error == 1)
|
||||
{
|
||||
//current layer is not a vector layer
|
||||
return;
|
||||
}
|
||||
else if (error == 2)
|
||||
{
|
||||
//problem with coordinate transformation
|
||||
QMessageBox::information(0, QObject::tr("Coordinate transform error"), \
|
||||
QObject::tr("Cannot transform the point to the layers coordinate system"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (e->button() == Qt::LeftButton)
|
||||
{
|
||||
mCapturing = TRUE;
|
||||
}
|
||||
else if (e->button() == Qt::RightButton)
|
||||
{
|
||||
// End of string
|
||||
|
||||
mCapturing = FALSE;
|
||||
|
||||
delete mRubberBand;
|
||||
mRubberBand = NULL;
|
||||
|
||||
//lines: bail out if there are not at least two vertices
|
||||
if(mTool == CaptureLine && mCaptureList.size() < 2)
|
||||
{
|
||||
mCaptureList.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
//polygons: bail out if there are not at least two vertices
|
||||
if(mTool == CapturePolygon && mCaptureList.size() < 3)
|
||||
{
|
||||
mCaptureList.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
//create QgsFeature with wkb representation
|
||||
QgsFeature* f = new QgsFeature(0,"WKBLineString");
|
||||
unsigned char* wkb;
|
||||
int size;
|
||||
char end=QgsApplication::endian();
|
||||
|
||||
if(mTool == CaptureLine)
|
||||
{
|
||||
if(layerWKBType == QGis::WKBLineString)
|
||||
{
|
||||
size=1+2*sizeof(int)+2*mCaptureList.size()*sizeof(double);
|
||||
wkb= new unsigned char[size];
|
||||
int wkbtype=QGis::WKBLineString;
|
||||
int length=mCaptureList.size();
|
||||
memcpy(&wkb[0],&end,1);
|
||||
memcpy(&wkb[1],&wkbtype, sizeof(int));
|
||||
memcpy(&wkb[1+sizeof(int)],&length, sizeof(int));
|
||||
int position=1+2*sizeof(int);
|
||||
double x,y;
|
||||
for(QList<QgsPoint>::iterator it=mCaptureList.begin();it!=mCaptureList.end();++it)
|
||||
{
|
||||
QgsPoint savePoint = *it;
|
||||
x = savePoint.x();
|
||||
y = savePoint.y();
|
||||
|
||||
memcpy(&wkb[position],&x,sizeof(double));
|
||||
position+=sizeof(double);
|
||||
|
||||
memcpy(&wkb[position],&y,sizeof(double));
|
||||
position+=sizeof(double);
|
||||
}
|
||||
}
|
||||
else if(layerWKBType == QGis::WKBMultiLineString)
|
||||
{
|
||||
size = 1+2*sizeof(int)+1+2*sizeof(int)+2*mCaptureList.size()*sizeof(double);
|
||||
wkb= new unsigned char[size];
|
||||
int position = 0;
|
||||
int wkbtype=QGis::WKBMultiLineString;
|
||||
memcpy(&wkb[position], &end, 1);
|
||||
position += 1;
|
||||
memcpy(&wkb[position], &wkbtype, sizeof(int));
|
||||
position += sizeof(int);
|
||||
int nlines = 1;
|
||||
memcpy(&wkb[position], &nlines, sizeof(int));
|
||||
position += sizeof(int);
|
||||
memcpy(&wkb[position], &end, 1);
|
||||
position += 1;
|
||||
int linewkbtype = QGis::WKBLineString;
|
||||
memcpy(&wkb[position], &linewkbtype, sizeof(int));
|
||||
position += sizeof(int);
|
||||
int length=mCaptureList.size();
|
||||
memcpy(&wkb[position], &length, sizeof(int));
|
||||
position += sizeof(int);
|
||||
double x,y;
|
||||
for(QList<QgsPoint>::iterator it=mCaptureList.begin();it!=mCaptureList.end();++it)
|
||||
{
|
||||
QgsPoint savePoint = *it;
|
||||
x = savePoint.x();
|
||||
y = savePoint.y();
|
||||
|
||||
memcpy(&wkb[position],&x,sizeof(double));
|
||||
position+=sizeof(double);
|
||||
|
||||
memcpy(&wkb[position],&y,sizeof(double));
|
||||
position+=sizeof(double);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(0, QObject::tr("Error"), QObject::tr("Cannot add feature. Unknown WKB type"));
|
||||
return; //unknown wkbtype
|
||||
}
|
||||
f->setGeometryAndOwnership(&wkb[0],size);
|
||||
}
|
||||
else // polygon
|
||||
{
|
||||
if(layerWKBType == QGis::WKBPolygon)
|
||||
{
|
||||
size=1+3*sizeof(int)+2*(mCaptureList.size()+1)*sizeof(double);
|
||||
wkb= new unsigned char[size];
|
||||
int wkbtype=QGis::WKBPolygon;
|
||||
int length=mCaptureList.size()+1;//+1 because the first point is needed twice
|
||||
int numrings=1;
|
||||
memcpy(&wkb[0],&end,1);
|
||||
memcpy(&wkb[1],&wkbtype, sizeof(int));
|
||||
memcpy(&wkb[1+sizeof(int)],&numrings,sizeof(int));
|
||||
memcpy(&wkb[1+2*sizeof(int)],&length, sizeof(int));
|
||||
int position=1+3*sizeof(int);
|
||||
double x,y;
|
||||
QList<QgsPoint>::iterator it;
|
||||
for(it=mCaptureList.begin();it!=mCaptureList.end();++it)
|
||||
{
|
||||
QgsPoint savePoint = *it;
|
||||
x = savePoint.x();
|
||||
y = savePoint.y();
|
||||
|
||||
memcpy(&wkb[position],&x,sizeof(double));
|
||||
position+=sizeof(double);
|
||||
|
||||
memcpy(&wkb[position],&y,sizeof(double));
|
||||
position+=sizeof(double);
|
||||
}
|
||||
// close the polygon
|
||||
it=mCaptureList.begin();
|
||||
QgsPoint savePoint = *it;
|
||||
x = savePoint.x();
|
||||
y = savePoint.y();
|
||||
|
||||
memcpy(&wkb[position],&x,sizeof(double));
|
||||
position+=sizeof(double);
|
||||
|
||||
memcpy(&wkb[position],&y,sizeof(double));
|
||||
}
|
||||
else if(layerWKBType == QGis::WKBMultiPolygon)
|
||||
{
|
||||
size = 2+5*sizeof(int)+2*(mCaptureList.size()+1)*sizeof(double);
|
||||
wkb = new unsigned char[size];
|
||||
int wkbtype = QGis::WKBMultiPolygon;
|
||||
int polygontype = QGis::WKBPolygon;
|
||||
int length = mCaptureList.size()+1;//+1 because the first point is needed twice
|
||||
int numrings = 1;
|
||||
int numpolygons = 1;
|
||||
int position = 0; //pointer position relative to &wkb[0]
|
||||
memcpy(&wkb[position],&end,1);
|
||||
position += 1;
|
||||
memcpy(&wkb[position],&wkbtype, sizeof(int));
|
||||
position += sizeof(int);
|
||||
memcpy(&wkb[position], &numpolygons, sizeof(int));
|
||||
position += sizeof(int);
|
||||
memcpy(&wkb[position], &end, 1);
|
||||
position += 1;
|
||||
memcpy(&wkb[position], &polygontype, sizeof(int));
|
||||
position += sizeof(int);
|
||||
memcpy(&wkb[position], &numrings, sizeof(int));
|
||||
position += sizeof(int);
|
||||
memcpy(&wkb[position], &length, sizeof(int));
|
||||
position += sizeof(int);
|
||||
double x,y;
|
||||
QList<QgsPoint>::iterator it;
|
||||
for(it=mCaptureList.begin();it!=mCaptureList.end();++it)//add the captured points to the polygon
|
||||
{
|
||||
QgsPoint savePoint = *it;
|
||||
x = savePoint.x();
|
||||
y = savePoint.y();
|
||||
|
||||
memcpy(&wkb[position],&x,sizeof(double));
|
||||
position+=sizeof(double);
|
||||
|
||||
memcpy(&wkb[position],&y,sizeof(double));
|
||||
position+=sizeof(double);
|
||||
}
|
||||
// close the polygon
|
||||
it=mCaptureList.begin();
|
||||
QgsPoint savePoint = *it;
|
||||
x = savePoint.x();
|
||||
y = savePoint.y();
|
||||
memcpy(&wkb[position],&x,sizeof(double));
|
||||
position+=sizeof(double);
|
||||
memcpy(&wkb[position],&y,sizeof(double));
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(0, QObject::tr("Error"), QObject::tr("Cannot add feature. Unknown WKB type"));
|
||||
return; //unknown wkbtype
|
||||
}
|
||||
f->setGeometryAndOwnership(&wkb[0],size);
|
||||
//is automatic polygon intersection removal activated?
|
||||
int avoidPolygonIntersections = QgsProject::instance()->readNumEntry("Digitizing", "/AvoidPolygonIntersections", 0);
|
||||
|
||||
if(avoidPolygonIntersections != 0)
|
||||
{
|
||||
if(vlayer->removePolygonIntersections(f->geometry()) != 0)
|
||||
{
|
||||
QMessageBox::critical(0, QObject::tr("Error"), QObject::tr("Could not remove polygon intersection"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add the fields to the QgsFeature
|
||||
const QgsFieldMap fields = provider->fields();
|
||||
for(QgsFieldMap::const_iterator it = fields.begin(); it != fields.end(); ++it)
|
||||
{
|
||||
f->addAttribute(it.key(), provider->getDefaultValue(it.key()));
|
||||
}
|
||||
|
||||
QgsAttributeDialog * mypDialog = new QgsAttributeDialog( vlayer, f );
|
||||
if (mypDialog->exec())
|
||||
//check we only use the polygon tool for polygon/multipolygon layers
|
||||
if(mTool == CapturePolygon && vlayer->vectorType() != QGis::Polygon)
|
||||
{
|
||||
if(vlayer->addFeature(*f))
|
||||
QMessageBox::information(0, QObject::tr("Wrong editing tool"),
|
||||
QObject::tr("Cannot apply the 'capture polygon' tool on this vector layer"));
|
||||
return;
|
||||
}
|
||||
|
||||
//add point to list and to rubber band
|
||||
int error = addVertex(e->pos());
|
||||
if(error == 1)
|
||||
{
|
||||
//current layer is not a vector layer
|
||||
return;
|
||||
}
|
||||
else if (error == 2)
|
||||
{
|
||||
//problem with coordinate transformation
|
||||
QMessageBox::information(0, QObject::tr("Coordinate transform error"), \
|
||||
QObject::tr("Cannot transform the point to the layers coordinate system"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (e->button() == Qt::LeftButton)
|
||||
{
|
||||
mCapturing = TRUE;
|
||||
}
|
||||
else if (e->button() == Qt::RightButton)
|
||||
{
|
||||
// End of string
|
||||
|
||||
mCapturing = FALSE;
|
||||
|
||||
delete mRubberBand;
|
||||
mRubberBand = NULL;
|
||||
|
||||
//lines: bail out if there are not at least two vertices
|
||||
if(mTool == CaptureLine && mCaptureList.size() < 2)
|
||||
{
|
||||
//add points to other features to keep topology up-to-date
|
||||
int topologicalEditing = QgsProject::instance()->readNumEntry("Digitizing", "/TopologicalEditing", 0);
|
||||
if(topologicalEditing)
|
||||
mCaptureList.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
//polygons: bail out if there are not at least two vertices
|
||||
if(mTool == CapturePolygon && mCaptureList.size() < 3)
|
||||
{
|
||||
mCaptureList.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
//create QgsFeature with wkb representation
|
||||
QgsFeature* f = new QgsFeature(0,"WKBLineString");
|
||||
unsigned char* wkb;
|
||||
int size;
|
||||
char end=QgsApplication::endian();
|
||||
|
||||
if(mTool == CaptureLine)
|
||||
{
|
||||
if(layerWKBType == QGis::WKBLineString)
|
||||
{
|
||||
vlayer->addTopologicalPoints(f->geometry());
|
||||
size=1+2*sizeof(int)+2*mCaptureList.size()*sizeof(double);
|
||||
wkb= new unsigned char[size];
|
||||
int wkbtype=QGis::WKBLineString;
|
||||
int length=mCaptureList.size();
|
||||
memcpy(&wkb[0],&end,1);
|
||||
memcpy(&wkb[1],&wkbtype, sizeof(int));
|
||||
memcpy(&wkb[1+sizeof(int)],&length, sizeof(int));
|
||||
int position=1+2*sizeof(int);
|
||||
double x,y;
|
||||
for(QList<QgsPoint>::iterator it=mCaptureList.begin();it!=mCaptureList.end();++it)
|
||||
{
|
||||
QgsPoint savePoint = *it;
|
||||
x = savePoint.x();
|
||||
y = savePoint.y();
|
||||
|
||||
memcpy(&wkb[position],&x,sizeof(double));
|
||||
position+=sizeof(double);
|
||||
|
||||
memcpy(&wkb[position],&y,sizeof(double));
|
||||
position+=sizeof(double);
|
||||
}
|
||||
}
|
||||
else if(layerWKBType == QGis::WKBMultiLineString)
|
||||
{
|
||||
size = 1+2*sizeof(int)+1+2*sizeof(int)+2*mCaptureList.size()*sizeof(double);
|
||||
wkb= new unsigned char[size];
|
||||
int position = 0;
|
||||
int wkbtype=QGis::WKBMultiLineString;
|
||||
memcpy(&wkb[position], &end, 1);
|
||||
position += 1;
|
||||
memcpy(&wkb[position], &wkbtype, sizeof(int));
|
||||
position += sizeof(int);
|
||||
int nlines = 1;
|
||||
memcpy(&wkb[position], &nlines, sizeof(int));
|
||||
position += sizeof(int);
|
||||
memcpy(&wkb[position], &end, 1);
|
||||
position += 1;
|
||||
int linewkbtype = QGis::WKBLineString;
|
||||
memcpy(&wkb[position], &linewkbtype, sizeof(int));
|
||||
position += sizeof(int);
|
||||
int length=mCaptureList.size();
|
||||
memcpy(&wkb[position], &length, sizeof(int));
|
||||
position += sizeof(int);
|
||||
double x,y;
|
||||
for(QList<QgsPoint>::iterator it=mCaptureList.begin();it!=mCaptureList.end();++it)
|
||||
{
|
||||
QgsPoint savePoint = *it;
|
||||
x = savePoint.x();
|
||||
y = savePoint.y();
|
||||
|
||||
memcpy(&wkb[position],&x,sizeof(double));
|
||||
position+=sizeof(double);
|
||||
|
||||
memcpy(&wkb[position],&y,sizeof(double));
|
||||
position+=sizeof(double);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(0, QObject::tr("Error"), QObject::tr("Cannot add feature. Unknown WKB type"));
|
||||
return; //unknown wkbtype
|
||||
}
|
||||
f->setGeometryAndOwnership(&wkb[0],size);
|
||||
}
|
||||
else // polygon
|
||||
{
|
||||
if(layerWKBType == QGis::WKBPolygon)
|
||||
{
|
||||
size=1+3*sizeof(int)+2*(mCaptureList.size()+1)*sizeof(double);
|
||||
wkb= new unsigned char[size];
|
||||
int wkbtype=QGis::WKBPolygon;
|
||||
int length=mCaptureList.size()+1;//+1 because the first point is needed twice
|
||||
int numrings=1;
|
||||
memcpy(&wkb[0],&end,1);
|
||||
memcpy(&wkb[1],&wkbtype, sizeof(int));
|
||||
memcpy(&wkb[1+sizeof(int)],&numrings,sizeof(int));
|
||||
memcpy(&wkb[1+2*sizeof(int)],&length, sizeof(int));
|
||||
int position=1+3*sizeof(int);
|
||||
double x,y;
|
||||
QList<QgsPoint>::iterator it;
|
||||
for(it=mCaptureList.begin();it!=mCaptureList.end();++it)
|
||||
{
|
||||
QgsPoint savePoint = *it;
|
||||
x = savePoint.x();
|
||||
y = savePoint.y();
|
||||
|
||||
memcpy(&wkb[position],&x,sizeof(double));
|
||||
position+=sizeof(double);
|
||||
|
||||
memcpy(&wkb[position],&y,sizeof(double));
|
||||
position+=sizeof(double);
|
||||
}
|
||||
// close the polygon
|
||||
it=mCaptureList.begin();
|
||||
QgsPoint savePoint = *it;
|
||||
x = savePoint.x();
|
||||
y = savePoint.y();
|
||||
|
||||
memcpy(&wkb[position],&x,sizeof(double));
|
||||
position+=sizeof(double);
|
||||
|
||||
memcpy(&wkb[position],&y,sizeof(double));
|
||||
}
|
||||
else if(layerWKBType == QGis::WKBMultiPolygon)
|
||||
{
|
||||
size = 2+5*sizeof(int)+2*(mCaptureList.size()+1)*sizeof(double);
|
||||
wkb = new unsigned char[size];
|
||||
int wkbtype = QGis::WKBMultiPolygon;
|
||||
int polygontype = QGis::WKBPolygon;
|
||||
int length = mCaptureList.size()+1;//+1 because the first point is needed twice
|
||||
int numrings = 1;
|
||||
int numpolygons = 1;
|
||||
int position = 0; //pointer position relative to &wkb[0]
|
||||
memcpy(&wkb[position],&end,1);
|
||||
position += 1;
|
||||
memcpy(&wkb[position],&wkbtype, sizeof(int));
|
||||
position += sizeof(int);
|
||||
memcpy(&wkb[position], &numpolygons, sizeof(int));
|
||||
position += sizeof(int);
|
||||
memcpy(&wkb[position], &end, 1);
|
||||
position += 1;
|
||||
memcpy(&wkb[position], &polygontype, sizeof(int));
|
||||
position += sizeof(int);
|
||||
memcpy(&wkb[position], &numrings, sizeof(int));
|
||||
position += sizeof(int);
|
||||
memcpy(&wkb[position], &length, sizeof(int));
|
||||
position += sizeof(int);
|
||||
double x,y;
|
||||
QList<QgsPoint>::iterator it;
|
||||
for(it=mCaptureList.begin();it!=mCaptureList.end();++it)//add the captured points to the polygon
|
||||
{
|
||||
QgsPoint savePoint = *it;
|
||||
x = savePoint.x();
|
||||
y = savePoint.y();
|
||||
|
||||
memcpy(&wkb[position],&x,sizeof(double));
|
||||
position+=sizeof(double);
|
||||
|
||||
memcpy(&wkb[position],&y,sizeof(double));
|
||||
position+=sizeof(double);
|
||||
}
|
||||
// close the polygon
|
||||
it=mCaptureList.begin();
|
||||
QgsPoint savePoint = *it;
|
||||
x = savePoint.x();
|
||||
y = savePoint.y();
|
||||
memcpy(&wkb[position],&x,sizeof(double));
|
||||
position+=sizeof(double);
|
||||
memcpy(&wkb[position],&y,sizeof(double));
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(0, QObject::tr("Error"), QObject::tr("Cannot add feature. Unknown WKB type"));
|
||||
return; //unknown wkbtype
|
||||
}
|
||||
f->setGeometryAndOwnership(&wkb[0],size);
|
||||
|
||||
//is automatic polygon intersection removal activated?
|
||||
int avoidPolygonIntersections = QgsProject::instance()->readNumEntry("Digitizing", "/AvoidPolygonIntersections", 0);
|
||||
|
||||
if(avoidPolygonIntersections != 0)
|
||||
{
|
||||
if(vlayer->removePolygonIntersections(f->geometry()) != 0)
|
||||
{
|
||||
QMessageBox::critical(0, QObject::tr("Error"), QObject::tr("Could not remove polygon intersection"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
delete f;
|
||||
delete mypDialog;
|
||||
|
||||
// delete the elements of mCaptureList
|
||||
mCaptureList.clear();
|
||||
mCanvas->refresh();
|
||||
}
|
||||
}
|
||||
|
||||
// add the fields to the QgsFeature
|
||||
const QgsFieldMap fields = vlayer->pendingFields();
|
||||
for(QgsFieldMap::const_iterator it = fields.begin(); it != fields.end(); ++it)
|
||||
{
|
||||
f->addAttribute(it.key(), provider->getDefaultValue(it.key()));
|
||||
}
|
||||
|
||||
QgsAttributeDialog * mypDialog = new QgsAttributeDialog( vlayer, f );
|
||||
if (mypDialog->exec())
|
||||
{
|
||||
if(vlayer->addFeature(*f))
|
||||
{
|
||||
//add points to other features to keep topology up-to-date
|
||||
int topologicalEditing = QgsProject::instance()->readNumEntry("Digitizing", "/TopologicalEditing", 0);
|
||||
if(topologicalEditing)
|
||||
{
|
||||
vlayer->addTopologicalPoints(f->geometry());
|
||||
}
|
||||
}
|
||||
}
|
||||
delete f;
|
||||
delete mypDialog;
|
||||
|
||||
// delete the elements of mCaptureList
|
||||
mCaptureList.clear();
|
||||
mCanvas->refresh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "qgsspatialrefsys.h"
|
||||
#include "qgsvectordataprovider.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsattributedialog.h"
|
||||
|
||||
#include <QSettings>
|
||||
#include <QMessageBox>
|
||||
@ -73,7 +74,7 @@ void QgsMapToolIdentify::canvasReleaseEvent(QMouseEvent * e)
|
||||
return;
|
||||
}
|
||||
|
||||
QgsMapLayer* layer = mCanvas->currentLayer();
|
||||
mLayer = mCanvas->currentLayer();
|
||||
|
||||
// delete rubber band if there was any
|
||||
delete mRubberBand;
|
||||
@ -81,31 +82,31 @@ void QgsMapToolIdentify::canvasReleaseEvent(QMouseEvent * e)
|
||||
|
||||
// call identify method for selected layer
|
||||
|
||||
if (layer)
|
||||
if (mLayer)
|
||||
{
|
||||
// In the special case of the WMS provider,
|
||||
// coordinates are sent back to the server as pixel coordinates
|
||||
// not the layer's native CRS. So identify on screen coordinates!
|
||||
if (
|
||||
(layer->type() == QgsMapLayer::RASTER)
|
||||
(mLayer->type() == QgsMapLayer::RASTER)
|
||||
&&
|
||||
(dynamic_cast<QgsRasterLayer*>(layer)->providerKey() == "wms")
|
||||
(dynamic_cast<QgsRasterLayer*>(mLayer)->providerKey() == "wms")
|
||||
)
|
||||
{
|
||||
identifyRasterWmsLayer(dynamic_cast<QgsRasterLayer*>(layer), QgsPoint(e->x(), e->y()) );
|
||||
identifyRasterWmsLayer( QgsPoint(e->x(), e->y()) );
|
||||
}
|
||||
else
|
||||
{
|
||||
// convert screen coordinates to map coordinates
|
||||
QgsPoint idPoint = mCanvas->getCoordinateTransform()->toMapCoordinates(e->x(), e->y());
|
||||
|
||||
if (layer->type() == QgsMapLayer::VECTOR)
|
||||
if (mLayer->type() == QgsMapLayer::VECTOR)
|
||||
{
|
||||
identifyVectorLayer(dynamic_cast<QgsVectorLayer*>(layer), idPoint);
|
||||
identifyVectorLayer(idPoint);
|
||||
}
|
||||
else if (layer->type() == QgsMapLayer::RASTER)
|
||||
else if (mLayer->type() == QgsMapLayer::RASTER)
|
||||
{
|
||||
identifyRasterLayer(dynamic_cast<QgsRasterLayer*>(layer), idPoint);
|
||||
identifyRasterLayer(idPoint);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -127,8 +128,9 @@ void QgsMapToolIdentify::canvasReleaseEvent(QMouseEvent * e)
|
||||
}
|
||||
|
||||
|
||||
void QgsMapToolIdentify::identifyRasterLayer(QgsRasterLayer* layer, const QgsPoint& point)
|
||||
void QgsMapToolIdentify::identifyRasterLayer(const QgsPoint& point)
|
||||
{
|
||||
QgsRasterLayer *layer = dynamic_cast<QgsRasterLayer*>(mLayer);
|
||||
if (!layer)
|
||||
return;
|
||||
|
||||
@ -140,7 +142,7 @@ void QgsMapToolIdentify::identifyRasterLayer(QgsRasterLayer* layer, const QgsPoi
|
||||
QgsAttributeAction aa;
|
||||
mResults = new QgsIdentifyResults(aa, mCanvas->window());
|
||||
mResults->setAttribute(Qt::WA_DeleteOnClose);
|
||||
// Be informed when the dialog box is closed so that we can stop using it.
|
||||
// Be informed when the dialog box is closed so that we can stop using it.
|
||||
connect(mResults, SIGNAL(accepted()), this, SLOT(resultsDialogGone()));
|
||||
connect(mResults, SIGNAL(rejected()), this, SLOT(resultsDialogGone()));
|
||||
mResults->restorePosition();
|
||||
@ -166,8 +168,9 @@ void QgsMapToolIdentify::identifyRasterLayer(QgsRasterLayer* layer, const QgsPoi
|
||||
}
|
||||
|
||||
|
||||
void QgsMapToolIdentify::identifyRasterWmsLayer(QgsRasterLayer* layer, const QgsPoint& point)
|
||||
void QgsMapToolIdentify::identifyRasterWmsLayer(const QgsPoint& point)
|
||||
{
|
||||
QgsRasterLayer *layer = dynamic_cast<QgsRasterLayer*>(mLayer);
|
||||
if (!layer)
|
||||
{
|
||||
return;
|
||||
@ -193,7 +196,7 @@ void QgsMapToolIdentify::identifyRasterWmsLayer(QgsRasterLayer* layer, const Qgs
|
||||
|
||||
if(xMinView < xMinLayer)
|
||||
{
|
||||
i = (int)(point.x() - (xMinLayer - xMinView) / mupp);
|
||||
i = (int)(point.x() - (xMinLayer - xMinView) / mupp);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -214,7 +217,7 @@ void QgsMapToolIdentify::identifyRasterWmsLayer(QgsRasterLayer* layer, const Qgs
|
||||
|
||||
if (text.isEmpty())
|
||||
{
|
||||
showError(layer);
|
||||
showError();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -225,8 +228,9 @@ void QgsMapToolIdentify::identifyRasterWmsLayer(QgsRasterLayer* layer, const Qgs
|
||||
viewer->showMessage(); // deletes itself on close
|
||||
}
|
||||
|
||||
void QgsMapToolIdentify::identifyVectorLayer(QgsVectorLayer* layer, const QgsPoint& point)
|
||||
void QgsMapToolIdentify::identifyVectorLayer(const QgsPoint& point)
|
||||
{
|
||||
QgsVectorLayer *layer = dynamic_cast<QgsVectorLayer*>(mLayer);
|
||||
if (!layer)
|
||||
return;
|
||||
|
||||
@ -250,8 +254,7 @@ void QgsMapToolIdentify::identifyVectorLayer(QgsVectorLayer* layer, const QgsPoi
|
||||
//QgsFeature feat;
|
||||
QgsAttributeAction& actions = *layer->actions();
|
||||
QString fieldIndex = layer->displayField();
|
||||
QgsVectorDataProvider* dataProvider = layer->getDataProvider();
|
||||
const QgsFieldMap& fields = dataProvider->fields();
|
||||
const QgsFieldMap& fields = layer->pendingFields();
|
||||
|
||||
// init distance/area calculator
|
||||
QgsDistanceArea calc;
|
||||
@ -259,6 +262,22 @@ void QgsMapToolIdentify::identifyVectorLayer(QgsVectorLayer* layer, const QgsPoi
|
||||
calc.setEllipsoid(ellipsoid);
|
||||
calc.setSourceSRS(layer->srs().srsid());
|
||||
|
||||
mFeatureList.clear();
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
|
||||
layer->select(layer->pendingAllAttributesList(), r, true);
|
||||
QgsFeature f;
|
||||
while( layer->getNextFeature(f) )
|
||||
mFeatureList << f;
|
||||
|
||||
QApplication::restoreOverrideCursor();
|
||||
|
||||
if( layer->isEditable() && mFeatureList.size()==1 )
|
||||
{
|
||||
editFeature(mFeatureList[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
// display features falling within the search radius
|
||||
if(!mResults)
|
||||
{
|
||||
@ -268,6 +287,8 @@ void QgsMapToolIdentify::identifyVectorLayer(QgsVectorLayer* layer, const QgsPoi
|
||||
connect(mResults, SIGNAL(accepted()), this, SLOT(resultsDialogGone()));
|
||||
connect(mResults, SIGNAL(rejected()), this, SLOT(resultsDialogGone()));
|
||||
connect(mResults, SIGNAL(selectedFeatureChanged(int)), this, SLOT(highlightFeature(int)));
|
||||
connect(mResults, SIGNAL(editFeature(int)), this, SLOT(editFeature(int)));
|
||||
|
||||
// restore the identify window position and show it
|
||||
mResults->restorePosition();
|
||||
}
|
||||
@ -281,12 +302,9 @@ void QgsMapToolIdentify::identifyVectorLayer(QgsVectorLayer* layer, const QgsPoi
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
|
||||
int lastFeatureId = 0;
|
||||
QgsFeatureList::iterator f_it = mFeatureList.begin();
|
||||
|
||||
QList<QgsFeature> featureList;
|
||||
layer->featuresInRectangle(r, featureList, true, true);
|
||||
QList<QgsFeature>::iterator f_it = featureList.begin();
|
||||
|
||||
for(; f_it != featureList.end(); ++f_it)
|
||||
for(; f_it != mFeatureList.end(); ++f_it)
|
||||
{
|
||||
featureCount++;
|
||||
|
||||
@ -294,6 +312,10 @@ void QgsMapToolIdentify::identifyVectorLayer(QgsVectorLayer* layer, const QgsPoi
|
||||
featureNode->setData(0, Qt::UserRole, QVariant(f_it->featureId())); // save feature id
|
||||
lastFeatureId = f_it->featureId();
|
||||
featureNode->setText(0, fieldIndex);
|
||||
|
||||
if( layer->isEditable() )
|
||||
mResults->addEdit( featureNode, f_it->featureId() );
|
||||
|
||||
const QgsAttributeMap& attr = f_it->attributeMap();
|
||||
|
||||
for (QgsAttributeMap::const_iterator it = attr.begin(); it != attr.end(); ++it)
|
||||
@ -340,13 +362,12 @@ void QgsMapToolIdentify::identifyVectorLayer(QgsVectorLayer* layer, const QgsPoi
|
||||
mResults->addDerivedAttribute(featureNode, "Y", str);
|
||||
}
|
||||
|
||||
// Add actions
|
||||
// Add actions
|
||||
QgsAttributeAction::aIter iter = actions.begin();
|
||||
for (register int i = 0; iter != actions.end(); ++iter, ++i)
|
||||
{
|
||||
mResults->addAction( featureNode, i, QObject::tr("action"), iter->name() );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QgsDebugMsg("Feature count on identify: " + QString::number(featureCount));
|
||||
@ -354,7 +375,7 @@ void QgsMapToolIdentify::identifyVectorLayer(QgsVectorLayer* layer, const QgsPoi
|
||||
//also test the not commited features //todo: eliminate copy past code
|
||||
|
||||
mResults->setTitle(layer->name() + " - " + QString::number(featureCount) + QObject::tr(" features found"));
|
||||
if (featureCount == 1)
|
||||
if (featureCount == 1)
|
||||
{
|
||||
mResults->showAllAttributes();
|
||||
mResults->setTitle(layer->name() + " - " + QObject::tr(" 1 feature found") );
|
||||
@ -369,228 +390,14 @@ void QgsMapToolIdentify::identifyVectorLayer(QgsVectorLayer* layer, const QgsPoi
|
||||
{
|
||||
QString title = layer->name();
|
||||
title += QString( tr("- %1 features found","Identify results window title",featureCount) ).arg(featureCount);
|
||||
mResults->setTitle(title);
|
||||
mResults->setTitle(title);
|
||||
}
|
||||
QApplication::restoreOverrideCursor();
|
||||
|
||||
mResults->show();
|
||||
}
|
||||
|
||||
#if 0 //MH: old state of the function
|
||||
void QgsMapToolIdentify::identifyVectorLayer(QgsVectorLayer* layer, const QgsPoint& point)
|
||||
{
|
||||
if (!layer)
|
||||
return;
|
||||
|
||||
// load identify radius from settings
|
||||
QSettings settings;
|
||||
double identifyValue = settings.value("/Map/identifyRadius", QGis::DEFAULT_IDENTIFY_RADIUS).toDouble();
|
||||
QString ellipsoid = settings.readEntry("/qgis/measure/ellipsoid", "WGS84");
|
||||
|
||||
// create the search rectangle
|
||||
double searchRadius = mCanvas->extent().width() * (identifyValue/100.0);
|
||||
|
||||
QgsRect r;
|
||||
r.setXmin(point.x() - searchRadius);
|
||||
r.setXmax(point.x() + searchRadius);
|
||||
r.setYmin(point.y() - searchRadius);
|
||||
r.setYmax(point.y() + searchRadius);
|
||||
|
||||
r = toLayerCoords(layer, r);
|
||||
|
||||
int featureCount = 0;
|
||||
QgsFeature feat;
|
||||
QgsAttributeAction& actions = *layer->actions();
|
||||
QString fieldIndex = layer->displayField();
|
||||
QgsVectorDataProvider* dataProvider = layer->getDataProvider();
|
||||
QgsAttributeList allAttributes = dataProvider->allAttributesList();
|
||||
const QgsFieldMap& fields = dataProvider->fields();
|
||||
|
||||
dataProvider->select(allAttributes, r, true, true);
|
||||
|
||||
// init distance/area calculator
|
||||
QgsDistanceArea calc;
|
||||
calc.setProjectionsEnabled(mCanvas->projectionsEnabled()); // project?
|
||||
calc.setEllipsoid(ellipsoid);
|
||||
calc.setSourceSRS(layer->srs().srsid());
|
||||
|
||||
if ( !layer->isEditable() )
|
||||
{
|
||||
// display features falling within the search radius
|
||||
if(!mResults)
|
||||
{
|
||||
mResults = new QgsIdentifyResults(actions, mCanvas->window());
|
||||
mResults->setAttribute(Qt::WA_DeleteOnClose);
|
||||
// Be informed when the dialog box is closed so that we can stop using it.
|
||||
connect(mResults, SIGNAL(accepted()), this, SLOT(resultsDialogGone()));
|
||||
connect(mResults, SIGNAL(rejected()), this, SLOT(resultsDialogGone()));
|
||||
connect(mResults, SIGNAL(selectedFeatureChanged(int)), this, SLOT(highlightFeature(int)));
|
||||
// restore the identify window position and show it
|
||||
mResults->restorePosition();
|
||||
}
|
||||
else
|
||||
{
|
||||
mResults->raise();
|
||||
mResults->clear();
|
||||
mResults->setActions(actions);
|
||||
}
|
||||
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
|
||||
int lastFeatureId = 0;
|
||||
|
||||
QTreeWidgetItem *click = mResults->addNode(tr("(clicked coordinate)"));
|
||||
click->setText(1, point.stringRep());
|
||||
|
||||
while (dataProvider->getNextFeature(feat))
|
||||
{
|
||||
featureCount++;
|
||||
|
||||
QTreeWidgetItem* featureNode = mResults->addNode("foo");
|
||||
featureNode->setData(0, Qt::UserRole, QVariant(feat.featureId())); // save feature id
|
||||
lastFeatureId = feat.featureId();
|
||||
featureNode->setText(0, fieldIndex);
|
||||
const QgsAttributeMap& attr = feat.attributeMap();
|
||||
|
||||
for (QgsAttributeMap::const_iterator it = attr.begin(); it != attr.end(); ++it)
|
||||
{
|
||||
//QgsDebugMsg(it->fieldName() + " == " + fieldIndex);
|
||||
|
||||
if (fields[it.key()].name() == fieldIndex)
|
||||
{
|
||||
featureNode->setText(1, it->toString());
|
||||
}
|
||||
mResults->addAttribute(featureNode, fields[it.key()].name(), it->toString());
|
||||
}
|
||||
|
||||
// Calculate derived attributes and insert:
|
||||
// measure distance or area depending on geometry type
|
||||
if (layer->vectorType() == QGis::Line)
|
||||
{
|
||||
double dist = calc.measure(feat.geometry());
|
||||
QString str = calc.textUnit(dist, 3, mCanvas->mapUnits(), false);
|
||||
mResults->addDerivedAttribute(featureNode, QObject::tr("Length"), str);
|
||||
}
|
||||
else if (layer->vectorType() == QGis::Polygon)
|
||||
{
|
||||
double area = calc.measure(feat.geometry());
|
||||
QString str = calc.textUnit(area, 3, mCanvas->mapUnits(), true);
|
||||
mResults->addDerivedAttribute(featureNode, QObject::tr("Area"), str);
|
||||
}
|
||||
|
||||
// Add actions
|
||||
QgsAttributeAction::aIter iter = actions.begin();
|
||||
for (register int i = 0; iter != actions.end(); ++iter, ++i)
|
||||
{
|
||||
mResults->addAction( featureNode, i, QObject::tr("action"), iter->name() );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QgsDebugMsg("Feature count on identify: " + QString::number(featureCount));
|
||||
|
||||
//also test the not commited features //todo: eliminate copy past code
|
||||
|
||||
mResults->setTitle(layer->name() + " - " + QString::number(featureCount) + QObject::tr(" features found"));
|
||||
if (featureCount == 1)
|
||||
{
|
||||
mResults->showAllAttributes();
|
||||
mResults->setTitle(layer->name() + " - " + QObject::tr(" 1 feature found") );
|
||||
highlightFeature(lastFeatureId);
|
||||
}
|
||||
else if (featureCount == 0)
|
||||
{
|
||||
mResults->setTitle(layer->name() + " - " + QObject::tr("No features found") );
|
||||
mResults->setMessage ( QObject::tr("No features found"), QObject::tr("No features were found in the active layer at the point you clicked") );
|
||||
}
|
||||
else
|
||||
{
|
||||
QString title = layer->name();
|
||||
title += QString( tr("- %1 features found","Identify results window title",featureCount) ).arg(featureCount);
|
||||
mResults->setTitle(title);
|
||||
}
|
||||
QApplication::restoreOverrideCursor();
|
||||
|
||||
mResults->show();
|
||||
}
|
||||
else // ( layer->isEditable() )
|
||||
{
|
||||
// Edit attributes
|
||||
// TODO: what to do if more features were selected? - nearest?
|
||||
QgsChangedAttributesMap& changedAttributes = layer->changedAttributes();
|
||||
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
|
||||
if (dataProvider->getNextFeature(feat))
|
||||
{
|
||||
// these are the values to populate the dialog with
|
||||
// start off with list of committed attribute values
|
||||
QgsAttributeMap old = feat.attributeMap();
|
||||
|
||||
// Test if this feature already changed since the last commit
|
||||
|
||||
QgsChangedAttributesMap::iterator it = changedAttributes.find(feat.featureId());
|
||||
if ( it != changedAttributes.end() )
|
||||
{
|
||||
// Yes, this feature already has in-memory attribute changes
|
||||
|
||||
// go through and apply the modified-but-not-committed values
|
||||
QgsAttributeMap oldattr = *it;
|
||||
int index=0;
|
||||
for (QgsAttributeMap::const_iterator oldit = old.begin(); oldit != old.end(); ++oldit)
|
||||
{
|
||||
QgsAttributeMap::iterator ait = oldattr.find( oldit.key() );
|
||||
if ( ait != oldattr.end() )
|
||||
{
|
||||
// replace the committed value with the
|
||||
// modified-but-not-committed value
|
||||
old[index] = *ait;
|
||||
}
|
||||
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
QApplication::restoreOverrideCursor();
|
||||
|
||||
// Show the attribute value editing dialog
|
||||
QgsAttributeDialog ad( dataProvider->fields(), old );
|
||||
|
||||
if (ad.exec() == QDialog::Accepted)
|
||||
{
|
||||
|
||||
int i = 0;
|
||||
for (QgsAttributeMap::const_iterator oldit = old.begin(); oldit != old.end(); ++oldit, ++i)
|
||||
{
|
||||
// only apply changed values if they were edited by the user
|
||||
if (ad.isDirty(i))
|
||||
{
|
||||
QgsDebugMsg("found a changed attribute: " + QString::number(i) + " = " + ad.value(i));
|
||||
|
||||
QgsAttributeMap& chattr = changedAttributes[ feat.featureId() ];
|
||||
chattr[i] = ad.value(i);
|
||||
|
||||
// propagate "dirtyness" to the layer
|
||||
layer->setModified();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QApplication::restoreOverrideCursor();
|
||||
QMessageBox::information(0, tr("No features found"),
|
||||
tr("<p>No features were found within the search radius. "
|
||||
"Note that it is currently not possible to use the "
|
||||
"identify tool on unsaved features.</p>"));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void QgsMapToolIdentify::showError(QgsMapLayer * mapLayer)
|
||||
void QgsMapToolIdentify::showError()
|
||||
{
|
||||
// QMessageBox::warning(
|
||||
// this,
|
||||
@ -600,10 +407,10 @@ void QgsMapToolIdentify::showError(QgsMapLayer * mapLayer)
|
||||
// );
|
||||
|
||||
QgsMessageViewer * mv = new QgsMessageViewer();
|
||||
mv->setWindowTitle( mapLayer->errorCaptionString() );
|
||||
mv->setWindowTitle( mLayer->errorCaptionString() );
|
||||
mv->setMessageAsPlainText(
|
||||
QObject::tr("Could not identify objects on") + " " + mapLayer->name() + " " + QObject::tr("because") + ":\n" +
|
||||
mapLayer->errorString()
|
||||
QObject::tr("Could not identify objects on") + " " + mLayer->name() + " " + QObject::tr("because") + ":\n" +
|
||||
mLayer->errorString()
|
||||
);
|
||||
mv->exec(); // deletes itself on close
|
||||
}
|
||||
@ -625,7 +432,7 @@ void QgsMapToolIdentify::deactivate()
|
||||
|
||||
void QgsMapToolIdentify::highlightFeature(int featureId)
|
||||
{
|
||||
QgsVectorLayer* layer = dynamic_cast<QgsVectorLayer*>(mCanvas->currentLayer());
|
||||
QgsVectorLayer* layer = dynamic_cast<QgsVectorLayer*>(mLayer);
|
||||
if (!layer)
|
||||
return;
|
||||
|
||||
@ -653,3 +460,41 @@ void QgsMapToolIdentify::highlightFeature(int featureId)
|
||||
mRubberBand->show();
|
||||
}
|
||||
}
|
||||
|
||||
void QgsMapToolIdentify::editFeature(int featureId)
|
||||
{
|
||||
for(QgsFeatureList::iterator it=mFeatureList.begin(); it!=mFeatureList.end(); it++)
|
||||
{
|
||||
if( it->featureId() == featureId )
|
||||
{
|
||||
editFeature( *it );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsMapToolIdentify::editFeature(QgsFeature &f)
|
||||
{
|
||||
QgsVectorLayer* layer = dynamic_cast<QgsVectorLayer*>(mLayer);
|
||||
if (!layer)
|
||||
return;
|
||||
|
||||
if (!layer->isEditable() )
|
||||
return;
|
||||
|
||||
QgsAttributeMap src = f.attributeMap();
|
||||
|
||||
QgsAttributeDialog *ad = new QgsAttributeDialog(layer, &f);
|
||||
if (ad->exec())
|
||||
{
|
||||
const QgsAttributeMap &dst = f.attributeMap();
|
||||
|
||||
for(QgsAttributeMap::const_iterator it=dst.begin(); it!=dst.end(); it++)
|
||||
{
|
||||
if( !src.contains( it.key() ) || it.value()!=src[it.key()] )
|
||||
layer->changeAttributeValue( f.featureId(), it.key(), it.value().toString() );
|
||||
}
|
||||
}
|
||||
delete ad;
|
||||
mCanvas->refresh();
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include "qgsmaptool.h"
|
||||
#include "qgspoint.h"
|
||||
#include "qgsfeature.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
@ -60,6 +61,9 @@ class QgsMapToolIdentify : public QgsMapTool
|
||||
public slots:
|
||||
//! creates rubberband on top of the feature to highlight it
|
||||
void highlightFeature(int featureId);
|
||||
|
||||
//! edit a feature
|
||||
void editFeature(int featureId);
|
||||
|
||||
private:
|
||||
|
||||
@ -68,7 +72,7 @@ class QgsMapToolIdentify : public QgsMapTool
|
||||
*
|
||||
* \param point[in] The coordinate (as the CRS of the raster layer)
|
||||
*/
|
||||
void identifyRasterLayer(QgsRasterLayer* layer, const QgsPoint& point);
|
||||
void identifyRasterLayer(const QgsPoint& point);
|
||||
|
||||
/**
|
||||
* \brief function for identifying a pixel in a OGC WMS raster layer
|
||||
@ -78,18 +82,20 @@ class QgsMapToolIdentify : public QgsMapTool
|
||||
* \note WMS Servers prefer to receive coordinates in image space not CRS space, therefore
|
||||
* this special variant of identifyRasterLayer.
|
||||
*/
|
||||
void identifyRasterWmsLayer(QgsRasterLayer* layer, const QgsPoint& point);
|
||||
void identifyRasterWmsLayer(const QgsPoint& point);
|
||||
|
||||
/**
|
||||
* \brief function for identifying features at a coordinate in a vector layer
|
||||
*
|
||||
* \param point[in] The coordinate (as the CRS of the vector layer)
|
||||
*/
|
||||
void identifyVectorLayer(QgsVectorLayer* layer, const QgsPoint& point);
|
||||
void identifyVectorLayer(const QgsPoint& point);
|
||||
|
||||
//! show whatever error is exposed by the QgsMapLayer.
|
||||
void showError(QgsMapLayer * mapLayer);
|
||||
void showError();
|
||||
|
||||
//! edit a feature
|
||||
void editFeature(QgsFeature &f);
|
||||
|
||||
//! Pointer to the identify results dialog for name/value pairs
|
||||
QgsIdentifyResults *mResults;
|
||||
@ -97,6 +103,11 @@ class QgsMapToolIdentify : public QgsMapTool
|
||||
//! Rubber band for highlighting identified feature
|
||||
QgsRubberBand* mRubberBand;
|
||||
|
||||
QgsMapLayer *mLayer;
|
||||
|
||||
//! list of identified features
|
||||
QgsFeatureList mFeatureList;
|
||||
|
||||
private slots:
|
||||
// Let us know when the QgsIdentifyResults dialog box has been closed
|
||||
void resultsDialogGone();
|
||||
|
@ -56,65 +56,65 @@ void QgsMapToolMoveFeature::canvasPressEvent(QMouseEvent * e)
|
||||
|
||||
QgsVectorLayer* vlayer = currentVectorLayer();
|
||||
if(!vlayer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(!vlayer->isEditable())
|
||||
{
|
||||
QMessageBox::information(0, QObject::tr("Layer not editable"), \
|
||||
QObject::tr("Cannot edit the vector layer. To make it editable, go to the file item " \
|
||||
"of the layer, right click and check 'Allow Editing'."));
|
||||
return;
|
||||
}
|
||||
{
|
||||
QMessageBox::information(0, QObject::tr("Layer not editable"),
|
||||
QObject::tr("Cannot edit the vector layer. To make it editable, go to the file item "
|
||||
"of the layer, right click and check 'Allow Editing'."));
|
||||
return;
|
||||
}
|
||||
|
||||
//find first geometry under mouse cursor and store iterator to it
|
||||
QgsPoint layerCoords = toLayerCoords((QgsMapLayer*)vlayer, e->pos());
|
||||
QSettings settings;
|
||||
double searchRadius = settings.value("/qgis/digitizing/search_radius_vertex_edit", 10).toDouble();
|
||||
QgsRect selectRect(layerCoords.x()-searchRadius, layerCoords.y()-searchRadius, \
|
||||
layerCoords.x()+searchRadius, layerCoords.y()+searchRadius);
|
||||
QgsRect selectRect(layerCoords.x()-searchRadius, layerCoords.y()-searchRadius,
|
||||
layerCoords.x()+searchRadius, layerCoords.y()+searchRadius);
|
||||
|
||||
QList<QgsFeature> featureList;
|
||||
vlayer->featuresInRectangle(selectRect, featureList, true, false);
|
||||
|
||||
if(featureList.size() > 0)
|
||||
vlayer->select(QgsAttributeList(), selectRect, true);
|
||||
|
||||
//find the closest feature
|
||||
QgsGeometry* pointGeometry = QgsGeometry::fromPoint(layerCoords);
|
||||
if(!pointGeometry)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
double minDistance = std::numeric_limits<double>::max();
|
||||
|
||||
QgsFeature cf;
|
||||
QgsFeature f;
|
||||
while( vlayer->getNextFeature(f) )
|
||||
{
|
||||
if(f.geometry())
|
||||
{
|
||||
//find the closest feature
|
||||
QgsGeometry* pointGeometry = QgsGeometry::fromPoint(layerCoords);
|
||||
if(!pointGeometry)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QList<QgsFeature>::iterator closestFeatureIt;
|
||||
double minDistance = std::numeric_limits<double>::max();
|
||||
double currentDistance;
|
||||
|
||||
QList<QgsFeature>::iterator it = featureList.begin();
|
||||
for(; it != featureList.end(); ++it)
|
||||
{
|
||||
if(it->geometry())
|
||||
{
|
||||
currentDistance = pointGeometry->distance(*(it->geometry()));
|
||||
if(currentDistance < minDistance)
|
||||
{
|
||||
minDistance = currentDistance;
|
||||
closestFeatureIt = it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mStartPointMapCoords = toMapCoords(e->pos());
|
||||
mMovedFeature = closestFeatureIt->featureId(); //todo: take the closest feature, not the first one...
|
||||
mRubberBand = createRubberBand();
|
||||
mRubberBand->setToGeometry(closestFeatureIt->geometry(), *vlayer);
|
||||
mRubberBand->setColor(Qt::red);
|
||||
mRubberBand->setWidth(2);
|
||||
mRubberBand->show();
|
||||
|
||||
delete pointGeometry;
|
||||
double currentDistance = pointGeometry->distance(*f.geometry());
|
||||
if(currentDistance < minDistance)
|
||||
{
|
||||
minDistance = currentDistance;
|
||||
cf = f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( minDistance==std::numeric_limits<double>::max() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mStartPointMapCoords = toMapCoords(e->pos());
|
||||
mMovedFeature = cf.featureId(); //todo: take the closest feature, not the first one...
|
||||
mRubberBand = createRubberBand();
|
||||
mRubberBand->setToGeometry( cf.geometry(), *vlayer);
|
||||
mRubberBand->setColor(Qt::red);
|
||||
mRubberBand->setWidth(2);
|
||||
mRubberBand->show();
|
||||
|
||||
delete pointGeometry;
|
||||
}
|
||||
|
||||
void QgsMapToolMoveFeature::canvasReleaseEvent(QMouseEvent * e)
|
||||
|
@ -49,7 +49,6 @@ QgsOptions::QgsOptions(QWidget *parent, Qt::WFlags fl) :
|
||||
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
|
||||
connect(this, SIGNAL(accepted()), this, SLOT(saveOptions()));
|
||||
|
||||
qparent = parent;
|
||||
// read the current browser and set it
|
||||
QSettings settings;
|
||||
#ifdef QGISDEBUG
|
||||
@ -116,6 +115,7 @@ QgsOptions::QgsOptions(QWidget *parent, Qt::WFlags fl) :
|
||||
chkAddedVisibility->setChecked(settings.value("/qgis/new_layers_visible",true).toBool());
|
||||
cbxLegendClassifiers->setChecked(settings.value("/qgis/showLegendClassifiers",false).toBool());
|
||||
cbxHideSplash->setChecked(settings.value("/qgis/hideSplash",false).toBool());
|
||||
cbxAttributeTableDocked->setChecked(settings.value("/qgis/dockAttributeTable",false).toBool());
|
||||
|
||||
//set the colour for selections
|
||||
int myRed = settings.value("/qgis/default_selection_color_red",255).toInt();
|
||||
@ -239,7 +239,7 @@ void QgsOptions::themeChanged(const QString &newThemeName)
|
||||
{
|
||||
// Slot to change the theme as user scrolls through the choices
|
||||
QString newt = newThemeName;
|
||||
((QgisApp*)qparent)->setTheme(newt);
|
||||
QgisApp::instance()->setTheme(newt);
|
||||
}
|
||||
QString QgsOptions::theme()
|
||||
{
|
||||
@ -260,6 +260,7 @@ void QgsOptions::saveOptions()
|
||||
settings.setValue("/Map/identifyRadius", spinBoxIdentifyValue->value());
|
||||
settings.setValue("/qgis/showLegendClassifiers",cbxLegendClassifiers->isChecked());
|
||||
settings.setValue("/qgis/hideSplash",cbxHideSplash->isChecked());
|
||||
settings.setValue("/qgis/dockAttributeTable",cbxAttributeTableDocked->isChecked());
|
||||
settings.setValue("/qgis/new_layers_visible",chkAddedVisibility->isChecked());
|
||||
settings.setValue("/qgis/enable_anti_aliasing",chkAntiAliasing->isChecked());
|
||||
settings.setValue("/qgis/use_qimage_to_render", !(chkUseQPixmap->isChecked()));
|
||||
|
@ -93,9 +93,6 @@ class QgsOptions :public QDialog, private Ui::QgsOptionsBase
|
||||
//
|
||||
QStringList i18nList();
|
||||
|
||||
//! Pointer to our parent
|
||||
QWidget *qparent;
|
||||
|
||||
//!Global default projection used for new layers added that have no projection
|
||||
long mGlobalSRSID;
|
||||
|
||||
|
@ -43,10 +43,9 @@
|
||||
static long DEFAULT_WMS_EPSG = 4326; // WGS 84
|
||||
|
||||
|
||||
QgsServerSourceSelect::QgsServerSourceSelect(QgisApp * app, QWidget * parent, Qt::WFlags fl)
|
||||
QgsServerSourceSelect::QgsServerSourceSelect(QWidget * parent, Qt::WFlags fl)
|
||||
: QDialog(parent, fl),
|
||||
m_Epsg(DEFAULT_WMS_EPSG),
|
||||
qgisApp(app),
|
||||
mWmsProvider(0)
|
||||
{
|
||||
setupUi(this);
|
||||
|
@ -44,7 +44,7 @@ class QgsServerSourceSelect : public QDialog, private Ui::QgsServerSourceSelectB
|
||||
public:
|
||||
|
||||
//! Constructor
|
||||
QgsServerSourceSelect(QgisApp *app, QWidget *parent = 0, Qt::WFlags fl = QgisGui::ModalDialogFlags);
|
||||
QgsServerSourceSelect(QWidget *parent = 0, Qt::WFlags fl = QgisGui::ModalDialogFlags);
|
||||
//! Destructor
|
||||
~QgsServerSourceSelect();
|
||||
//! Populate the connection list combo box
|
||||
@ -173,9 +173,6 @@ private:
|
||||
//! The mime type, the text to use in the button and a unique number
|
||||
QMap<QString, QPair<QString, int> > m_PotentialFormats;
|
||||
|
||||
//! Pointer to the qgis application mainwindow
|
||||
QgisApp *qgisApp;
|
||||
|
||||
//! The widget that controls the image format radio buttons
|
||||
QButtonGroup* m_imageFormatGroup;
|
||||
QHBoxLayout* m_imageFormatLayout;
|
||||
|
@ -19,6 +19,7 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "qgisapp.h"
|
||||
#include "qgsapplication.h"
|
||||
#include "qgsattributeactiondialog.h"
|
||||
#include "qgscontexthelp.h"
|
||||
@ -32,7 +33,6 @@
|
||||
#include "qgsproject.h"
|
||||
#include "qgssinglesymboldialog.h"
|
||||
#include "qgsuniquevaluedialog.h"
|
||||
#include "qgsvectordataprovider.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsvectorlayerproperties.h"
|
||||
#include "qgsconfig.h"
|
||||
@ -48,15 +48,18 @@
|
||||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QSettings>
|
||||
#include <QComboBox>
|
||||
#include <QCheckBox>
|
||||
|
||||
#if QT_VERSION < 0x040300
|
||||
#define toPlainText() text()
|
||||
#endif
|
||||
|
||||
|
||||
QgsVectorLayerProperties::QgsVectorLayerProperties(QgsVectorLayer * lyr,
|
||||
QWidget * parent,
|
||||
Qt::WFlags fl)
|
||||
QgsVectorLayerProperties::QgsVectorLayerProperties(
|
||||
QgsVectorLayer *lyr,
|
||||
QWidget * parent,
|
||||
Qt::WFlags fl)
|
||||
: QDialog(parent, fl),
|
||||
layer(lyr),
|
||||
mRendererDialog(0)
|
||||
@ -66,6 +69,21 @@ QgsVectorLayerProperties::QgsVectorLayerProperties(QgsVectorLayer * lyr,
|
||||
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
|
||||
connect(buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(apply()));
|
||||
connect(this, SIGNAL(accepted()), this, SLOT(apply()));
|
||||
connect(mAddAttributeButton, SIGNAL(clicked()), this, SLOT(addAttribute()));
|
||||
connect(mDeleteAttributeButton, SIGNAL(clicked()), this, SLOT(deleteAttribute()));
|
||||
|
||||
connect(mToggleEditingButton, SIGNAL(clicked()), this, SLOT(toggleEditing()));
|
||||
connect(this, SIGNAL(toggleEditing(QgsMapLayer*)),
|
||||
QgisApp::instance(), SLOT(toggleEditing(QgsMapLayer*)));
|
||||
|
||||
connect(layer, SIGNAL(editingStarted()), this, SLOT(editingToggled()));
|
||||
connect(layer, SIGNAL(editingStopped()), this, SLOT(editingToggled()));
|
||||
connect(layer, SIGNAL(attributeAdded(int)), this, SLOT(attributeAdded(int)));
|
||||
connect(layer, SIGNAL(attributeDeleted(int)), this, SLOT(attributeDeleted(int)));
|
||||
|
||||
mAddAttributeButton->setIcon(QgisApp::getThemeIcon("/mActionNewAttribute.png"));
|
||||
mDeleteAttributeButton->setIcon(QgisApp::getThemeIcon("/mActionDeleteAttribute.png"));
|
||||
mToggleEditingButton->setIcon(QgisApp::getThemeIcon("/mActionToggleEditing.png"));
|
||||
|
||||
// Create the Label dialog tab
|
||||
QVBoxLayout *layout = new QVBoxLayout( labelOptionsFrame );
|
||||
@ -73,18 +91,31 @@ QgsVectorLayerProperties::QgsVectorLayerProperties(QgsVectorLayer * lyr,
|
||||
labelDialog = new QgsLabelDialog ( layer->label(), labelOptionsFrame);
|
||||
layout->addWidget( labelDialog );
|
||||
labelOptionsFrame->setLayout(layout);
|
||||
connect(labelDialog, SIGNAL(labelSourceSet()),
|
||||
this, SLOT(setLabelCheckBox()));
|
||||
connect(labelDialog, SIGNAL(labelSourceSet()), this, SLOT(setLabelCheckBox()));
|
||||
|
||||
// Create the Actions dialog tab
|
||||
QgsVectorDataProvider *dp = dynamic_cast<QgsVectorDataProvider *>(layer->getDataProvider());
|
||||
QVBoxLayout *actionLayout = new QVBoxLayout( actionOptionsFrame );
|
||||
actionLayout->setMargin(0);
|
||||
QgsFieldMap fields = dp->fields();
|
||||
actionDialog = new QgsAttributeActionDialog ( layer->actions(), fields,
|
||||
actionOptionsFrame );
|
||||
const QgsFieldMap &fields = layer->pendingFields();
|
||||
actionDialog = new QgsAttributeActionDialog ( layer->actions(), fields, actionOptionsFrame );
|
||||
actionLayout->addWidget( actionDialog );
|
||||
|
||||
tblAttributes->setColumnCount(8);
|
||||
tblAttributes->setRowCount( fields.size() );
|
||||
tblAttributes->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr("id") ) );
|
||||
tblAttributes->setHorizontalHeaderItem( 1, new QTableWidgetItem( tr("name") ) );
|
||||
tblAttributes->setHorizontalHeaderItem( 2, new QTableWidgetItem( tr("type") ) );
|
||||
tblAttributes->setHorizontalHeaderItem( 3, new QTableWidgetItem( tr("length") ) );
|
||||
tblAttributes->setHorizontalHeaderItem( 4, new QTableWidgetItem( tr("precision") ) );
|
||||
tblAttributes->setHorizontalHeaderItem( 5, new QTableWidgetItem( tr("comment") ) );
|
||||
tblAttributes->setHorizontalHeaderItem( 6, new QTableWidgetItem( tr("edit widget") ) );
|
||||
tblAttributes->setHorizontalHeaderItem( 7, new QTableWidgetItem( tr("values") ) );
|
||||
|
||||
tblAttributes->setSelectionBehavior( QAbstractItemView::SelectRows );
|
||||
tblAttributes->setSelectionMode( QAbstractItemView::MultiSelection );
|
||||
|
||||
loadRows();
|
||||
|
||||
reset();
|
||||
if(layer->getDataProvider())//enable spatial index button group if supported by provider
|
||||
{
|
||||
@ -95,18 +126,169 @@ QgsVectorLayerProperties::QgsVectorLayerProperties(QgsVectorLayer * lyr,
|
||||
}
|
||||
}
|
||||
|
||||
updateButtons();
|
||||
|
||||
leSpatialRefSys->setText(layer->srs().proj4String());
|
||||
leSpatialRefSys->setCursorPosition(0);
|
||||
|
||||
connect(sliderTransparency, SIGNAL(valueChanged(int)), this, SLOT(sliderTransparency_valueChanged(int)));
|
||||
|
||||
tabWidget->setCurrentIndex(0);
|
||||
} // QgsVectorLayerProperties ctor
|
||||
|
||||
void QgsVectorLayerProperties::loadRows()
|
||||
{
|
||||
const QgsFieldMap &fields = layer->pendingFields();
|
||||
|
||||
int row=0;
|
||||
for(QgsFieldMap::const_iterator it=fields.begin(); it!=fields.end(); it++, row++)
|
||||
setRow( row, it.key(), it.value() );
|
||||
|
||||
tblAttributes->resizeColumnsToContents();
|
||||
}
|
||||
|
||||
void QgsVectorLayerProperties::setRow(int row, int idx, const QgsField &field)
|
||||
{
|
||||
tblAttributes->setItem(row, 0, new QTableWidgetItem( QString::number(idx) ) );
|
||||
tblAttributes->setItem(row, 1, new QTableWidgetItem( field.name() ) );
|
||||
tblAttributes->setItem(row, 2, new QTableWidgetItem( field.typeName() ) );
|
||||
tblAttributes->setItem(row, 3, new QTableWidgetItem( QString::number( field.length() ) ) );
|
||||
tblAttributes->setItem(row, 4, new QTableWidgetItem( QString::number( field.precision() ) ) );
|
||||
tblAttributes->setItem(row, 5, new QTableWidgetItem( field.comment() ) );
|
||||
|
||||
for(int i=0; i<6; i++)
|
||||
tblAttributes->item(row, i)->setFlags( tblAttributes->item(row, i)->flags() & ~Qt::ItemIsEditable );
|
||||
|
||||
QComboBox *cb = new QComboBox();
|
||||
cb->addItem( tr("line edit"), QgsVectorLayer::LineEdit);
|
||||
cb->addItem( tr("unique values"), QgsVectorLayer::UniqueValues);
|
||||
cb->addItem( tr("unique values (editable)"), QgsVectorLayer::UniqueValuesEditable);
|
||||
cb->addItem( tr("value map"), QgsVectorLayer::ValueMap);
|
||||
cb->addItem( tr("classification"), QgsVectorLayer::Classification);
|
||||
cb->addItem( tr("range"), QgsVectorLayer::Range);
|
||||
cb->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow);
|
||||
cb->setCurrentIndex( layer->editType( idx ) );
|
||||
|
||||
tblAttributes->setCellWidget(row, 6, cb );
|
||||
|
||||
if( layer->editType(idx)==QgsVectorLayer::ValueMap )
|
||||
{
|
||||
// TODO: create a gui for value maps
|
||||
QStringList mapList;
|
||||
QMap<QString, QVariant> &map = layer->valueMap( idx );
|
||||
for(QMap<QString, QVariant>::iterator mit=map.begin(); mit!=map.end(); mit++)
|
||||
{
|
||||
QgsDebugMsg( QString("idx:%1 key:%2 value:%3").arg( idx ).arg( mit.key() ).arg( mit.value().toString() ) );
|
||||
if( mit.value().isNull() )
|
||||
mapList << mit.key();
|
||||
else
|
||||
mapList << QString( "%1=%2" ).arg( mit.key() ).arg( mit.value().toString() );
|
||||
}
|
||||
|
||||
tblAttributes->setItem(row, 7, new QTableWidgetItem( mapList.join(";") ) );
|
||||
} else if( layer->editType(idx)==QgsVectorLayer::Range ) {
|
||||
tblAttributes->setItem(
|
||||
row, 7,
|
||||
new QTableWidgetItem( QString("%1;%2;%3")
|
||||
.arg( layer->range(idx).mMin.toString() )
|
||||
.arg( layer->range(idx).mMax.toString() )
|
||||
.arg( layer->range(idx).mStep.toString() )
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QgsVectorLayerProperties::~QgsVectorLayerProperties()
|
||||
{
|
||||
disconnect(labelDialog, SIGNAL(labelSourceSet()),
|
||||
this, SLOT(setLabelCheckBox()));
|
||||
disconnect(labelDialog, SIGNAL(labelSourceSet()), this, SLOT(setLabelCheckBox()));
|
||||
}
|
||||
|
||||
void QgsVectorLayerProperties::toggleEditing()
|
||||
{
|
||||
emit toggleEditing(layer);
|
||||
}
|
||||
|
||||
void QgsVectorLayerProperties::attributeAdded(int idx)
|
||||
{
|
||||
const QgsFieldMap &fields = layer->pendingFields();
|
||||
int row = tblAttributes->rowCount();
|
||||
tblAttributes->insertRow(row);
|
||||
setRow(row, idx, fields[idx]);
|
||||
tblAttributes->setCurrentCell(row, idx, QItemSelectionModel::NoUpdate);
|
||||
}
|
||||
|
||||
|
||||
void QgsVectorLayerProperties::attributeDeleted(int idx)
|
||||
{
|
||||
for(int i=0; i<tblAttributes->rowCount(); i++)
|
||||
{
|
||||
if( tblAttributes->item(i, 0)->text().toInt()==idx )
|
||||
{
|
||||
tblAttributes->removeRow(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsVectorLayerProperties::addAttribute()
|
||||
{
|
||||
QgsAddAttrDialog dialog(layer->getDataProvider(), this);
|
||||
if(dialog.exec()==QDialog::Accepted)
|
||||
{
|
||||
if(!addAttribute(dialog.name(),dialog.type()))
|
||||
{
|
||||
QMessageBox::information(this,tr("Name conflict"),tr("The attribute could not be inserted. The name already exists in the table."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool QgsVectorLayerProperties::addAttribute(QString name, QString type)
|
||||
{
|
||||
QgsDebugMsg("inserting attribute " + name + " of type " + type );
|
||||
return layer->addAttribute( name, type );
|
||||
}
|
||||
|
||||
void QgsVectorLayerProperties::deleteAttribute()
|
||||
{
|
||||
QList<QTableWidgetItem*> items = tblAttributes->selectedItems();
|
||||
QList<int> idxs;
|
||||
|
||||
for(QList<QTableWidgetItem*>::const_iterator it=items.begin(); it!=items.end(); it++)
|
||||
{
|
||||
if( (*it)->column()==0 )
|
||||
idxs << (*it)->text().toInt();
|
||||
}
|
||||
|
||||
for(QList<int>::const_iterator it=idxs.begin(); it!=idxs.end(); it++)
|
||||
layer->deleteAttribute(*it);
|
||||
}
|
||||
|
||||
void QgsVectorLayerProperties::editingToggled()
|
||||
{
|
||||
if( layer->isEditable() )
|
||||
loadRows();
|
||||
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
void QgsVectorLayerProperties::updateButtons()
|
||||
{
|
||||
if ( layer->isEditable() )
|
||||
{
|
||||
int cap = layer->getDataProvider()->capabilities();
|
||||
mAddAttributeButton->setEnabled( cap & QgsVectorDataProvider::AddAttributes );
|
||||
mDeleteAttributeButton->setEnabled( cap & QgsVectorDataProvider::DeleteAttributes );
|
||||
mToggleEditingButton->setChecked( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
mAddAttributeButton->setEnabled( false );
|
||||
mDeleteAttributeButton->setEnabled( false );
|
||||
mToggleEditingButton->setChecked( false );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsVectorLayerProperties::sliderTransparency_valueChanged(int theValue)
|
||||
{
|
||||
//set the transparency percentage label to a suitable value
|
||||
@ -167,8 +349,6 @@ void QgsVectorLayerProperties::reset( void )
|
||||
"layer is shown here. This is currently only supported for PostgreSQL "
|
||||
"layers. To enter or modify the query, click on the Query Builder button"));
|
||||
|
||||
//we are dealing with a pg layer here so that we can enable the sql box
|
||||
QgsVectorDataProvider *dp = dynamic_cast<QgsVectorDataProvider *>(layer->getDataProvider());
|
||||
//see if we are dealing with a pg layer here
|
||||
if(layer->providerType() == "postgres")
|
||||
{
|
||||
@ -188,7 +368,7 @@ void QgsVectorLayerProperties::reset( void )
|
||||
}
|
||||
|
||||
//get field list for display field combo
|
||||
const QgsFieldMap& myFields = dp->fields();
|
||||
const QgsFieldMap& myFields = layer->pendingFields();
|
||||
for (QgsFieldMap::const_iterator it = myFields.begin(); it != myFields.end(); ++it)
|
||||
{
|
||||
displayFieldComboBox->addItem( it->name() );
|
||||
@ -249,7 +429,7 @@ void QgsVectorLayerProperties::reset( void )
|
||||
SLOT(alterLayerDialog(const QString &)));
|
||||
|
||||
// reset fields in label dialog
|
||||
layer->label()->setFields ( layer->getDataProvider()->fields() );
|
||||
layer->label()->setFields ( layer->pendingFields() );
|
||||
|
||||
//set the metadata contents
|
||||
QString myStyle = QgsApplication::reportStyleSheet();
|
||||
@ -311,6 +491,69 @@ void QgsVectorLayerProperties::apply()
|
||||
layer->setLabelOn(labelCheckBox->isChecked());
|
||||
layer->setLayerName(displayName());
|
||||
|
||||
for(int i=0; i<tblAttributes->rowCount(); i++)
|
||||
{
|
||||
int idx = tblAttributes->item(i, 0)->text().toInt();
|
||||
const QgsField &field = layer->pendingFields()[idx];
|
||||
QgsVectorLayer::EditType editType = layer->editType(idx);
|
||||
|
||||
QComboBox *cb = dynamic_cast<QComboBox*>( tblAttributes->cellWidget(i, 6) );
|
||||
if(!cb)
|
||||
continue;
|
||||
layer->setEditType( idx, (QgsVectorLayer::EditType) cb->itemData( cb->currentIndex() ).toInt() );
|
||||
|
||||
if( editType==QgsVectorLayer::ValueMap )
|
||||
{
|
||||
QMap<QString, QVariant> &map = layer->valueMap(idx);
|
||||
map.clear();
|
||||
|
||||
QString value = tblAttributes->item(i, 7)->text();
|
||||
if( !value.isEmpty() )
|
||||
{
|
||||
QStringList values = tblAttributes->item(i, 7)->text().split(";");
|
||||
for(int j=0; j<values.size(); j++)
|
||||
{
|
||||
QStringList args = values[j].split("=");
|
||||
QVariant value;
|
||||
|
||||
if(args.size()==1 || (args.size()==2 && args[0]==args[1]))
|
||||
{
|
||||
QgsDebugMsg( QString("idx:%1 key:%2 value:%2").arg(idx).arg(args[0]) );
|
||||
value = args[0];
|
||||
}
|
||||
else if(args.size()==2)
|
||||
{
|
||||
QgsDebugMsg( QString("idx:%1 key:%2 value:%3").arg( idx ).arg( args[0] ).arg( args[1] ) );
|
||||
value = args[1];
|
||||
|
||||
}
|
||||
|
||||
if( value.canConvert( field.type() ) )
|
||||
{
|
||||
map.insert( args[0], value );
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if( editType==QgsVectorLayer::Range ) {
|
||||
QStringList values = tblAttributes->item(i, 7)->text().split(";");
|
||||
|
||||
if( values.size()==3 ) {
|
||||
QVariant min = values[0];
|
||||
QVariant max = values[1];
|
||||
QVariant step = values[2];
|
||||
|
||||
if( min.canConvert(field.type()) &&
|
||||
max.canConvert(field.type()) &&
|
||||
step.canConvert(field.type()) )
|
||||
{
|
||||
min.convert( field.type() );
|
||||
max.convert( field.type() );
|
||||
step.convert( field.type() );
|
||||
layer->range(idx) = QgsVectorLayer::RangeData(min,max,step);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QgsSingleSymbolDialog *sdialog =
|
||||
dynamic_cast < QgsSingleSymbolDialog * >(widgetStackRenderers->currentWidget());
|
||||
@ -354,11 +597,8 @@ void QgsVectorLayerProperties::on_pbnQueryBuilder_clicked()
|
||||
// launch the query builder using the PostgreSQL connection
|
||||
// from the provider
|
||||
|
||||
// get the data provider
|
||||
QgsVectorDataProvider *dp =
|
||||
dynamic_cast<QgsVectorDataProvider *>(layer->getDataProvider());
|
||||
// cast to postgres provider type
|
||||
QgsPostgresProvider * myPGProvider = (QgsPostgresProvider *) dp;
|
||||
// cast to postgres provider type
|
||||
QgsPostgresProvider * myPGProvider = (QgsPostgresProvider *) layer->getDataProvider() ; // FIXME use dynamic cast
|
||||
// create the query builder object using the table name
|
||||
// and postgres connection from the provider
|
||||
QgsDataSourceURI uri(myPGProvider->dataSourceUri());
|
||||
@ -541,7 +781,7 @@ QString QgsVectorLayerProperties::getMetadata()
|
||||
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
//
|
||||
// Add the info about each field in the attribute table
|
||||
//
|
||||
@ -569,8 +809,7 @@ QString QgsVectorLayerProperties::getMetadata()
|
||||
myMetadata += "</th>";
|
||||
|
||||
//get info for each field by looping through them
|
||||
QgsVectorDataProvider *myDataProvider = dynamic_cast<QgsVectorDataProvider *>(layer->getDataProvider());
|
||||
const QgsFieldMap& myFields = myDataProvider->fields();
|
||||
const QgsFieldMap& myFields = layer->pendingFields();
|
||||
for (QgsFieldMap::const_iterator it = myFields.begin(); it != myFields.end(); ++it)
|
||||
{
|
||||
const QgsField& myField = *it;
|
||||
@ -594,15 +833,17 @@ QString QgsVectorLayerProperties::getMetadata()
|
||||
|
||||
//close field list
|
||||
myMetadata += "</table>"; //end of nested table
|
||||
#endif
|
||||
|
||||
myMetadata += "</td></tr>"; //end of stats container table row
|
||||
//
|
||||
// Close the table
|
||||
//
|
||||
|
||||
myMetadata += "</table>";
|
||||
|
||||
myMetadata += "</body></html>";
|
||||
return myMetadata;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -23,15 +23,20 @@
|
||||
#include "ui_qgsvectorlayerpropertiesbase.h"
|
||||
#include "qgisgui.h"
|
||||
#include "qgsrenderer.h"
|
||||
#include "qgsaddattrdialog.h"
|
||||
#include "qgsdelattrdialog.h"
|
||||
#include "qgsfield.h"
|
||||
|
||||
class QgsMapLayer;
|
||||
|
||||
class QgsAttributeActionDialog;
|
||||
class QgsLabelDialog;
|
||||
class QgsVectorLayer;
|
||||
|
||||
|
||||
class QgsVectorLayerProperties : public QDialog, private Ui::QgsVectorLayerPropertiesBase{
|
||||
Q_OBJECT
|
||||
public:
|
||||
class QgsVectorLayerProperties : public QDialog, private Ui::QgsVectorLayerPropertiesBase
|
||||
{
|
||||
Q_OBJECT;
|
||||
public:
|
||||
QgsVectorLayerProperties(QgsVectorLayer *lyr = 0,QWidget *parent = 0, Qt::WFlags fl = QgisGui::ModalDialogFlags);
|
||||
~QgsVectorLayerProperties();
|
||||
/**Sets the legend type to "single symbol", "graduated symbol" or "continuous color"*/
|
||||
@ -42,19 +47,42 @@ class QgsVectorLayerProperties : public QDialog, private Ui::QgsVectorLayerPrope
|
||||
/**Sets the attribute that is used in the Identify Results dialog box*/
|
||||
void setDisplayField(QString name);
|
||||
|
||||
public slots:
|
||||
/**Adds an attribute to the table (but does not commit it yet)
|
||||
@param name attribute name
|
||||
@param type attribute type
|
||||
@return false in case of a name conflict, true in case of success*/
|
||||
bool addAttribute(QString name, QString type);
|
||||
|
||||
/**Deletes an attribute (but does not commit it)
|
||||
@param name attribute name
|
||||
@return false in case of a non-existing attribute.*/
|
||||
bool deleteAttribute(int attr);
|
||||
|
||||
public slots:
|
||||
|
||||
void alterLayerDialog(const QString& string);
|
||||
|
||||
/** Reset to original (vector layer) values */
|
||||
void reset();
|
||||
|
||||
/** Get metadata about the layer in nice formatted html */
|
||||
QString getMetadata();
|
||||
|
||||
/** Set transparency based on slider position */
|
||||
void sliderTransparency_valueChanged(int theValue);
|
||||
|
||||
/** Toggles on the label check box */
|
||||
void setLabelCheckBox();
|
||||
|
||||
/** Called when apply button is pressed or dialog is accepted */
|
||||
void apply();
|
||||
|
||||
/** toggle editing of layer */
|
||||
void toggleEditing();
|
||||
|
||||
/** editing of layer was toggled */
|
||||
void editingToggled();
|
||||
|
||||
//
|
||||
//methods reimplemented from qt designer base class
|
||||
//
|
||||
@ -67,13 +95,21 @@ class QgsVectorLayerProperties : public QDialog, private Ui::QgsVectorLayerPrope
|
||||
void on_pbnSaveDefaultStyle_clicked();
|
||||
void on_pbnLoadStyle_clicked();
|
||||
void on_pbnSaveStyleAs_clicked();
|
||||
|
||||
signals:
|
||||
|
||||
/** emitted when changes to layer were saved to update legend */
|
||||
void refreshLegend(QString layerID, bool expandItem);
|
||||
|
||||
protected:
|
||||
void addAttribute();
|
||||
void deleteAttribute();
|
||||
|
||||
void attributeAdded(int idx);
|
||||
void attributeDeleted(int idx);
|
||||
|
||||
signals:
|
||||
|
||||
/** emitted when changes to layer were saved to update legend */
|
||||
void refreshLegend(QString layerID, bool expandItem);
|
||||
|
||||
void toggleEditing(QgsMapLayer *);
|
||||
|
||||
protected:
|
||||
QgsVectorLayer *layer;
|
||||
/**Renderer dialog which is shown*/
|
||||
QDialog* mRendererDialog;
|
||||
@ -83,14 +119,19 @@ class QgsVectorLayerProperties : public QDialog, private Ui::QgsVectorLayerPrope
|
||||
QgsLabelDialog* labelDialog;
|
||||
/**Actions dialog. If apply is pressed, the actions are stored for later use */
|
||||
QgsAttributeActionDialog* actionDialog;
|
||||
|
||||
void updateButtons();
|
||||
void loadRows();
|
||||
void setRow(int row, int idx, const QgsField &field);
|
||||
|
||||
/**Buffer pixmap which takes the picture of renderers before they are assigned to the vector layer*/
|
||||
//QPixmap bufferPixmap;
|
||||
static const int context_id = 94000531;
|
||||
|
||||
};
|
||||
|
||||
inline QString QgsVectorLayerProperties::displayName()
|
||||
{
|
||||
return txtDisplayName->text();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -34,9 +34,7 @@ General purpose distance and area calculator
|
||||
*/
|
||||
class CORE_EXPORT QgsDistanceArea
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
//! Constructor
|
||||
QgsDistanceArea();
|
||||
|
||||
|
@ -18,20 +18,12 @@ email : sherman at mrcc.com
|
||||
#include "qgsgeometry.h"
|
||||
#include "qgsrect.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <cfloat>
|
||||
#ifdef WIN32
|
||||
#include <limits>
|
||||
#endif
|
||||
#include <cstring>
|
||||
#include <assert.h>
|
||||
|
||||
/** \class QgsFeature
|
||||
* \brief Encapsulates a spatial feature with attributes
|
||||
*/
|
||||
|
||||
QgsFeature::QgsFeature(int id, QString typeName)
|
||||
: mFid(id),
|
||||
: mFid(id),
|
||||
mGeometry(0),
|
||||
mOwnsGeometry(0),
|
||||
mValid(false),
|
||||
@ -41,101 +33,40 @@ QgsFeature::QgsFeature(int id, QString typeName)
|
||||
// NOOP
|
||||
}
|
||||
|
||||
QgsFeature::QgsFeature( QgsFeature const & rhs,
|
||||
const QgsChangedAttributesMap & changedAttributes,
|
||||
const QgsGeometryMap & changedGeometries )
|
||||
: mFid( rhs.mFid ),
|
||||
mValid( rhs.mValid ),
|
||||
mDirty( rhs.mDirty ),
|
||||
mTypeName( rhs.mTypeName )
|
||||
|
||||
{
|
||||
// copy attributes from rhs feature
|
||||
mAttributes = rhs.mAttributes;
|
||||
|
||||
if (changedAttributes.contains(mFid))
|
||||
{
|
||||
// get map of changed attributes
|
||||
const QgsAttributeMap& changed = changedAttributes[mFid];
|
||||
|
||||
// changet the attributes which were provided in the attribute map
|
||||
for (QgsAttributeMap::const_iterator it = changed.begin(); it != changed.end(); ++it)
|
||||
{
|
||||
changeAttribute(it.key(), it.value());
|
||||
}
|
||||
}
|
||||
|
||||
if (changedGeometries.contains(mFid))
|
||||
{
|
||||
// deep-copy geometry purely from changedGeometries
|
||||
mGeometry = new QgsGeometry(changedGeometries[mFid]);
|
||||
mOwnsGeometry = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
// copy geometry purely from rhs feature
|
||||
if ( rhs.mGeometry )
|
||||
{
|
||||
mGeometry = new QgsGeometry( *(rhs.mGeometry) );
|
||||
mOwnsGeometry = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
mGeometry = 0;
|
||||
mOwnsGeometry = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
QgsFeature::QgsFeature( QgsFeature const & rhs )
|
||||
: mFid( rhs.mFid ),
|
||||
: mFid( rhs.mFid ),
|
||||
mAttributes( rhs.mAttributes ),
|
||||
mValid( rhs.mValid ),
|
||||
mDirty( rhs.mDirty ),
|
||||
mTypeName( rhs.mTypeName )
|
||||
mTypeName( rhs.mTypeName ),
|
||||
mGeometry( 0 ),
|
||||
mOwnsGeometry( false )
|
||||
{
|
||||
|
||||
// copy embedded geometry
|
||||
if ( rhs.mGeometry )
|
||||
{
|
||||
mGeometry = new QgsGeometry( *(rhs.mGeometry) );
|
||||
mOwnsGeometry = TRUE;
|
||||
setGeometry( *rhs.mGeometry );
|
||||
}
|
||||
else
|
||||
{
|
||||
mGeometry = 0;
|
||||
mOwnsGeometry = FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
QgsFeature & QgsFeature::operator=( QgsFeature const & rhs )
|
||||
{
|
||||
if ( &rhs == this )
|
||||
{ return *this; }
|
||||
return *this;
|
||||
|
||||
mFid = rhs.mFid ;
|
||||
mDirty = rhs.mDirty ;
|
||||
mAttributes = rhs.mAttributes ;
|
||||
mValid = rhs.mValid ;
|
||||
mFid = rhs.mFid;
|
||||
mDirty = rhs.mDirty;
|
||||
mAttributes = rhs.mAttributes;
|
||||
mValid = rhs.mValid;
|
||||
mTypeName = rhs.mTypeName;
|
||||
mGeometry = 0;
|
||||
mOwnsGeometry = false;
|
||||
|
||||
// copy embedded geometry
|
||||
delete mGeometry;
|
||||
if ( rhs.mGeometry )
|
||||
{
|
||||
mGeometry = new QgsGeometry( *(rhs.mGeometry) );
|
||||
mOwnsGeometry = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
mGeometry = 0;
|
||||
mOwnsGeometry = FALSE;
|
||||
}
|
||||
|
||||
setGeometry( *rhs.mGeometry );
|
||||
|
||||
return *this;
|
||||
} // QgsFeature::operator=( QgsFeature const & rhs )
|
||||
|
||||
@ -144,13 +75,9 @@ QgsFeature & QgsFeature::operator=( QgsFeature const & rhs )
|
||||
//! Destructor
|
||||
QgsFeature::~QgsFeature()
|
||||
{
|
||||
|
||||
// Destruct the attached geometry only if we still own it.
|
||||
if ( (mOwnsGeometry) && (mGeometry) )
|
||||
{
|
||||
if ( mOwnsGeometry && mGeometry )
|
||||
delete mGeometry;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -197,17 +124,15 @@ void QgsFeature::changeAttribute(int field, QVariant attr)
|
||||
mAttributes[field] = attr;
|
||||
}
|
||||
|
||||
|
||||
QgsGeometry * QgsFeature::geometry()
|
||||
QgsGeometry *QgsFeature::geometry()
|
||||
{
|
||||
return mGeometry;
|
||||
}
|
||||
|
||||
|
||||
QgsGeometry * QgsFeature::geometryAndOwnership()
|
||||
QgsGeometry *QgsFeature::geometryAndOwnership()
|
||||
{
|
||||
mOwnsGeometry = FALSE;
|
||||
|
||||
mOwnsGeometry = false;
|
||||
|
||||
return mGeometry;
|
||||
}
|
||||
|
||||
@ -218,7 +143,6 @@ QgsGeometry * QgsFeature::geometryAndOwnership()
|
||||
void QgsFeature::setFeatureId(int id)
|
||||
{
|
||||
mFid = id;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -239,45 +163,29 @@ void QgsFeature::setTypeName(QString typeName)
|
||||
|
||||
void QgsFeature::setGeometry(const QgsGeometry& geom)
|
||||
{
|
||||
// Destruct the attached geometry only if we still own it, before assigning new one.
|
||||
if ( (mOwnsGeometry) && (mGeometry) )
|
||||
{
|
||||
delete mGeometry;
|
||||
mGeometry = 0;
|
||||
}
|
||||
|
||||
mGeometry = new QgsGeometry(geom);
|
||||
mOwnsGeometry = TRUE;
|
||||
setGeometry( new QgsGeometry(geom) );
|
||||
}
|
||||
|
||||
void QgsFeature::setGeometry(QgsGeometry* geom)
|
||||
{
|
||||
// Destruct the attached geometry only if we still own it, before assigning new one.
|
||||
if ( (mOwnsGeometry) && (mGeometry) )
|
||||
if ( mOwnsGeometry && mGeometry )
|
||||
{
|
||||
delete mGeometry;
|
||||
mGeometry = 0;
|
||||
}
|
||||
|
||||
|
||||
mGeometry = geom;
|
||||
mOwnsGeometry = TRUE;
|
||||
mOwnsGeometry = true;
|
||||
}
|
||||
|
||||
/** Set the pointer to the feature geometry
|
||||
*/
|
||||
void QgsFeature::setGeometryAndOwnership(unsigned char *geom, size_t length)
|
||||
{
|
||||
// Destruct the attached geometry only if we still own it, before assigning new one.
|
||||
if ( (mOwnsGeometry) && (mGeometry) )
|
||||
{
|
||||
delete mGeometry;
|
||||
mGeometry = 0;
|
||||
}
|
||||
|
||||
mGeometry = new QgsGeometry();
|
||||
mGeometry->setWkbAndOwnership(geom, length);
|
||||
mOwnsGeometry = TRUE;
|
||||
|
||||
QgsGeometry *g = new QgsGeometry();
|
||||
g->setWkbAndOwnership(geom, length);
|
||||
setGeometry(g);
|
||||
}
|
||||
|
||||
|
||||
@ -298,5 +206,5 @@ bool QgsFeature::isDirty() const
|
||||
|
||||
void QgsFeature::resetDirty()
|
||||
{
|
||||
mDirty = FALSE;
|
||||
mDirty = false;
|
||||
}
|
||||
|
@ -20,10 +20,11 @@ email : sherman at mrcc.com
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
#include <QList>
|
||||
|
||||
class QgsGeometry;
|
||||
class QgsRect;
|
||||
|
||||
class QgsFeature;
|
||||
|
||||
// key = field index, value = field value
|
||||
typedef QMap<int, QVariant> QgsAttributeMap;
|
||||
@ -37,6 +38,7 @@ typedef QMap<int, QgsGeometry> QgsGeometryMap;
|
||||
// key = field index, value = field name
|
||||
typedef QMap<int, QString> QgsFieldNameMap;
|
||||
|
||||
typedef QList<QgsFeature> QgsFeatureList;
|
||||
|
||||
/**
|
||||
* @class QgsFeature - Feature attribute class.
|
||||
@ -44,25 +46,12 @@ typedef QMap<int, QString> QgsFieldNameMap;
|
||||
*
|
||||
* @author Gary E.Sherman
|
||||
*/
|
||||
class CORE_EXPORT QgsFeature {
|
||||
|
||||
class CORE_EXPORT QgsFeature
|
||||
{
|
||||
public:
|
||||
|
||||
//! Constructor
|
||||
QgsFeature(int id = 0, QString typeName = "" );
|
||||
|
||||
/** create a copy of this feature in its uncommitted state.
|
||||
To do this, you also pass in a reference to the feature's
|
||||
layer's uncommitted attribute and geometry changes.
|
||||
The resulting feature will have those changes applied.
|
||||
|
||||
This is useful in the cut/copy routine, where you'd
|
||||
want a copy of the "current" feature, not the on-disk feature.
|
||||
*/
|
||||
QgsFeature( const QgsFeature & rhs,
|
||||
const QgsChangedAttributesMap & changedAttributes,
|
||||
const QgsGeometryMap & changedGeometries );
|
||||
|
||||
/** copy ctor needed due to internal pointer */
|
||||
QgsFeature( QgsFeature const & rhs );
|
||||
|
||||
@ -140,17 +129,17 @@ class CORE_EXPORT QgsFeature {
|
||||
* You would normally do this after it's saved to permanent storage (e.g. disk, an ACID-compliant database)
|
||||
*/
|
||||
void resetDirty();
|
||||
|
||||
|
||||
/**
|
||||
* Get the geometry object associated with this feature
|
||||
*/
|
||||
QgsGeometry * geometry();
|
||||
QgsGeometry *geometry();
|
||||
|
||||
/**
|
||||
* Get the geometry object associated with this feature
|
||||
* The caller assumes responsibility for the QgsGeometry*'s destruction.
|
||||
*/
|
||||
QgsGeometry * geometryAndOwnership();
|
||||
QgsGeometry *geometryAndOwnership();
|
||||
|
||||
/** Set this feature's geometry from another QgsGeometry object (deep copy)
|
||||
*/
|
||||
@ -174,17 +163,17 @@ class CORE_EXPORT QgsFeature {
|
||||
|
||||
/** map of attributes accessed by field index */
|
||||
QgsAttributeMap mAttributes;
|
||||
|
||||
|
||||
/** pointer to geometry in binary WKB format
|
||||
|
||||
This is usually set by a call to OGRGeometry::exportToWkb()
|
||||
*/
|
||||
QgsGeometry* mGeometry;
|
||||
|
||||
|
||||
/** Indicator if the mGeometry is owned by this QgsFeature.
|
||||
If so, this QgsFeature takes responsibility for the mGeometry's destruction.
|
||||
*/
|
||||
bool mOwnsGeometry;
|
||||
*/
|
||||
bool mOwnsGeometry;
|
||||
|
||||
//! Flag to indicate if this feature is valid
|
||||
// TODO: still applies? [MD]
|
||||
@ -200,4 +189,5 @@ class CORE_EXPORT QgsFeature {
|
||||
|
||||
}; // class QgsFeature
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -145,4 +145,7 @@ private:
|
||||
|
||||
}; // class QgsField
|
||||
|
||||
// key = field index, value=field data
|
||||
typedef QMap<int, QgsField> QgsFieldMap;
|
||||
|
||||
#endif
|
||||
|
@ -482,7 +482,7 @@ QgsLabelAttributes *QgsLabel::layerAttributes ( void )
|
||||
|
||||
void QgsLabel::labelPoint ( std::vector<QgsPoint>& points, QgsFeature & feature )
|
||||
{
|
||||
QgsGeometry* geometry = feature.geometry();
|
||||
QgsGeometry *geometry = feature.geometry();
|
||||
unsigned char *geom = geometry->wkbBuffer();
|
||||
size_t geomlen = geometry->wkbSize();
|
||||
QGis::WKBTYPE wkbType = geometry->wkbType();
|
||||
|
@ -83,7 +83,7 @@ public:
|
||||
void renderLabel ( QPainter* painter, const QgsRect& viewExtent,
|
||||
const QgsCoordinateTransform* coordTransform,
|
||||
const QgsMapToPixel *transform,
|
||||
QgsFeature &feature, bool selected, QgsLabelAttributes *classAttributes=0, double sizeScale = 1.);
|
||||
QgsFeature &feature, bool selected, QgsLabelAttributes *classAttributes=0, double sizeScale = 1.);
|
||||
|
||||
/** Reads the renderer configuration from an XML file
|
||||
@param rnode the DOM node to read
|
||||
@ -132,7 +132,7 @@ private:
|
||||
int width, int height, int alignment);
|
||||
|
||||
/** Get label point for simple feature in map units */
|
||||
void labelPoint ( std::vector<QgsPoint>&, QgsFeature & feature );
|
||||
void labelPoint ( std::vector<QgsPoint>&, QgsFeature &feature );
|
||||
|
||||
/** Get label point for the given feature in wkb format. */
|
||||
unsigned char* labelPoint( QgsPoint& point, unsigned char* wkb, size_t wkblen);
|
||||
|
@ -57,32 +57,32 @@ class CORE_EXPORT QgsLogger
|
||||
static void debug(const QString& var, double val, int debuglevel = 1, const char* file = NULL, const char* function = NULL, int line = -1);
|
||||
|
||||
/**Prints out a variable/value pair for types with overloaded operator<<*/
|
||||
template <typename T> static void debug(const QString& var, T val, const char* file = 0, const char* function = 0, \
|
||||
template <typename T> static void debug(const QString& var, T val, const char* file = 0, const char* function = 0,
|
||||
int line = -1, int debuglevel = 1)
|
||||
{
|
||||
const char* dfile = debugFile();
|
||||
if(dfile) //exit if QGIS_DEBUG_FILE is set and the message comes from the wrong file
|
||||
{
|
||||
const char* dfile = debugFile();
|
||||
if(dfile) //exit if QGIS_DEBUG_FILE is set and the message comes from the wrong file
|
||||
{
|
||||
if(!file || strcmp(dfile, file) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
std::ostringstream os;
|
||||
os << var.toLocal8Bit().data() << " = " << val;
|
||||
if(line == -1)
|
||||
{
|
||||
qDebug("%s: (%s) %s", file, function, os.str().c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
qDebug("%s(%d): (%s) %s", file, line, function, os.str().c_str());
|
||||
#else
|
||||
qDebug("%s: %d: (%s) %s", file, line, function, os.str().c_str());
|
||||
#endif
|
||||
}
|
||||
if(!file || strcmp(dfile, file) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
std::ostringstream os;
|
||||
os << var.toLocal8Bit().data() << " = " << val;
|
||||
if(line == -1)
|
||||
{
|
||||
qDebug("%s: (%s) %s", file, function, os.str().c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
qDebug("%s(%d): (%s) %s", file, line, function, os.str().c_str());
|
||||
#else
|
||||
qDebug("%s: %d: (%s) %s", file, line, function, os.str().c_str());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/**Goes to qWarning*/
|
||||
static void warning(const QString& msg);
|
||||
|
@ -24,11 +24,10 @@
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
||||
class QgsSearchTreeValue;
|
||||
class QgsField;
|
||||
#include <qgsfield.h>
|
||||
#include <qgsfeature.h>
|
||||
|
||||
typedef QMap<int, QgsField> QgsFieldMap;
|
||||
typedef QMap<int, QVariant> QgsAttributeMap;
|
||||
class QgsSearchTreeValue;
|
||||
|
||||
/**
|
||||
* QgsSearchTreeNode
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include <cmath>
|
||||
|
||||
|
||||
QgsSnapper::QgsSnapper(QgsMapRenderer* mapRender): mMapRenderer(mapRender)
|
||||
QgsSnapper::QgsSnapper(QgsMapRenderer* mapRenderer): mMapRenderer(mapRenderer)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ QString QgsVectorDataProvider::dataComment() const
|
||||
return QString();
|
||||
}
|
||||
|
||||
bool QgsVectorDataProvider::addFeatures(QgsFeatureList & flist)
|
||||
bool QgsVectorDataProvider::addFeatures(QgsFeatureList &flist)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -220,7 +220,7 @@ QString QgsVectorDataProvider::capabilitiesString() const
|
||||
|
||||
int QgsVectorDataProvider::indexFromFieldName(const QString& fieldName) const
|
||||
{
|
||||
const QgsFieldMap& theFields = fields();
|
||||
const QgsFieldMap &theFields = fields();
|
||||
|
||||
for (QgsFieldMap::const_iterator it = theFields.begin(); it != theFields.end(); ++it)
|
||||
{
|
||||
@ -248,7 +248,7 @@ void QgsVectorDataProvider::setFetchFeaturesWithoutGeom(bool fetch)
|
||||
mFetchFeaturesWithoutGeom = fetch;
|
||||
}
|
||||
|
||||
const QSet<QString>& QgsVectorDataProvider::supportedNativeTypes() const
|
||||
const QgsNativeTypeMap &QgsVectorDataProvider::supportedNativeTypes() const
|
||||
{
|
||||
return mSupportedNativeTypes;
|
||||
}
|
||||
@ -261,15 +261,15 @@ QVariant QgsVectorDataProvider::minValue(int index)
|
||||
QgsDebugMsg("Warning: access requested to invalid field index: " + QString::number(index));
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
|
||||
if (mCacheMinMaxDirty)
|
||||
{
|
||||
fillMinMaxCache();
|
||||
}
|
||||
|
||||
|
||||
if (!mCacheMinValues.contains(index))
|
||||
return QVariant();
|
||||
|
||||
|
||||
return mCacheMinValues[index];
|
||||
}
|
||||
|
||||
@ -280,7 +280,7 @@ QVariant QgsVectorDataProvider::maxValue(int index)
|
||||
QgsDebugMsg("Warning: access requested to invalid field index: " + QString::number(index));
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
|
||||
if (mCacheMinMaxDirty)
|
||||
{
|
||||
fillMinMaxCache();
|
||||
|
@ -26,9 +26,11 @@ class QTextCodec;
|
||||
//QGIS Includes
|
||||
#include "qgis.h"
|
||||
#include "qgsdataprovider.h"
|
||||
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsfield.h"
|
||||
|
||||
typedef QMap<QString, QString> QgsNewAttributesMap;
|
||||
typedef QMap<QString, QVariant::Type> QgsNativeTypeMap;
|
||||
|
||||
/** Base class for vector data providers
|
||||
*/
|
||||
@ -137,7 +139,7 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider
|
||||
* Return a map of indexes with field names for this layer
|
||||
* @return map of fields
|
||||
*/
|
||||
virtual const QgsFieldMap & fields() const = 0;
|
||||
virtual const QgsFieldMap &fields() const = 0;
|
||||
|
||||
/**
|
||||
* Return a short comment for the data that this provider is
|
||||
@ -181,14 +183,14 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider
|
||||
* Adds a list of features
|
||||
* @return true in case of success and false in case of failure
|
||||
*/
|
||||
virtual bool addFeatures(QgsFeatureList & flist);
|
||||
virtual bool addFeatures(QgsFeatureList &flist);
|
||||
|
||||
/**
|
||||
* Deletes a feature
|
||||
* @param id list containing feature ids to delete
|
||||
* @return true in case of success and false in case of failure
|
||||
*/
|
||||
virtual bool deleteFeatures(const QgsFeatureIds & id);
|
||||
virtual bool deleteFeatures(const QgsFeatureIds &id);
|
||||
|
||||
/**
|
||||
* Adds new attributes
|
||||
@ -246,24 +248,24 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider
|
||||
* Set encoding used for accessing data from layer
|
||||
*/
|
||||
virtual void setEncoding(const QString& e);
|
||||
|
||||
|
||||
/**
|
||||
* Get encoding which is used for accessing data
|
||||
*/
|
||||
QString encoding() const;
|
||||
|
||||
|
||||
/**
|
||||
* Returns the index of a field name or -1 if the field does not exist
|
||||
*/
|
||||
int indexFromFieldName(const QString& fieldName) const;
|
||||
|
||||
|
||||
/**
|
||||
* Return list of indexes to fetch all attributes in getNextFeature()
|
||||
*/
|
||||
virtual QgsAttributeList allAttributesList();
|
||||
|
||||
/**Returns the names of the numerical types*/
|
||||
const QSet<QString>& supportedNativeTypes() const;
|
||||
const QgsNativeTypeMap &supportedNativeTypes() const;
|
||||
|
||||
/**
|
||||
* Set whether provider should return also features that don't have
|
||||
@ -272,13 +274,12 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider
|
||||
void setFetchFeaturesWithoutGeom(bool fetch);
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
void fillMinMaxCache();
|
||||
|
||||
|
||||
bool mCacheMinMaxDirty;
|
||||
QMap<int, QVariant> mCacheMinValues, mCacheMaxValues;
|
||||
|
||||
|
||||
/** Encoding */
|
||||
QTextCodec* mEncoding;
|
||||
|
||||
@ -292,7 +293,7 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider
|
||||
QgsAttributeList mAttributesToFetch;
|
||||
|
||||
/**The names of the providers native types*/
|
||||
QSet<QString> mSupportedNativeTypes;
|
||||
QgsNativeTypeMap mSupportedNativeTypes;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -219,7 +219,7 @@ bool QgsVectorFileWriter::addFeature(QgsFeature& feature)
|
||||
}
|
||||
|
||||
// build geometry from WKB
|
||||
QgsGeometry* geom = feature.geometry();
|
||||
QgsGeometry *geom = feature.geometry();
|
||||
|
||||
if (geom->wkbType() != mWkbType)
|
||||
{
|
||||
@ -234,7 +234,7 @@ bool QgsVectorFileWriter::addFeature(QgsFeature& feature)
|
||||
|
||||
OGRGeometryH mGeom2 = createEmptyGeometry(geom->wkbType());
|
||||
|
||||
OGRErr err = OGR_G_ImportFromWkb(mGeom2,geom->wkbBuffer(), geom->wkbSize());
|
||||
OGRErr err = OGR_G_ImportFromWkb(mGeom2, geom->wkbBuffer(), geom->wkbSize());
|
||||
if (err != OGRERR_NONE)
|
||||
{
|
||||
QgsDebugMsg("Failed to import geometry from WKB: " + QString::number(err));
|
||||
@ -247,7 +247,7 @@ bool QgsVectorFileWriter::addFeature(QgsFeature& feature)
|
||||
}
|
||||
else
|
||||
{
|
||||
OGRErr err = OGR_G_ImportFromWkb(mGeom,geom->wkbBuffer(), geom->wkbSize());
|
||||
OGRErr err = OGR_G_ImportFromWkb(mGeom, geom->wkbBuffer(), geom->wkbSize());
|
||||
if (err != OGRERR_NONE)
|
||||
{
|
||||
QgsDebugMsg("Failed to import geometry from WKB: " + QString::number(err));
|
||||
|
@ -21,8 +21,7 @@
|
||||
#define _QGSVECTORFILEWRITER_H_
|
||||
|
||||
#include "qgsvectorlayer.h"
|
||||
|
||||
#include <QString>
|
||||
#include "qgsfield.h"
|
||||
|
||||
typedef void *OGRDataSourceH;
|
||||
typedef void *OGRLayerH;
|
||||
@ -41,7 +40,7 @@ class QTextCodec;
|
||||
class CORE_EXPORT QgsVectorFileWriter
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
enum WriterError
|
||||
{
|
||||
NoError = 0,
|
||||
@ -64,36 +63,36 @@ class CORE_EXPORT QgsVectorFileWriter
|
||||
const QgsFieldMap& fields,
|
||||
QGis::WKBTYPE geometryType,
|
||||
const QgsSpatialRefSys* srs);
|
||||
|
||||
|
||||
/** checks whether there were any errors in constructor */
|
||||
WriterError hasError();
|
||||
|
||||
|
||||
/** add feature to the currently opened shapefile */
|
||||
bool addFeature(QgsFeature& feature);
|
||||
|
||||
|
||||
/** close opened shapefile for writing */
|
||||
~QgsVectorFileWriter();
|
||||
|
||||
|
||||
/** Delete a shapefile (and its accompanying shx / dbf / prf)
|
||||
* @param QString theFileName - /path/to/file.shp
|
||||
* @return bool true if the file was deleted successfully
|
||||
*/
|
||||
static bool deleteShapeFile(QString theFileName);
|
||||
protected:
|
||||
|
||||
|
||||
OGRGeometryH createEmptyGeometry(QGis::WKBTYPE wkbType);
|
||||
|
||||
|
||||
OGRDataSourceH mDS;
|
||||
OGRLayerH mLayer;
|
||||
OGRGeometryH mGeom;
|
||||
|
||||
|
||||
QgsFieldMap mFields;
|
||||
|
||||
|
||||
/** contains error value if construction was not successfull */
|
||||
WriterError mError;
|
||||
|
||||
QTextCodec* mCodec;
|
||||
|
||||
|
||||
/** geometry type which is being used */
|
||||
QGis::WKBTYPE mWkbType;
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -22,20 +22,20 @@
|
||||
#include <QMap>
|
||||
#include <QSet>
|
||||
#include <QList>
|
||||
#include <QPair>
|
||||
#include <QStringList>
|
||||
|
||||
#include "qgis.h"
|
||||
#include "qgsmaplayer.h"
|
||||
#include "qgsfeature.h"
|
||||
#include "qgssnapper.h"
|
||||
#include "qgsfeature.h"
|
||||
#include "qgsfield.h"
|
||||
|
||||
class QPainter;
|
||||
class QImage;
|
||||
|
||||
class QgsAttributeAction;
|
||||
class QgsCoordinateTransform;
|
||||
class QgsField;
|
||||
class QgsFeature;
|
||||
class QgsGeometry;
|
||||
class QgsGeometryVertexIndex;
|
||||
class QgsMapToPixel;
|
||||
@ -44,34 +44,39 @@ class QgsRect;
|
||||
class QgsRenderer;
|
||||
class QgsVectorDataProvider;
|
||||
|
||||
|
||||
class QgsGeometry;
|
||||
class QgsRect;
|
||||
class QgsFeature;
|
||||
|
||||
//typedef QList<QgsField> QgsFieldList;
|
||||
typedef QList<QgsFeature> QgsFeatureList;
|
||||
typedef QList<int> QgsAttributeList;
|
||||
|
||||
typedef QList<int> QgsAttributeList;
|
||||
typedef QSet<int> QgsFeatureIds;
|
||||
typedef QSet<int> QgsAttributeIds;
|
||||
|
||||
// key = attribute name, value = attribute type
|
||||
typedef QMap<QString, QString> QgsNewAttributesMap;
|
||||
|
||||
typedef QMap<int, QgsField> QgsFieldMap;
|
||||
|
||||
|
||||
|
||||
/*! \class QgsVectorLayer
|
||||
* \brief Vector layer backed by a data source provider
|
||||
*/
|
||||
|
||||
class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum EditType {
|
||||
LineEdit,
|
||||
UniqueValues,
|
||||
UniqueValuesEditable,
|
||||
ValueMap,
|
||||
Classification,
|
||||
Range,
|
||||
};
|
||||
|
||||
struct RangeData {
|
||||
RangeData() {}
|
||||
RangeData(QVariant theMin, QVariant theMax, QVariant theStep)
|
||||
: mMin(theMin), mMax(theMax), mStep(theStep) {}
|
||||
|
||||
QVariant mMin;
|
||||
QVariant mMax;
|
||||
QVariant mStep;
|
||||
};
|
||||
|
||||
/** Constructor */
|
||||
QgsVectorLayer(QString path = 0, QString baseName = 0,
|
||||
@ -113,35 +118,31 @@ public:
|
||||
|
||||
/** The number of features that are selected in this layer */
|
||||
int selectedFeatureCount();
|
||||
|
||||
|
||||
/** Select features found within the search rectangle (in layer's coordinates) */
|
||||
void select(QgsRect & rect, bool lock);
|
||||
|
||||
|
||||
/** Select not selected features and deselect selected ones */
|
||||
void invertSelection();
|
||||
|
||||
/** Get a copy of the user-selected features */
|
||||
/** Get a copy of the user-selected features */
|
||||
QgsFeatureList selectedFeatures();
|
||||
|
||||
|
||||
/** Return reference to identifiers of selected features */
|
||||
const QgsFeatureIds& selectedFeaturesIds() const;
|
||||
|
||||
|
||||
/** Change selection to the new set of features */
|
||||
void setSelectedFeatures(const QgsFeatureIds& ids);
|
||||
|
||||
/** Returns the bounding box of the selected features. If there is no selection, QgsRect(0,0,0,0) is returned */
|
||||
QgsRect boundingBoxOfSelected();
|
||||
|
||||
|
||||
/** Insert a copy of the given features into the layer */
|
||||
bool addFeatures(QgsFeatureList features, bool makeSelected = TRUE);
|
||||
|
||||
/** Copies the symbology settings from another layer. Returns true in case of success */
|
||||
bool copySymbologySettings(const QgsMapLayer& other);
|
||||
|
||||
/** Returns true if this layer can be in the same symbology group with another layer */
|
||||
bool isSymbologyCompatible(const QgsMapLayer& other) const;
|
||||
|
||||
|
||||
/** Returns a pointer to the renderer */
|
||||
const QgsRenderer* renderer() const;
|
||||
|
||||
@ -196,13 +197,15 @@ public:
|
||||
*/
|
||||
virtual QString subsetString();
|
||||
|
||||
/**Returns the features contained in the rectangle. Considers the changed, added, deleted and permanent features
|
||||
@return 0 in case of success*/
|
||||
int featuresInRectangle(const QgsRect& searchRect, QList<QgsFeature>& features, bool fetchGeometries = true, bool fetchAttributes = true);
|
||||
void select(QgsAttributeList fetchAttributes,
|
||||
QgsRect rect = QgsRect(),
|
||||
bool fetchGeometry = true);
|
||||
|
||||
bool getNextFeature(QgsFeature& feature);
|
||||
|
||||
/**Gets the feature at the given feature id. Considers the changed, added, deleted and permanent features
|
||||
@return 0 in case of success*/
|
||||
int getFeatureAtId(int featureId, QgsFeature& f, bool fetchGeometries = true, bool fetchAttributes = true);
|
||||
int getFeatureAtId(int featureId, QgsFeature &f, bool fetchGeometries = true, bool fetchAttributes = true);
|
||||
|
||||
/** Adds a feature
|
||||
@param lastFeatureInBatch If True, will also go to the effort of e.g. updating the extents.
|
||||
@ -233,14 +236,24 @@ public:
|
||||
bool deleteSelectedFeatures();
|
||||
|
||||
/**Adds a ring to polygon/multipolygon features
|
||||
@return 0 in case of success, 1 problem with feature type, 2 ring not closed, 3 ring not valid, 4 ring crosses \
|
||||
existing rings, 5 no feature found where ring can be inserted*/
|
||||
@return
|
||||
0 in case of success,
|
||||
1 problem with feature type,
|
||||
2 ring not closed,
|
||||
3 ring not valid,
|
||||
4 ring crosses existing rings,
|
||||
5 no feature found where ring can be inserted*/
|
||||
int addRing(const QList<QgsPoint>& ring);
|
||||
|
||||
/**Adds a new island polygon to a multipolygon feature
|
||||
@return 0 in case of success, 1 if selected feature is not multipolygon, 2 if ring is not a valid geometry, \
|
||||
3if new polygon ring not disjoint with existing rings, 4 if no feature was selected, 5 if several features are selected, \
|
||||
6 if selected geometry not found*/
|
||||
@return
|
||||
0 in case of success,
|
||||
1 if selected feature is not multipolygon,
|
||||
2 if ring is not a valid geometry,
|
||||
3 if new polygon ring not disjoint with existing rings,
|
||||
4 if no feature was selected,
|
||||
5 if several features are selected,
|
||||
6 if selected geometry not found*/
|
||||
int addIsland(const QList<QgsPoint>& ring);
|
||||
|
||||
/**Translates feature by dx, dy
|
||||
@ -256,7 +269,7 @@ existing rings, 5 no feature found where ring can be inserted*/
|
||||
@return 0 in case of success*/
|
||||
int splitFeatures(const QList<QgsPoint>& splitLine, bool topologicalEditing = false);
|
||||
|
||||
/**Changes the specified geometry such that it has no intersections with other \
|
||||
/**Changes the specified geometry such that it has no intersections with other
|
||||
polygon (or multipolygon) geometries in this vector layer
|
||||
@param geom geometry to modify
|
||||
@return 0 in case of success*/
|
||||
@ -309,30 +322,8 @@ existing rings, 5 no feature found where ring can be inserted*/
|
||||
@param snap_to to segment / to vertex
|
||||
@return 0 in case of success
|
||||
*/
|
||||
int snapWithContext(const QgsPoint& startPoint, double snappingTolerance, QMultiMap<double, QgsSnappingResult>& snappingResults, \
|
||||
QgsSnapper::SNAP_TO snap_to);
|
||||
|
||||
/**
|
||||
Commits edited attributes. Depending on the feature id,
|
||||
the changes are written to not commited features or redirected to
|
||||
the data provider
|
||||
|
||||
The commits (in this version) occur in three distinct stages,
|
||||
(delete attributes, add attributes, change attribute values)
|
||||
so if a stage fails, it's difficult to roll back cleanly.
|
||||
|
||||
\todo Need to indicate at which stage the failed commit occurred,
|
||||
for better cleanup and recovery from the error.
|
||||
|
||||
\param deleted Set of attribute indices (i.e. columns) to delete
|
||||
\param added Map (name, type) of attribute names (i.e. columns) to add
|
||||
\param changed Map (feature ID, Map (attribute name, new value) )
|
||||
of attribute values to change
|
||||
|
||||
*/
|
||||
bool commitAttributeChanges(const QgsAttributeIds& deleted,
|
||||
const QgsNewAttributesMap& added,
|
||||
const QgsChangedAttributesMap& changed);
|
||||
int snapWithContext(const QgsPoint& startPoint, double snappingTolerance, QMultiMap<double, QgsSnappingResult>& snappingResults,
|
||||
QgsSnapper::SNAP_TO snap_to);
|
||||
|
||||
/** Draws the layer
|
||||
* @return FALSE if an error occurred during drawing
|
||||
@ -347,21 +338,37 @@ existing rings, 5 no feature found where ring can be inserted*/
|
||||
*/
|
||||
void drawLabels(QPainter * p, const QgsRect& viewExtent, const QgsMapToPixel* cXf, const QgsCoordinateTransform* ct, double scale);
|
||||
|
||||
/** returns array of added features */
|
||||
QgsFeatureList& addedFeatures();
|
||||
/** returns fields list which are not commited */
|
||||
const QgsFieldMap &pendingFields();
|
||||
|
||||
/** returns array of deleted feature IDs */
|
||||
QgsFeatureIds& deletedFeatureIds();
|
||||
|
||||
/** returns array of features with changed attributes */
|
||||
QgsChangedAttributesMap& changedAttributes();
|
||||
/** returns list of attributes */
|
||||
QgsAttributeList pendingAllAttributesList();
|
||||
|
||||
/** returns feature count after commit */
|
||||
int pendingFeatureCount();
|
||||
|
||||
/** Sets whether some features are modified or not */
|
||||
void setModified(bool modified = TRUE, bool onlyGeometryWasModified = FALSE);
|
||||
|
||||
|
||||
/** Make layer editable */
|
||||
bool startEditing();
|
||||
|
||||
|
||||
/** changed an attribute value (but does not commit it */
|
||||
bool changeAttributeValue(int fid, int field, QVariant value, bool emitSignal = true);
|
||||
|
||||
/** add an attribute field (but does not commit it)
|
||||
returns the field index or -1 in case of failure */
|
||||
bool addAttribute(QString name, QString type);
|
||||
|
||||
/** delete an attribute field (but does not commit it) */
|
||||
bool deleteAttribute(int attr);
|
||||
|
||||
/** Insert a copy of the given features into the layer (but does not commit it) */
|
||||
bool addFeatures(QgsFeatureList features, bool makeSelected = TRUE);
|
||||
|
||||
/** delete a feature from the layer (but does not commit it) */
|
||||
bool deleteFeature(int fid);
|
||||
|
||||
/**
|
||||
Attempts to commit any changes to disk. Returns the result of the attempt.
|
||||
If a commit fails, the in-memory changes are left alone.
|
||||
@ -370,20 +377,31 @@ existing rings, 5 no feature found where ring can be inserted*/
|
||||
disallowed value in a Postgres database - the user can re-edit and try
|
||||
again.
|
||||
|
||||
The commits (in this version) occur in four distinct stages,
|
||||
(add features, change attributes, change geometries, delete features)
|
||||
The commits occur in distinct stages,
|
||||
(add attributes, add features, change attribute values, change geometries, delete features, delete attributes)
|
||||
so if a stage fails, it's difficult to roll back cleanly.
|
||||
Therefore any error message also includes which stage failed so
|
||||
that the user has some chance of repairing the damage cleanly.
|
||||
|
||||
*/
|
||||
bool commitChanges();
|
||||
const QStringList &commitErrors();
|
||||
|
||||
/** Stop editing and discard the edits */
|
||||
bool rollBack();
|
||||
|
||||
public slots:
|
||||
/**get edit type*/
|
||||
EditType editType(int idx);
|
||||
|
||||
/**set edit type*/
|
||||
void setEditType(int idx, EditType edit);
|
||||
|
||||
/**access value map*/
|
||||
QMap<QString, QVariant> &valueMap(int idx);
|
||||
|
||||
/**access range */
|
||||
RangeData &range(int idx);
|
||||
|
||||
public slots:
|
||||
/** Select feature by its ID, optionally emit signal selectionChanged() */
|
||||
void select(int featureId, bool emitSignal = TRUE);
|
||||
|
||||
@ -405,6 +423,15 @@ signals:
|
||||
/** This signal is emitted when modifications has been done on layer */
|
||||
void wasModified(bool onlyGeometry);
|
||||
|
||||
void editingStarted();
|
||||
void editingStopped();
|
||||
void attributeAdded(int idx);
|
||||
void attributeDeleted(int idx);
|
||||
void featureDeleted(int fid);
|
||||
void layerDeleted();
|
||||
|
||||
void attributeValueChanged(int fid, int idx, const QVariant &);
|
||||
|
||||
private: // Private methods
|
||||
|
||||
enum VertexMarkerType
|
||||
@ -424,7 +451,7 @@ private: // Private methods
|
||||
@todo XXX should this return bool? Throw exceptions?
|
||||
*/
|
||||
bool setDataProvider( QString const & provider );
|
||||
|
||||
|
||||
/** Draws features. May cause projections exceptions to be generated
|
||||
* (i.e., code that calls this function needs to catch them
|
||||
*/
|
||||
@ -433,7 +460,7 @@ private: // Private methods
|
||||
const QgsMapToPixel* cXf,
|
||||
const QgsCoordinateTransform* ct,
|
||||
QImage* marker,
|
||||
double widthScale,
|
||||
double widthScale,
|
||||
double markerScaleFactor,
|
||||
bool drawingToEditingCanvas);
|
||||
|
||||
@ -447,19 +474,19 @@ private: // Private methods
|
||||
/** Draw the linestring as given in the WKB format. Returns a pointer
|
||||
* to the byte after the end of the line string binary data stream (WKB).
|
||||
*/
|
||||
unsigned char* drawLineString(unsigned char* WKBlinestring,
|
||||
QPainter* p,
|
||||
const QgsMapToPixel* mtp,
|
||||
const QgsCoordinateTransform* ct,
|
||||
unsigned char *drawLineString(unsigned char *WKBlinestring,
|
||||
QPainter *p,
|
||||
const QgsMapToPixel *mtp,
|
||||
const QgsCoordinateTransform *ct,
|
||||
bool drawingToEditingCanvas);
|
||||
|
||||
/** Draw the polygon as given in the WKB format. Returns a pointer to
|
||||
* the byte after the end of the polygon binary data stream (WKB).
|
||||
*/
|
||||
unsigned char* drawPolygon(unsigned char* WKBpolygon,
|
||||
QPainter* p,
|
||||
const QgsMapToPixel* mtp,
|
||||
const QgsCoordinateTransform* ct,
|
||||
unsigned char *drawPolygon(unsigned char *WKBpolygon,
|
||||
QPainter *p,
|
||||
const QgsMapToPixel *mtp,
|
||||
const QgsCoordinateTransform *ct,
|
||||
bool drawingToEditingCanvas);
|
||||
|
||||
/** Goes through all features and finds a free id (e.g. to give it temporarily to a not-commited feature) */
|
||||
@ -478,7 +505,7 @@ private: // Private methods
|
||||
@param snappingResult list to which the result is appended
|
||||
@param snap_to snap to vertex or to segment
|
||||
*/
|
||||
void snapToGeometry(const QgsPoint& startPoint, int featureId, QgsGeometry* geom, double sqrSnappingTolerance, \
|
||||
void snapToGeometry(const QgsPoint& startPoint, int featureId, QgsGeometry* geom, double sqrSnappingTolerance,
|
||||
QMultiMap<double, QgsSnappingResult>& snappingResults, QgsSnapper::SNAP_TO snap_to) const;
|
||||
|
||||
/**Little helper function that gives bounding box from a list of points.
|
||||
@ -488,6 +515,11 @@ private: // Private methods
|
||||
/**Reads vertex marker type from settings*/
|
||||
QgsVectorLayer::VertexMarkerType currentVertexMarkerType();
|
||||
|
||||
/**Update feature with uncommited attribute updates*/
|
||||
void updateFeatureAttributes(QgsFeature &f);
|
||||
|
||||
/**Update feature with uncommited geometry updates*/
|
||||
void updateFeatureGeometry(QgsFeature &f);
|
||||
|
||||
private: // Private attributes
|
||||
|
||||
@ -513,36 +545,48 @@ private: // Private attributes
|
||||
|
||||
/** Flag indicating whether the layer has been modified since the last commit */
|
||||
bool mModified;
|
||||
|
||||
|
||||
/** cache of the committed geometries retrieved *for the current display* */
|
||||
QgsGeometryMap mCachedGeometries;
|
||||
|
||||
|
||||
/** Set holding the feature IDs that are activated. Note that if a feature
|
||||
subsequently gets deleted (i.e. by its addition to mDeletedFeatureIds),
|
||||
it always needs to be removed from mSelectedFeatureIds as well.
|
||||
*/
|
||||
*/
|
||||
QgsFeatureIds mSelectedFeatureIds;
|
||||
|
||||
|
||||
/** Deleted feature IDs which are not commited. Note a feature can be added and then deleted
|
||||
again before the change is committed - in that case the added feature would be removed
|
||||
from mAddedFeatures only and *not* entered here.
|
||||
*/
|
||||
*/
|
||||
QgsFeatureIds mDeletedFeatureIds;
|
||||
|
||||
|
||||
/** New features which are not commited. Note a feature can be added and then changed,
|
||||
therefore the details here can be overridden by mChangedAttributes and mChangedGeometries.
|
||||
*/
|
||||
therefore the details here can be overridden by mChangedAttributeValues and mChangedGeometries.
|
||||
*/
|
||||
QgsFeatureList mAddedFeatures;
|
||||
|
||||
/** Changed attributes which are not commited */
|
||||
QgsChangedAttributesMap mChangedAttributes;
|
||||
|
||||
|
||||
/** Changed attributes values which are not commited */
|
||||
QgsChangedAttributesMap mChangedAttributeValues;
|
||||
|
||||
/** deleted attributes fields which are not commited */
|
||||
QgsAttributeIds mDeletedAttributeIds;
|
||||
|
||||
/** added attributes fields which are not commited */
|
||||
QgsAttributeIds mAddedAttributeIds;
|
||||
|
||||
/** Changed geometries which are not commited. */
|
||||
QgsGeometryMap mChangedGeometries;
|
||||
|
||||
|
||||
/** field map to commit */
|
||||
QgsFieldMap mUpdatedFields;
|
||||
|
||||
/** max field index */
|
||||
int mMaxUpdatedIndex;
|
||||
|
||||
/** Geometry type as defined in enum WKBTYPE (qgis.h) */
|
||||
int mGeometryType;
|
||||
|
||||
|
||||
/** Renderer object which holds the information about how to display the features */
|
||||
QgsRenderer *mRenderer;
|
||||
|
||||
@ -552,6 +596,20 @@ private: // Private attributes
|
||||
/** Display labels */
|
||||
bool mLabelOn;
|
||||
|
||||
QStringList mCommitErrors;
|
||||
|
||||
QMap< QString, EditType > mEditTypes;
|
||||
QMap< QString, QMap<QString, QVariant> > mValueMaps;
|
||||
QMap< QString, RangeData > mRanges;
|
||||
|
||||
bool mFetching;
|
||||
QgsRect mFetchRect;
|
||||
QgsAttributeList mFetchAttributes;
|
||||
bool mFetchGeometry;
|
||||
|
||||
QSet<int> mFetchConsidered;
|
||||
QgsGeometryMap::iterator mFetchChangedGeomIt;
|
||||
QgsFeatureList::iterator mFetchAddedFeaturesIt;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -156,7 +156,7 @@ void QgsGraduatedSymbolRenderer::renderFeature(QPainter * p, QgsFeature & f, QIm
|
||||
}
|
||||
}
|
||||
|
||||
QgsSymbol* QgsGraduatedSymbolRenderer::symbolForFeature(const QgsFeature* f)
|
||||
QgsSymbol *QgsGraduatedSymbolRenderer::symbolForFeature(const QgsFeature* f)
|
||||
{
|
||||
//first find out the value for the classification attribute
|
||||
const QgsAttributeMap& attrs = f->attributeMap();
|
||||
|
@ -40,7 +40,7 @@ class CORE_EXPORT QgsGraduatedSymbolRenderer: public QgsRenderer
|
||||
void removeSymbols();
|
||||
/** Determines if a feature will be rendered or not
|
||||
@param f a pointer to the feature to determine if rendering will happen*/
|
||||
bool willRenderFeature(QgsFeature *f);
|
||||
virtual bool willRenderFeature(QgsFeature *f);
|
||||
/**Renders an OGRFeature
|
||||
\param p a painter (usually the one from the current map canvas)
|
||||
\param f a pointer to a feature to render
|
||||
@ -72,7 +72,7 @@ class CORE_EXPORT QgsGraduatedSymbolRenderer: public QgsRenderer
|
||||
int mClassificationField;
|
||||
/**List holding the symbols for the individual classes*/
|
||||
QList<QgsSymbol*> mSymbols;
|
||||
QgsSymbol* symbolForFeature(const QgsFeature* f);
|
||||
QgsSymbol *symbolForFeature(const QgsFeature* f);
|
||||
/**Cached copy of all underlying symbols required attribute fields*/
|
||||
QgsAttributeList mSymbolAttributes;
|
||||
|
||||
|
@ -103,13 +103,13 @@ void QgsSingleSymbolRenderer::renderFeature(QPainter * p, QgsFeature & f, QImage
|
||||
//first find out the value for the scale classification attribute
|
||||
const QgsAttributeMap& attrs = f.attributeMap();
|
||||
fieldScale = sqrt(fabs(attrs[mSymbol->scaleClassificationField()].toDouble()));
|
||||
QgsDebugMsg(QString("Feature has field scale factor %1").arg(fieldScale));
|
||||
QgsDebugMsgLevel(QString("Feature has field scale factor %1").arg(fieldScale), 3);
|
||||
}
|
||||
if ( mSymbol->rotationClassificationField() >= 0 )
|
||||
{
|
||||
const QgsAttributeMap& attrs = f.attributeMap();
|
||||
rotation = attrs[mSymbol->rotationClassificationField()].toDouble();
|
||||
QgsDebugMsg(QString("Feature has rotation factor %1").arg(rotation));
|
||||
QgsDebugMsgLevel(QString("Feature has rotation factor %1").arg(rotation), 3);
|
||||
}
|
||||
|
||||
*img = mSymbol->getPointSymbolAsImage( widthScale, selected, mSelectionColor, fieldScale, rotation, rasterScaleFactor);
|
||||
|
@ -34,7 +34,7 @@ class CORE_EXPORT QgsSingleSymbolRenderer: public QgsRenderer
|
||||
void addSymbol(QgsSymbol* sy);
|
||||
/*Returns a pointer to mSymbol*/
|
||||
const QgsSymbol* symbol() const;
|
||||
/**Renders an OGRFeature*/
|
||||
/**Renders a feature*/
|
||||
void renderFeature(QPainter* p, QgsFeature& f, QImage* img, bool selected, double widthScale = 1.0, double rasterScaleFactor = 1.0);
|
||||
/**Reads the renderer configuration from an XML file
|
||||
@param rnode the DOM node to read
|
||||
|
@ -165,7 +165,7 @@ void QgsUniqueValueRenderer::renderFeature(QPainter* p, QgsFeature& f,QImage* im
|
||||
}
|
||||
}
|
||||
|
||||
QgsSymbol* QgsUniqueValueRenderer::symbolForFeature(const QgsFeature* f)
|
||||
QgsSymbol *QgsUniqueValueRenderer::symbolForFeature(const QgsFeature *f)
|
||||
{
|
||||
//first find out the value
|
||||
const QgsAttributeMap& attrs = f->attributeMap();
|
||||
|
@ -30,7 +30,7 @@ class CORE_EXPORT QgsUniqueValueRenderer: public QgsRenderer
|
||||
virtual ~QgsUniqueValueRenderer();
|
||||
/** Determines if a feature will be rendered or not
|
||||
@param f a pointer to the feature to determine if rendering will happen*/
|
||||
bool willRenderFeature(QgsFeature *f);
|
||||
virtual bool willRenderFeature(QgsFeature *f);
|
||||
void renderFeature(QPainter* p, QgsFeature& f,QImage* img, bool selected, double widthScale = 1.0, double rasterScaleFactor = 1.0);
|
||||
/**Reads the renderer configuration from an XML file
|
||||
@param rnode the DOM node to read
|
||||
@ -64,7 +64,7 @@ class CORE_EXPORT QgsUniqueValueRenderer: public QgsRenderer
|
||||
/**Symbols for the unique values*/
|
||||
QMap<QString, QgsSymbol*> mSymbols;
|
||||
/**Returns the symbol for a feature or 0 if there isn't any*/
|
||||
QgsSymbol* symbolForFeature(const QgsFeature* f);
|
||||
QgsSymbol *symbolForFeature(const QgsFeature* f);
|
||||
/**Cached copy of all underlying symbols required attribute fields*/
|
||||
QgsAttributeList mSymbolAttributes;
|
||||
bool mSymbolAttributesDirty; // insertValue was called
|
||||
|
@ -324,7 +324,7 @@ QImage QgsSymbol::getCachedPointSymbolAsImage( double widthScale,
|
||||
}
|
||||
}
|
||||
|
||||
QImage QgsSymbol::getPointSymbolAsImage( double widthScale, bool selected, QColor selectionColor, double scale, \
|
||||
QImage QgsSymbol::getPointSymbolAsImage( double widthScale, bool selected, QColor selectionColor, double scale,
|
||||
double rotation, double rasterScaleFactor)
|
||||
{
|
||||
//QgsDebugMsg(QString("Symbol scale = %1, and rotation = %2").arg(scale).arg(rotation));
|
||||
|
@ -44,6 +44,8 @@ class QValidator;
|
||||
|
||||
// Must be here, so that it is included to moc file
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsfield.h"
|
||||
|
||||
class QgisInterface;
|
||||
class QgsMapCanvas;
|
||||
|
||||
@ -490,9 +492,9 @@ public:
|
||||
* \param qdesc option element in QGIS module description XML file
|
||||
* \param gdesc GRASS module XML description file
|
||||
*/
|
||||
QgsGrassModuleInput ( QgsGrassModule *module,
|
||||
QgsGrassModuleStandardOptions *options, QString key,
|
||||
QDomElement &qdesc, QDomElement &gdesc, QDomNode &gnode,
|
||||
QgsGrassModuleInput ( QgsGrassModule *module,
|
||||
QgsGrassModuleStandardOptions *options, QString key,
|
||||
QDomElement &qdesc, QDomElement &gdesc, QDomNode &gnode,
|
||||
QWidget * parent = 0 );
|
||||
|
||||
//! Destructor
|
||||
|
@ -37,7 +37,7 @@ class GPSData;
|
||||
*/
|
||||
class QgsGPXProvider : public QgsVectorDataProvider
|
||||
{
|
||||
Q_OBJECT;
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
|
@ -36,16 +36,6 @@ email : sherman at mrcc.com
|
||||
#include <QString>
|
||||
#include <QTextCodec>
|
||||
|
||||
//TODO Following ifndef can be removed once WIN32 GEOS support
|
||||
// is fixed
|
||||
#ifndef NOWIN32GEOSXXX
|
||||
//XXX GEOS support on windows is broken until we can get VC++ to
|
||||
// tolerate geos.h without throwing a bunch of type errors. It
|
||||
// appears that the windows version of GEOS may be compiled with
|
||||
// MINGW rather than VC++.
|
||||
#endif
|
||||
|
||||
|
||||
#include "qgsapplication.h"
|
||||
#include "qgsdataprovider.h"
|
||||
#include "qgsfeature.h"
|
||||
@ -134,13 +124,9 @@ QgsOgrProvider::QgsOgrProvider(QString const & uri)
|
||||
valid = false;
|
||||
}
|
||||
|
||||
// create the geos objects
|
||||
geometryFactory = new GEOS_GEOM::GeometryFactory();
|
||||
assert(geometryFactory!=0);
|
||||
|
||||
mSupportedNativeTypes.insert("Integer");
|
||||
mSupportedNativeTypes.insert("Real");
|
||||
mSupportedNativeTypes.insert("String");
|
||||
mSupportedNativeTypes.insert("Integer", QVariant::Int);
|
||||
mSupportedNativeTypes.insert("Real", QVariant::Double);
|
||||
mSupportedNativeTypes.insert("String", QVariant::String);
|
||||
}
|
||||
|
||||
QgsOgrProvider::~QgsOgrProvider()
|
||||
@ -149,7 +135,6 @@ QgsOgrProvider::~QgsOgrProvider()
|
||||
ogrDataSource = 0;
|
||||
free(extent_);
|
||||
extent_ = 0;
|
||||
delete geometryFactory;
|
||||
if( mSelectionRectangle )
|
||||
{
|
||||
OGR_G_DestroyGeometry( mSelectionRectangle );
|
||||
|
@ -19,23 +19,10 @@ email : sherman at mrcc.com
|
||||
#include "qgsrect.h"
|
||||
#include "qgsvectordataprovider.h"
|
||||
|
||||
#include <geos/version.h>
|
||||
#if GEOS_VERSION_MAJOR < 3
|
||||
#include <geos/geom.h>
|
||||
#define GEOS_GEOM geos
|
||||
#else
|
||||
#include <geos/geom/GeometryFactory.h>
|
||||
#define GEOS_GEOM geos::geom
|
||||
#endif
|
||||
|
||||
class QgsFeature;
|
||||
class QgsField;
|
||||
|
||||
typedef void *OGRDataSourceH;
|
||||
typedef void *OGRSFDriverH;
|
||||
typedef void *OGRLayerH;
|
||||
typedef void *OGRFeatureH;
|
||||
typedef void *OGRGeometryH;
|
||||
#include <ogr_api.h>
|
||||
|
||||
/**
|
||||
\class QgsOgrProvider
|
||||
@ -264,6 +251,4 @@ class QgsOgrProvider : public QgsVectorDataProvider
|
||||
bool addFeature(QgsFeature& f);
|
||||
/**Deletes one feature*/
|
||||
bool deleteFeature(int id);
|
||||
//! The geometry factory
|
||||
GEOS_GEOM::GeometryFactory *geometryFactory;
|
||||
};
|
||||
|
@ -49,7 +49,8 @@
|
||||
const QString POSTGRES_KEY = "postgres";
|
||||
const QString POSTGRES_DESCRIPTION = "PostgreSQL/PostGIS data provider";
|
||||
|
||||
QMap<QString, QgsPostgresProvider::Conn *> QgsPostgresProvider::connections;
|
||||
QMap<QString, QgsPostgresProvider::Conn *> QgsPostgresProvider::connectionsRO;
|
||||
QMap<QString, QgsPostgresProvider::Conn *> QgsPostgresProvider::connectionsRW;
|
||||
int QgsPostgresProvider::providerIds=0;
|
||||
|
||||
QgsPostgresProvider::QgsPostgresProvider(QString const & uri)
|
||||
@ -86,12 +87,9 @@ QgsPostgresProvider::QgsPostgresProvider(QString const & uri)
|
||||
QgsDebugMsg("Schema is: " + mSchemaName);
|
||||
QgsDebugMsg("Table name is: " + mTableName);
|
||||
|
||||
//QString logFile = "./pg_provider_" + mTableName + ".log";
|
||||
//pLog.open((const char *)logFile);
|
||||
//QgsDebugMsg("Opened log file for " + mTableName);
|
||||
|
||||
connection = connectDb( mUri.connInfo() );
|
||||
if( connection==NULL ) {
|
||||
connectionRW = NULL;
|
||||
connectionRO = connectDb( mUri.connInfo() );
|
||||
if( connectionRO==NULL ) {
|
||||
valid = false;
|
||||
return;
|
||||
}
|
||||
@ -100,7 +98,7 @@ QgsPostgresProvider::QgsPostgresProvider(QString const & uri)
|
||||
the problems they will see :) */
|
||||
QgsDebugMsg("Checking for GEOS support");
|
||||
|
||||
if(!hasGEOS(connection))
|
||||
if(!hasGEOS(connectionRO))
|
||||
{
|
||||
showMessageBox(tr("No GEOS Support!"),
|
||||
tr("Your PostGIS installation has no GEOS support.\n"
|
||||
@ -114,7 +112,7 @@ QgsPostgresProvider::QgsPostgresProvider(QString const & uri)
|
||||
// Check that we can read from the table (i.e., we have
|
||||
// select permission).
|
||||
QString sql = QString("select * from %1 limit 1").arg(mSchemaTableName);
|
||||
PGresult* testAccess = PQexec(connection, sql.toUtf8());
|
||||
PGresult* testAccess = PQexec(connectionRO, sql.toUtf8());
|
||||
if (PQresultStatus(testAccess) != PGRES_TUPLES_OK)
|
||||
{
|
||||
showMessageBox(tr("Unable to access relation"),
|
||||
@ -136,7 +134,7 @@ QgsPostgresProvider::QgsPostgresProvider(QString const & uri)
|
||||
"current_schema()")
|
||||
.arg( quotedValue(mSchemaTableName) );
|
||||
|
||||
testAccess = PQexec( connection, sql.toUtf8() );
|
||||
testAccess = PQexec( connectionRO, sql.toUtf8() );
|
||||
if( PQresultStatus(testAccess) != PGRES_TUPLES_OK ) {
|
||||
showMessageBox(tr("Unable to access relation"),
|
||||
tr("Unable to determine table access privileges for the ") + mSchemaTableName +
|
||||
@ -181,7 +179,7 @@ QgsPostgresProvider::QgsPostgresProvider(QString const & uri)
|
||||
"relname=%1 AND nspname=%2")
|
||||
.arg( quotedValue(mTableName) )
|
||||
.arg( quotedValue(mSchemaName) );
|
||||
testAccess = PQexec(connection, sql.toUtf8());
|
||||
testAccess = PQexec(connectionRO, sql.toUtf8());
|
||||
if (PQresultStatus(testAccess) == PGRES_TUPLES_OK && PQntuples(testAccess)==1)
|
||||
{
|
||||
enabledCapabilities |= QgsVectorDataProvider::AddAttributes | QgsVectorDataProvider::DeleteAttributes;
|
||||
@ -212,7 +210,7 @@ QgsPostgresProvider::QgsPostgresProvider(QString const & uri)
|
||||
// Set the postgresql message level so that we don't get the
|
||||
// 'there is no transaction in progress' warning.
|
||||
#ifndef QGISDEBUG
|
||||
PQexecNR(connection, QString("set client_min_messages to error").toUtf8());
|
||||
PQexecNR(connectionRO, QString("set client_min_messages to error").toUtf8());
|
||||
#endif
|
||||
|
||||
// Kick off the long running threads
|
||||
@ -240,11 +238,11 @@ QgsPostgresProvider::QgsPostgresProvider(QString const & uri)
|
||||
#endif
|
||||
|
||||
//fill type names into sets
|
||||
mSupportedNativeTypes.insert("double precision");
|
||||
mSupportedNativeTypes.insert("int4");
|
||||
mSupportedNativeTypes.insert("int8");
|
||||
mSupportedNativeTypes.insert("text");
|
||||
mSupportedNativeTypes.insert("varchar(30)");
|
||||
mSupportedNativeTypes.insert("double precision", QVariant::Double);
|
||||
mSupportedNativeTypes.insert("int4", QVariant::Int);
|
||||
mSupportedNativeTypes.insert("int8", QVariant::LongLong);
|
||||
mSupportedNativeTypes.insert("text", QVariant::String);
|
||||
mSupportedNativeTypes.insert("varchar(30)", QVariant::String);
|
||||
|
||||
if (primaryKey.isEmpty())
|
||||
{
|
||||
@ -284,8 +282,10 @@ QgsPostgresProvider::~QgsPostgresProvider()
|
||||
//pLog.flush();
|
||||
}
|
||||
|
||||
PGconn *QgsPostgresProvider::connectDb(const QString & conninfo)
|
||||
PGconn *QgsPostgresProvider::connectDb(const QString & conninfo, bool readonly)
|
||||
{
|
||||
QMap<QString, QgsPostgresProvider::Conn *> &connections = readonly ? connectionsRO : connectionsRW;
|
||||
|
||||
if( connections.contains(conninfo) )
|
||||
{
|
||||
QgsDebugMsg( QString("Using cached connection for %1").arg(conninfo) );
|
||||
@ -333,24 +333,42 @@ void QgsPostgresProvider::disconnectDb()
|
||||
{
|
||||
if(mFetching)
|
||||
{
|
||||
PQexecNR(connection, QString("CLOSE qgisf%1").arg(providerId).toUtf8() );
|
||||
PQexecNR(connectionRO, QString("CLOSE qgisf%1").arg(providerId).toUtf8() );
|
||||
mFetching=false;
|
||||
}
|
||||
|
||||
QMap<QString, Conn *>::iterator i;
|
||||
for(i=connections.begin(); i!=connections.end() && i.value()->conn!=connection; i++)
|
||||
;
|
||||
if(!connectionRO) {
|
||||
QMap<QString, Conn *>::iterator i;
|
||||
for(i=connectionsRO.begin(); i!=connectionsRO.end() && i.value()->conn!=connectionRO; i++)
|
||||
;
|
||||
|
||||
assert( i.value()->conn==connection );
|
||||
assert( i.value()->ref>0 );
|
||||
assert( i.value()->conn==connectionRO );
|
||||
assert( i.value()->ref>0 );
|
||||
|
||||
if( --i.value()->ref==0 ) {
|
||||
PQfinish( connection );
|
||||
delete i.value();
|
||||
connections.remove( i.key() );
|
||||
if( --i.value()->ref==0 ) {
|
||||
PQfinish( connectionRO );
|
||||
delete i.value();
|
||||
connectionsRO.remove( i.key() );
|
||||
}
|
||||
|
||||
connectionRO = 0;
|
||||
|
||||
if(connectionRW) {
|
||||
for(i=connectionsRW.begin(); i!=connectionsRW.end() && i.value()->conn!=connectionRW; i++)
|
||||
;
|
||||
|
||||
assert( i.value()->conn==connectionRW );
|
||||
assert( i.value()->ref>0 );
|
||||
|
||||
if( --i.value()->ref==0 ) {
|
||||
PQfinish( connectionRW );
|
||||
delete i.value();
|
||||
connectionsRW.remove( i.key() );
|
||||
}
|
||||
|
||||
connectionRW = 0;
|
||||
}
|
||||
}
|
||||
|
||||
connection = 0;
|
||||
}
|
||||
|
||||
QString QgsPostgresProvider::storageType() const
|
||||
@ -409,7 +427,7 @@ bool QgsPostgresProvider::declareCursor(const QString &cursorName,
|
||||
|
||||
QgsDebugMsg("Binary cursor: " + declare);
|
||||
|
||||
return PQexecNR(connection, declare.toUtf8());
|
||||
return PQexecNR(connectionRO, declare.toUtf8());
|
||||
}
|
||||
catch(PGFieldNotFound)
|
||||
{
|
||||
@ -515,7 +533,7 @@ void QgsPostgresProvider::select(QgsAttributeList fetchAttributes, QgsRect rect,
|
||||
|
||||
if(mFetching)
|
||||
{
|
||||
PQexecNR(connection, QString("CLOSE %1").arg(cursorName).toUtf8() );
|
||||
PQexecNR(connectionRO, QString("CLOSE %1").arg(cursorName).toUtf8() );
|
||||
mFetching=false;
|
||||
|
||||
while(!mFeatureQueue.empty())
|
||||
@ -575,13 +593,13 @@ bool QgsPostgresProvider::getNextFeature(QgsFeature& feature)
|
||||
if( mFeatureQueue.empty() )
|
||||
{
|
||||
QString fetch = QString("fetch forward %1 from %2").arg(mFeatureQueueSize).arg(cursorName);
|
||||
if(PQsendQuery(connection, fetch.toUtf8()) == 0) //fetch features in asynchronously
|
||||
if(PQsendQuery(connectionRO, fetch.toUtf8()) == 0) //fetch features in asynchronously
|
||||
{
|
||||
qWarning("PQsendQuery failed (1)");
|
||||
}
|
||||
|
||||
PGresult *queryResult;
|
||||
while( (queryResult = PQgetResult(connection)) )
|
||||
while( (queryResult = PQgetResult(connectionRO)) )
|
||||
{
|
||||
int rows = PQntuples(queryResult);
|
||||
if (rows == 0)
|
||||
@ -627,7 +645,7 @@ bool QgsPostgresProvider::getFeatureAtId(int featureId, QgsFeature& feature, boo
|
||||
if( !declareCursor( cursorName, fetchAttributes, fetchGeometry, QString("%2=%3").arg(quotedIdentifier(primaryKey)).arg(featureId) ) )
|
||||
return false;
|
||||
|
||||
PGresult *queryResult = PQexec(connection, QString("fetch forward 1 from %1").arg(cursorName).toUtf8());
|
||||
PGresult *queryResult = PQexec(connectionRO, QString("fetch forward 1 from %1").arg(cursorName).toUtf8());
|
||||
if(queryResult==0)
|
||||
return false;
|
||||
|
||||
@ -636,7 +654,7 @@ bool QgsPostgresProvider::getFeatureAtId(int featureId, QgsFeature& feature, boo
|
||||
{
|
||||
QgsDebugMsg("feature " + QString::number(featureId) + " not found");
|
||||
PQclear(queryResult);
|
||||
PQexecNR(connection, QString("CLOSE %1").arg(cursorName).toUtf8());
|
||||
PQexecNR(connectionRO, QString("CLOSE %1").arg(cursorName).toUtf8());
|
||||
return false;
|
||||
}
|
||||
else if(rows != 1)
|
||||
@ -648,7 +666,7 @@ bool QgsPostgresProvider::getFeatureAtId(int featureId, QgsFeature& feature, boo
|
||||
|
||||
PQclear(queryResult);
|
||||
|
||||
PQexecNR(connection, QString("CLOSE %1").arg(cursorName).toUtf8());
|
||||
PQexecNR(connectionRO, QString("CLOSE %1").arg(cursorName).toUtf8());
|
||||
|
||||
return gotit;
|
||||
}
|
||||
@ -724,7 +742,7 @@ void QgsPostgresProvider::reset()
|
||||
if(mFetching)
|
||||
{
|
||||
//move cursor to first record
|
||||
PQexecNR(connection, QString("move 0 in qgisf%1").arg(providerId).toUtf8());
|
||||
PQexecNR(connectionRO, QString("move 0 in qgisf%1").arg(providerId).toUtf8());
|
||||
}
|
||||
mFeatureQueue.empty();
|
||||
loadFields();
|
||||
@ -752,13 +770,13 @@ void QgsPostgresProvider::loadFields()
|
||||
|
||||
// Get the relation oid for use in later queries
|
||||
QString sql = QString("SELECT regclass(%1)::oid").arg( quotedValue(mSchemaTableName) );
|
||||
PGresult *tresult= PQexec(connection, sql.toUtf8());
|
||||
PGresult *tresult= PQexec(connectionRO, sql.toUtf8());
|
||||
QString tableoid = QString::fromUtf8(PQgetvalue(tresult, 0, 0));
|
||||
PQclear(tresult);
|
||||
|
||||
// Get the table description
|
||||
sql = QString("SELECT description FROM pg_description WHERE objoid=%1 AND objsubid=0").arg( tableoid );
|
||||
tresult = PQexec(connection, sql.toUtf8());
|
||||
tresult = PQexec(connectionRO, sql.toUtf8());
|
||||
if (PQntuples(tresult) > 0)
|
||||
mDataComment = QString::fromUtf8(PQgetvalue(tresult, 0, 0));
|
||||
PQclear(tresult);
|
||||
@ -767,7 +785,7 @@ void QgsPostgresProvider::loadFields()
|
||||
// field name, type, length, and precision (if numeric)
|
||||
sql = QString("select * from %1 limit 0").arg ( mSchemaTableName );
|
||||
|
||||
PGresult *result = PQexec(connection, sql.toUtf8());
|
||||
PGresult *result = PQexec(connectionRO, sql.toUtf8());
|
||||
//--std::cout << "Field: Name, Type, Size, Modifier:" << std::endl;
|
||||
|
||||
// The queries inside this loop could possibly be combined into one
|
||||
@ -787,7 +805,7 @@ void QgsPostgresProvider::loadFields()
|
||||
// "oid = (SELECT Distinct typelem FROM pg_type WHERE " //needs DISTINCT to guard against 2 or more rows on int2
|
||||
// "typelem = " + typOid + " AND typlen = -1)";
|
||||
|
||||
PGresult* oidResult = PQexec(connection, sql.toUtf8());
|
||||
PGresult* oidResult = PQexec(connectionRO, sql.toUtf8());
|
||||
QString fieldTypeName = QString::fromUtf8(PQgetvalue(oidResult, 0, 0));
|
||||
QString fieldSize = QString::fromUtf8(PQgetvalue(oidResult, 0, 1));
|
||||
PQclear(oidResult);
|
||||
@ -795,14 +813,14 @@ void QgsPostgresProvider::loadFields()
|
||||
sql = QString("SELECT attnum FROM pg_attribute WHERE attrelid=%1 AND attname=%2")
|
||||
.arg( tableoid ).arg( quotedValue(fieldName) );
|
||||
|
||||
PGresult *tresult = PQexec(connection, sql.toUtf8());
|
||||
PGresult *tresult = PQexec(connectionRO, sql.toUtf8());
|
||||
QString attnum = QString::fromUtf8(PQgetvalue(tresult, 0, 0));
|
||||
PQclear(tresult);
|
||||
|
||||
sql = QString("SELECT description FROM pg_description WHERE objoid=%1 AND objsubid=%2")
|
||||
.arg( tableoid ).arg( attnum );
|
||||
|
||||
tresult = PQexec(connection, sql.toUtf8());
|
||||
tresult = PQexec(connectionRO, sql.toUtf8());
|
||||
if (PQntuples(tresult) > 0)
|
||||
fieldComment = QString::fromUtf8(PQgetvalue(tresult, 0, 0));
|
||||
PQclear(tresult);
|
||||
@ -859,7 +877,7 @@ QString QgsPostgresProvider::getPrimaryKey()
|
||||
|
||||
QgsDebugMsg("Getting unique index using '" + sql + "'");
|
||||
|
||||
PGresult *pk = executeDbCommand(connection, sql);
|
||||
PGresult *pk = executeDbCommand(connectionRO, sql);
|
||||
|
||||
QgsDebugMsg("Got " + QString::number(PQntuples(pk)) + " rows.");
|
||||
|
||||
@ -877,7 +895,7 @@ QString QgsPostgresProvider::getPrimaryKey()
|
||||
|
||||
sql = QString("SELECT relkind FROM pg_class WHERE oid=regclass(%1)::oid")
|
||||
.arg( quotedValue(mSchemaTableName) );
|
||||
PGresult* tableType = executeDbCommand(connection, sql);
|
||||
PGresult* tableType = executeDbCommand(connectionRO, sql);
|
||||
QString type = QString::fromUtf8(PQgetvalue(tableType, 0, 0));
|
||||
PQclear(tableType);
|
||||
|
||||
@ -892,7 +910,7 @@ QString QgsPostgresProvider::getPrimaryKey()
|
||||
sql = QString("SELECT attname FROM pg_attribute WHERE attname='oid' AND attrelid=regclass(%1)")
|
||||
.arg( quotedValue(mSchemaTableName) );
|
||||
|
||||
PGresult* oidCheck = executeDbCommand(connection, sql);
|
||||
PGresult* oidCheck = executeDbCommand(connectionRO, sql);
|
||||
|
||||
if (PQntuples(oidCheck) != 0)
|
||||
{
|
||||
@ -940,7 +958,7 @@ QString QgsPostgresProvider::getPrimaryKey()
|
||||
// Get the column name and data type
|
||||
sql = QString("select attname,pg_type.typname from pg_attribute,pg_type where atttypid=pg_type.oid and attnum=%1 and attrelid=regclass(%2)")
|
||||
.arg( col ).arg( quotedValue(mSchemaTableName) );
|
||||
PGresult* types = executeDbCommand(connection, sql);
|
||||
PGresult* types = executeDbCommand(connectionRO, sql);
|
||||
|
||||
if( PQntuples(types) > 0 )
|
||||
{
|
||||
@ -968,7 +986,7 @@ QString QgsPostgresProvider::getPrimaryKey()
|
||||
.arg( col.replace(" ", ",") )
|
||||
.arg( quotedValue(mSchemaTableName) );
|
||||
|
||||
PGresult* types = executeDbCommand(connection, sql);
|
||||
PGresult* types = executeDbCommand(connectionRO, sql);
|
||||
QString colNames;
|
||||
int numCols = PQntuples(types);
|
||||
for (int j = 0; j < numCols; ++j)
|
||||
@ -1002,7 +1020,7 @@ QString QgsPostgresProvider::getPrimaryKey()
|
||||
// If there is an oid on the table, use that instead,
|
||||
// otherwise give up
|
||||
sql = QString("select attname from pg_attribute where attname='oid' and attrelid=regclass(%1)::oid").arg( quotedValue(mSchemaTableName) );
|
||||
PGresult* oidCheck = executeDbCommand(connection, sql);
|
||||
PGresult* oidCheck = executeDbCommand(connectionRO, sql);
|
||||
|
||||
if (PQntuples(oidCheck) != 0)
|
||||
{
|
||||
@ -1069,7 +1087,7 @@ QString QgsPostgresProvider::chooseViewColumn(const tableCols& cols)
|
||||
// Get the oid from pg_class for the given schema.relation for use
|
||||
// in subsequent queries.
|
||||
sql = QString("select regclass(%1)::oid").arg( quotedValue( quotedIdentifier(schemaName) + "." + quotedIdentifier(tableName) ) );
|
||||
PGresult* result = PQexec(connection, sql.toUtf8());
|
||||
PGresult* result = PQexec(connectionRO, sql.toUtf8());
|
||||
QString rel_oid;
|
||||
if (PQntuples(result) == 1)
|
||||
{
|
||||
@ -1100,7 +1118,7 @@ QString QgsPostgresProvider::chooseViewColumn(const tableCols& cols)
|
||||
"and conrelid=%2 and (contype='p' or contype='u') "
|
||||
"and array_dims(conkey)='[1:1]'").arg( quotedValue(tableCol) ).arg( rel_oid );
|
||||
|
||||
result = PQexec(connection, sql.toUtf8());
|
||||
result = PQexec(connectionRO, sql.toUtf8());
|
||||
if (PQntuples(result) == 1 && colType == "int4")
|
||||
suitable[viewCol] = iter->second;
|
||||
|
||||
@ -1159,7 +1177,7 @@ QString QgsPostgresProvider::chooseViewColumn(const tableCols& cols)
|
||||
sql = QString( "select * from pg_index where indrelid=%1 and indkey[0]=(select attnum from pg_attribute where attrelid=%1 and attname=%2)")
|
||||
.arg( rel_oid )
|
||||
.arg( quotedValue( i->second.column ) );
|
||||
PGresult* result = PQexec(connection, sql.toUtf8());
|
||||
PGresult* result = PQexec(connectionRO, sql.toUtf8());
|
||||
|
||||
if (PQntuples(result) > 0 && uniqueData(mSchemaName, mTableName, i->first))
|
||||
{ // Got one. Use it.
|
||||
@ -1245,7 +1263,7 @@ bool QgsPostgresProvider::uniqueData(QString schemaName,
|
||||
.arg( quotedIdentifier(schemaName) )
|
||||
.arg( quotedIdentifier(tableName) );
|
||||
|
||||
PGresult* unique = PQexec(connection, sql.toUtf8());
|
||||
PGresult* unique = PQexec(connectionRO, sql.toUtf8());
|
||||
|
||||
if (PQntuples(unique)==1 && QString::fromUtf8(PQgetvalue(unique, 0, 0)).startsWith("t"))
|
||||
isUnique = true;
|
||||
@ -1259,7 +1277,7 @@ int QgsPostgresProvider::SRCFromViewColumn(const QString& ns, const QString& rel
|
||||
{
|
||||
QString newViewDefSql = QString("SELECT definition FROM pg_views WHERE schemaname=%1 AND viewname=%2")
|
||||
.arg( quotedValue(ns) ).arg( quotedValue(relname) );
|
||||
PGresult* newViewDefResult = PQexec(connection, newViewDefSql.toUtf8());
|
||||
PGresult* newViewDefResult = PQexec(connectionRO, newViewDefSql.toUtf8());
|
||||
int numEntries = PQntuples(newViewDefResult);
|
||||
|
||||
if(numEntries > 0) //relation is a view
|
||||
@ -1335,7 +1353,7 @@ int QgsPostgresProvider::SRCFromViewColumn(const QString& ns, const QString& rel
|
||||
.arg( quotedValue(relname) )
|
||||
.arg( quotedValue(newAttNameTable) );
|
||||
|
||||
PGresult* viewColumnResult = PQexec(connection, viewColumnSql.toUtf8());
|
||||
PGresult* viewColumnResult = PQexec(connectionRO, viewColumnSql.toUtf8());
|
||||
if(PQntuples(viewColumnResult) > 0)
|
||||
{
|
||||
QString newTableSchema = QString::fromUtf8(PQgetvalue(viewColumnResult, 0, 0));
|
||||
@ -1373,7 +1391,7 @@ int QgsPostgresProvider::SRCFromViewColumn(const QString& ns, const QString& rel
|
||||
.arg( quotedValue(ns) )
|
||||
.arg( quotedValue(attname_table) );
|
||||
|
||||
PGresult* typeSqlResult = PQexec(connection, typeSql.toUtf8());
|
||||
PGresult* typeSqlResult = PQexec(connectionRO, typeSql.toUtf8());
|
||||
if(PQntuples(typeSqlResult) < 1)
|
||||
{
|
||||
return 1;
|
||||
@ -1446,13 +1464,13 @@ void QgsPostgresProvider::findColumns(tableCols& cols)
|
||||
"view_schema=%1 AND view_name=%2")
|
||||
.arg( quotedValue(mSchemaName) )
|
||||
.arg( quotedValue(mTableName) );
|
||||
PGresult* viewColumnResult = PQexec(connection, viewColumnSql.toUtf8());
|
||||
PGresult* viewColumnResult = PQexec(connectionRO, viewColumnSql.toUtf8());
|
||||
|
||||
//find out view definition
|
||||
QString viewDefSql = QString("SELECT definition FROM pg_views WHERE schemaname=%1 AND viewname=%2")
|
||||
.arg( quotedValue( mSchemaName ) )
|
||||
.arg( quotedValue( mTableName ) );
|
||||
PGresult* viewDefResult = PQexec(connection, viewDefSql.toUtf8());
|
||||
PGresult* viewDefResult = PQexec(connectionRO, viewDefSql.toUtf8());
|
||||
if(PQntuples(viewDefResult) < 1)
|
||||
{
|
||||
PQclear(viewDefResult);
|
||||
@ -1523,7 +1541,7 @@ QVariant QgsPostgresProvider::minValue(int index)
|
||||
.arg(mSchemaTableName)
|
||||
.arg(sqlWhereClause);
|
||||
}
|
||||
PGresult *rmin = PQexec(connection, sql.toUtf8());
|
||||
PGresult *rmin = PQexec(connectionRO, sql.toUtf8());
|
||||
QString minValue = QString::fromUtf8(PQgetvalue(rmin,0,0));
|
||||
PQclear(rmin);
|
||||
return minValue.toDouble();
|
||||
@ -1558,7 +1576,7 @@ void QgsPostgresProvider::getUniqueValues(int index, QStringList &uniqueValues)
|
||||
.arg(sqlWhereClause);
|
||||
}
|
||||
|
||||
PGresult *res= PQexec(connection, sql.toUtf8());
|
||||
PGresult *res= PQexec(connectionRO, sql.toUtf8());
|
||||
if (PQresultStatus(res) == PGRES_TUPLES_OK)
|
||||
{
|
||||
for(int i=0; i<PQntuples(res); i++)
|
||||
@ -1593,7 +1611,7 @@ QVariant QgsPostgresProvider::maxValue(int index)
|
||||
.arg(mSchemaTableName)
|
||||
.arg(sqlWhereClause);
|
||||
}
|
||||
PGresult *rmax = PQexec(connection, sql.toUtf8());
|
||||
PGresult *rmax = PQexec(connectionRO, sql.toUtf8());
|
||||
QString maxValue = QString::fromUtf8(PQgetvalue(rmax,0,0));
|
||||
PQclear(rmax);
|
||||
return maxValue.toDouble();
|
||||
@ -1613,7 +1631,7 @@ int QgsPostgresProvider::maxPrimaryKeyValue()
|
||||
.arg(quotedIdentifier(primaryKey))
|
||||
.arg(mSchemaTableName);
|
||||
|
||||
PGresult *rmax = PQexec(connection, sql.toUtf8());
|
||||
PGresult *rmax = PQexec(connectionRO, sql.toUtf8());
|
||||
QString maxValue = QString::fromUtf8(PQgetvalue(rmax,0,0));
|
||||
PQclear(rmax);
|
||||
|
||||
@ -1645,7 +1663,7 @@ QVariant QgsPostgresProvider::getDefaultValue(int fieldId)
|
||||
|
||||
QVariant defaultValue(QString::null);
|
||||
|
||||
PGresult* result = PQexec(connection, sql.toUtf8());
|
||||
PGresult* result = PQexec(connectionRO, sql.toUtf8());
|
||||
|
||||
if (PQntuples(result)==1 && !PQgetisnull(result, 0, 0) )
|
||||
defaultValue = QString::fromUtf8(PQgetvalue(result, 0, 0));
|
||||
@ -1723,7 +1741,7 @@ QByteArray QgsPostgresProvider::paramValue(QString fieldValue, const QString &de
|
||||
|
||||
if( fieldValue==defaultValue && !defaultValue.isNull() )
|
||||
{
|
||||
PGresult *result = PQexec( connection, QString("select %1").arg(defaultValue).toUtf8() );
|
||||
PGresult *result = PQexec( connectionRO, QString("select %1").arg(defaultValue).toUtf8() );
|
||||
if( PQgetisnull(result, 0, 0) ) {
|
||||
PQclear(result);
|
||||
return QByteArray(0); // QByteArray(0).isNull() is true
|
||||
@ -1742,10 +1760,13 @@ bool QgsPostgresProvider::addFeatures(QgsFeatureList & flist)
|
||||
if( flist.size() == 0 )
|
||||
return true;
|
||||
|
||||
if( !connectRW() )
|
||||
return false;
|
||||
|
||||
bool returnvalue=true;
|
||||
|
||||
try {
|
||||
PQexecNR(connection,QString("BEGIN").toUtf8());
|
||||
PQexecNR(connectionRW,QString("BEGIN").toUtf8());
|
||||
|
||||
// Prepare the INSERT statement
|
||||
QString insert = QString("INSERT INTO %1(%2,%3")
|
||||
@ -1820,7 +1841,7 @@ bool QgsPostgresProvider::addFeatures(QgsFeatureList & flist)
|
||||
insert += values + ")";
|
||||
|
||||
QgsDebugMsg( QString("prepare addfeatures: %1").arg(insert) );
|
||||
PGresult *stmt = PQprepare(connection, "addfeatures", insert.toUtf8(), fieldId.size()+2, NULL);
|
||||
PGresult *stmt = PQprepare(connectionRW, "addfeatures", insert.toUtf8(), fieldId.size()+2, NULL);
|
||||
if(stmt==0 || PQresultStatus(stmt)==PGRES_FATAL_ERROR)
|
||||
throw PGException(stmt);
|
||||
|
||||
@ -1852,7 +1873,7 @@ bool QgsPostgresProvider::addFeatures(QgsFeatureList & flist)
|
||||
param[i+2] = qparam[i+2];
|
||||
}
|
||||
|
||||
PGresult *result = PQexecPrepared(connection, "addfeatures", fieldId.size()+2, param, NULL, NULL, 0);
|
||||
PGresult *result = PQexecPrepared(connectionRW, "addfeatures", fieldId.size()+2, param, NULL, NULL, 0);
|
||||
if( result==0 || PQresultStatus(result)==PGRES_FATAL_ERROR )
|
||||
{
|
||||
delete param;
|
||||
@ -1862,14 +1883,13 @@ bool QgsPostgresProvider::addFeatures(QgsFeatureList & flist)
|
||||
PQclear(result);
|
||||
}
|
||||
|
||||
PQexecNR(connection,QString("COMMIT").toUtf8());
|
||||
PQexecNR(connection,QString("DEALLOCATE addfeatures").toUtf8());
|
||||
PQexecNR(connectionRW,QString("DEALLOCATE addfeatures").toUtf8());
|
||||
PQexecNR(connectionRW,QString("COMMIT").toUtf8());
|
||||
delete param;
|
||||
} catch(PGException &e) {
|
||||
e.showErrorMessage( tr("Error while adding features") );
|
||||
PQexecNR(connection,QString("ROLLBACK").toUtf8());
|
||||
|
||||
PQexecNR(connection,QString("DEALLOCATE addfeatures").toUtf8());
|
||||
PQexecNR(connectionRW,QString("DEALLOCATE addfeatures").toUtf8());
|
||||
PQexecNR(connectionRW,QString("ROLLBACK").toUtf8());
|
||||
returnvalue = false;
|
||||
}
|
||||
|
||||
@ -1881,8 +1901,11 @@ bool QgsPostgresProvider::deleteFeatures(const QgsFeatureIds & id)
|
||||
{
|
||||
bool returnvalue=true;
|
||||
|
||||
if( !connectRW() )
|
||||
return false;
|
||||
|
||||
try {
|
||||
PQexecNR(connection,QString("BEGIN").toUtf8());
|
||||
PQexecNR(connectionRW,QString("BEGIN").toUtf8());
|
||||
|
||||
for(QgsFeatureIds::const_iterator it=id.begin();it!=id.end();++it) {
|
||||
QString sql = QString("DELETE FROM %1 WHERE %2=%3")
|
||||
@ -1892,16 +1915,16 @@ bool QgsPostgresProvider::deleteFeatures(const QgsFeatureIds & id)
|
||||
QgsDebugMsg("delete sql: "+sql);
|
||||
|
||||
//send DELETE statement and do error handling
|
||||
PGresult* result=PQexec(connection, sql.toUtf8());
|
||||
PGresult* result=PQexec(connectionRW, sql.toUtf8());
|
||||
if( result==0 || PQresultStatus(result)==PGRES_FATAL_ERROR )
|
||||
throw PGException(result);
|
||||
PQclear(result);
|
||||
}
|
||||
|
||||
PQexecNR(connection,QString("COMMIT").toUtf8());
|
||||
PQexecNR(connectionRW,QString("COMMIT").toUtf8());
|
||||
} catch(PGException &e) {
|
||||
e.showErrorMessage( tr("Error while deleting features") );
|
||||
PQexecNR(connection,QString("ROLLBACK").toUtf8());
|
||||
PQexecNR(connectionRW,QString("ROLLBACK").toUtf8());
|
||||
returnvalue = false;
|
||||
}
|
||||
reset();
|
||||
@ -1912,8 +1935,11 @@ bool QgsPostgresProvider::addAttributes(const QgsNewAttributesMap & name)
|
||||
{
|
||||
bool returnvalue=true;
|
||||
|
||||
if( !connectRW() )
|
||||
return false;
|
||||
|
||||
try {
|
||||
PQexecNR(connection,QString("BEGIN").toUtf8());
|
||||
PQexecNR(connectionRW,QString("BEGIN").toUtf8());
|
||||
|
||||
for(QgsNewAttributesMap::const_iterator iter=name.begin();iter!=name.end();++iter)
|
||||
{
|
||||
@ -1924,16 +1950,16 @@ bool QgsPostgresProvider::addAttributes(const QgsNewAttributesMap & name)
|
||||
QgsDebugMsg(sql);
|
||||
|
||||
//send sql statement and do error handling
|
||||
PGresult* result=PQexec(connection, sql.toUtf8());
|
||||
PGresult* result=PQexec(connectionRW, sql.toUtf8());
|
||||
if( result==0 || PQresultStatus(result)==PGRES_FATAL_ERROR )
|
||||
throw PGException(result);
|
||||
PQclear(result);
|
||||
}
|
||||
|
||||
PQexecNR(connection,QString("COMMIT").toUtf8());
|
||||
PQexecNR(connectionRW,QString("COMMIT").toUtf8());
|
||||
} catch(PGException &e) {
|
||||
e.showErrorMessage( tr("Error while adding attributes") );
|
||||
PQexecNR(connection,QString("ROLLBACK").toUtf8());
|
||||
PQexecNR(connectionRW,QString("ROLLBACK").toUtf8());
|
||||
returnvalue = false;
|
||||
}
|
||||
|
||||
@ -1945,8 +1971,11 @@ bool QgsPostgresProvider::deleteAttributes(const QgsAttributeIds& ids)
|
||||
{
|
||||
bool returnvalue=true;
|
||||
|
||||
if( !connectRW() )
|
||||
return false;
|
||||
|
||||
try {
|
||||
PQexecNR(connection,QString("BEGIN").toUtf8());
|
||||
PQexecNR(connectionRW,QString("BEGIN").toUtf8());
|
||||
|
||||
for(QgsAttributeIds::const_iterator iter=ids.begin();iter != ids.end();++iter)
|
||||
{
|
||||
@ -1960,7 +1989,7 @@ bool QgsPostgresProvider::deleteAttributes(const QgsAttributeIds& ids)
|
||||
.arg(quotedIdentifier(column));
|
||||
|
||||
//send sql statement and do error handling
|
||||
PGresult* result=PQexec(connection, sql.toUtf8());
|
||||
PGresult* result=PQexec(connectionRW, sql.toUtf8());
|
||||
if( result==0 || PQresultStatus(result)==PGRES_FATAL_ERROR )
|
||||
throw PGException(result);
|
||||
PQclear(result);
|
||||
@ -1969,10 +1998,10 @@ bool QgsPostgresProvider::deleteAttributes(const QgsAttributeIds& ids)
|
||||
attributeFields.remove(*iter);
|
||||
}
|
||||
|
||||
PQexecNR(connection,QString("COMMIT").toUtf8());
|
||||
PQexecNR(connectionRW,QString("COMMIT").toUtf8());
|
||||
} catch(PGException &e) {
|
||||
e.showErrorMessage( tr("Error while deleting attributes") );
|
||||
PQexecNR(connection,QString("ROLLBACK").toUtf8());
|
||||
PQexecNR(connectionRW,QString("ROLLBACK").toUtf8());
|
||||
returnvalue = false;
|
||||
}
|
||||
|
||||
@ -1984,8 +2013,11 @@ bool QgsPostgresProvider::changeAttributeValues(const QgsChangedAttributesMap &
|
||||
{
|
||||
bool returnvalue=true;
|
||||
|
||||
if( !connectRW() )
|
||||
return false;
|
||||
|
||||
try {
|
||||
PQexecNR(connection,QString("BEGIN").toUtf8());
|
||||
PQexecNR(connectionRW,QString("BEGIN").toUtf8());
|
||||
|
||||
// cycle through the features
|
||||
for(QgsChangedAttributesMap::const_iterator iter=attr_map.begin();iter!=attr_map.end();++iter)
|
||||
@ -2026,17 +2058,17 @@ bool QgsPostgresProvider::changeAttributeValues(const QgsChangedAttributesMap &
|
||||
.arg( quotedIdentifier(primaryKey) )
|
||||
.arg( fid );
|
||||
|
||||
PGresult* result=PQexec(connection, sql.toUtf8());
|
||||
PGresult* result=PQexec(connectionRW, sql.toUtf8());
|
||||
if( result==0 || PQresultStatus(result)==PGRES_FATAL_ERROR )
|
||||
throw PGException(result);
|
||||
|
||||
PQclear(result);
|
||||
}
|
||||
|
||||
PQexecNR(connection,QString("COMMIT").toUtf8());
|
||||
PQexecNR(connectionRW,QString("COMMIT").toUtf8());
|
||||
} catch(PGException &e) {
|
||||
e.showErrorMessage( tr("Error while changing attributes") );
|
||||
PQexecNR(connection,QString("ROLLBACK").toUtf8());
|
||||
PQexecNR(connectionRW,QString("ROLLBACK").toUtf8());
|
||||
returnvalue = false;
|
||||
}
|
||||
|
||||
@ -2061,11 +2093,14 @@ bool QgsPostgresProvider::changeGeometryValues(QgsGeometryMap & geometry_map)
|
||||
{
|
||||
QgsDebugMsg("entering.");
|
||||
|
||||
if( !connectRW() )
|
||||
return false;
|
||||
|
||||
bool returnvalue = true;
|
||||
|
||||
try {
|
||||
// Start the PostGIS transaction
|
||||
PQexecNR(connection,QString("BEGIN").toUtf8());
|
||||
PQexecNR(connectionRW,QString("BEGIN").toUtf8());
|
||||
|
||||
QString update = QString("UPDATE %1 SET %2=GeomFromWKB($1%3,%4) WHERE %5=$2")
|
||||
.arg( mSchemaTableName )
|
||||
@ -2074,7 +2109,7 @@ bool QgsPostgresProvider::changeGeometryValues(QgsGeometryMap & geometry_map)
|
||||
.arg( srid )
|
||||
.arg( quotedIdentifier(primaryKey) );
|
||||
|
||||
PGresult *stmt = PQprepare(connection, "updatefeatures", update.toUtf8(), 2, NULL);
|
||||
PGresult *stmt = PQprepare(connectionRW, "updatefeatures", update.toUtf8(), 2, NULL);
|
||||
if(stmt==0 || PQresultStatus(stmt)==PGRES_FATAL_ERROR)
|
||||
throw PGException(stmt);
|
||||
|
||||
@ -2102,7 +2137,7 @@ bool QgsPostgresProvider::changeGeometryValues(QgsGeometryMap & geometry_map)
|
||||
param[0] = qparam[0];
|
||||
param[1] = qparam[1];
|
||||
|
||||
PGresult *result = PQexecPrepared(connection, "updatefeatures", 2, param, NULL, NULL, 0);
|
||||
PGresult *result = PQexecPrepared(connectionRW, "updatefeatures", 2, param, NULL, NULL, 0);
|
||||
if( result==0 || PQresultStatus(result)==PGRES_FATAL_ERROR )
|
||||
throw PGException(result);
|
||||
|
||||
@ -2111,12 +2146,12 @@ bool QgsPostgresProvider::changeGeometryValues(QgsGeometryMap & geometry_map)
|
||||
|
||||
} // for each feature
|
||||
|
||||
PQexecNR(connection,QString("COMMIT").toUtf8());
|
||||
PQexecNR(connection,QString("DEALLOCATE updatefeatures").toUtf8());
|
||||
PQexecNR(connectionRW,QString("DEALLOCATE updatefeatures").toUtf8());
|
||||
PQexecNR(connectionRW,QString("COMMIT").toUtf8());
|
||||
} catch(PGException &e) {
|
||||
e.showErrorMessage( tr("Error while changing geometry values") );
|
||||
PQexecNR(connection,QString("ROLLBACK").toUtf8());
|
||||
PQexecNR(connection,QString("DEALLOCATE updatefeatures").toUtf8());
|
||||
PQexecNR(connectionRW,QString("DEALLOCATE updatefeatures").toUtf8());
|
||||
PQexecNR(connectionRW,QString("ROLLBACK").toUtf8());
|
||||
returnvalue = false;
|
||||
}
|
||||
|
||||
@ -2176,7 +2211,7 @@ long QgsPostgresProvider::getFeatureCount()
|
||||
}
|
||||
#endif
|
||||
|
||||
PGresult *result = PQexec(connection, sql.toUtf8());
|
||||
PGresult *result = PQexec(connectionRO, sql.toUtf8());
|
||||
|
||||
QgsDebugMsg("Approximate Number of features as text: " +
|
||||
QString::fromUtf8(PQgetvalue(result, 0, 0)));
|
||||
@ -2219,7 +2254,7 @@ void QgsPostgresProvider::calculateExtents()
|
||||
|
||||
QgsDebugMsg("Getting approximate extent using: '" + sql + "'");
|
||||
|
||||
PGresult *result = PQexec(connection, sql.toUtf8());
|
||||
PGresult *result = PQexec(connectionRO, sql.toUtf8());
|
||||
|
||||
// TODO: Guard against the result having no rows
|
||||
|
||||
@ -2271,7 +2306,7 @@ void QgsPostgresProvider::calculateExtents()
|
||||
|
||||
QgsDebugMsg("Getting extents using schema.table: " + sql);
|
||||
|
||||
PGresult *result = PQexec(connection, sql.toUtf8());
|
||||
PGresult *result = PQexec(connectionRO, sql.toUtf8());
|
||||
if(PQntuples(result)>0)
|
||||
{
|
||||
std::string box3d = PQgetvalue(result, 0, 0);
|
||||
@ -2390,7 +2425,7 @@ bool QgsPostgresProvider::deduceEndian()
|
||||
// return data in the endian of the server
|
||||
|
||||
QString firstOid = QString("select regclass(%1)::oid").arg( quotedValue(mSchemaTableName) );
|
||||
PGresult * oidResult = PQexec(connection, firstOid.toUtf8());
|
||||
PGresult * oidResult = PQexec(connectionRO, firstOid.toUtf8());
|
||||
// get the int value from a "normal" select
|
||||
QString oidValue = QString::fromUtf8(PQgetvalue(oidResult,0,0));
|
||||
PQclear(oidResult);
|
||||
@ -2401,12 +2436,12 @@ bool QgsPostgresProvider::deduceEndian()
|
||||
|
||||
QString oidDeclare = QString("declare oidcursor binary cursor with hold for select regclass(%1)::oid").arg( quotedValue(mSchemaTableName) );
|
||||
// set up the cursor
|
||||
PQexecNR(connection, oidDeclare.toUtf8());
|
||||
PQexecNR(connectionRO, oidDeclare.toUtf8());
|
||||
QString fetch = "fetch forward 1 from oidcursor";
|
||||
|
||||
QgsDebugMsg("Fetching a record and attempting to get check endian-ness");
|
||||
|
||||
PGresult *fResult = PQexec(connection, fetch.toUtf8());
|
||||
PGresult *fResult = PQexec(connectionRO, fetch.toUtf8());
|
||||
swapEndian = true;
|
||||
if(PQntuples(fResult) > 0){
|
||||
// get the oid value from the binary cursor
|
||||
@ -2420,7 +2455,7 @@ bool QgsPostgresProvider::deduceEndian()
|
||||
|
||||
PQclear(fResult);
|
||||
}
|
||||
PQexecNR(connection, QString("close oidcursor").toUtf8());
|
||||
PQexecNR(connectionRO, QString("close oidcursor").toUtf8());
|
||||
return swapEndian;
|
||||
}
|
||||
|
||||
@ -2439,7 +2474,7 @@ bool QgsPostgresProvider::getGeometryDetails()
|
||||
|
||||
QgsDebugMsg("Getting geometry column: " + sql);
|
||||
|
||||
PGresult *result = executeDbCommand(connection, sql);
|
||||
PGresult *result = executeDbCommand(connectionRO, sql);
|
||||
|
||||
QgsDebugMsg("geometry column query returned " + QString::number(PQntuples(result)));
|
||||
|
||||
@ -2467,7 +2502,7 @@ bool QgsPostgresProvider::getGeometryDetails()
|
||||
|
||||
sql += " limit 1";
|
||||
|
||||
result = executeDbCommand(connection, sql);
|
||||
result = executeDbCommand(connectionRO, sql);
|
||||
|
||||
if (PQntuples(result) > 0)
|
||||
{
|
||||
@ -2493,7 +2528,7 @@ bool QgsPostgresProvider::getGeometryDetails()
|
||||
if(mUri.sql()!="")
|
||||
sql += " where " + mUri.sql();
|
||||
|
||||
result = executeDbCommand(connection, sql);
|
||||
result = executeDbCommand(connectionRO, sql);
|
||||
|
||||
if (PQntuples(result)==1)
|
||||
{
|
||||
@ -2665,7 +2700,7 @@ QString QgsPostgresProvider::subsetString()
|
||||
|
||||
PGconn * QgsPostgresProvider::pgConnection()
|
||||
{
|
||||
return connection;
|
||||
return connectionRW;
|
||||
}
|
||||
|
||||
QString QgsPostgresProvider::getTableName()
|
||||
|
@ -47,10 +47,9 @@ class QgsGeometry;
|
||||
interface defined in the QgsDataProvider class to provide access to spatial
|
||||
data residing in a PostgreSQL/PostGIS enabled database.
|
||||
*/
|
||||
class QgsPostgresProvider:public QgsVectorDataProvider
|
||||
class QgsPostgresProvider : public QgsVectorDataProvider
|
||||
{
|
||||
|
||||
Q_OBJECT
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
/**
|
||||
@ -405,7 +404,18 @@ class QgsPostgresProvider:public QgsVectorDataProvider
|
||||
/**
|
||||
* Connection pointer
|
||||
*/
|
||||
PGconn *connection;
|
||||
PGconn *connectionRO;
|
||||
PGconn *connectionRW;
|
||||
|
||||
bool connectRW() {
|
||||
if(connectionRW)
|
||||
return connectionRW;
|
||||
|
||||
connectionRW = connectDb(mUri.connInfo(), false);
|
||||
|
||||
return connectionRW;
|
||||
}
|
||||
|
||||
/**
|
||||
* Spatial reference id of the layer
|
||||
*/
|
||||
@ -584,7 +594,7 @@ class QgsPostgresProvider:public QgsVectorDataProvider
|
||||
*/
|
||||
void customEvent ( QEvent *e );
|
||||
|
||||
PGconn *connectDb(const QString &conninfo);
|
||||
PGconn *connectDb(const QString &conninfo, bool readonly=true);
|
||||
void disconnectDb();
|
||||
|
||||
bool useWkbHex;
|
||||
@ -605,7 +615,8 @@ class QgsPostgresProvider:public QgsVectorDataProvider
|
||||
int ref;
|
||||
PGconn *conn;
|
||||
};
|
||||
static QMap<QString, Conn *> connections;
|
||||
static QMap<QString, Conn *> connectionsRW;
|
||||
static QMap<QString, Conn *> connectionsRO;
|
||||
static int providerIds;
|
||||
};
|
||||
|
||||
|
@ -13,27 +13,20 @@
|
||||
<string>Attribute Table</string>
|
||||
</property>
|
||||
<property name="windowIcon" >
|
||||
<iconset/>
|
||||
<iconset>
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<property name="leftMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="horizontalSpacing" >
|
||||
<number>6</number>
|
||||
</property>
|
||||
<property name="verticalSpacing" >
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="margin" >
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0" >
|
||||
<widget class="QToolButton" name="mRemoveSelectionButton" >
|
||||
<property name="toolTip" >
|
||||
@ -43,7 +36,8 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset>../xpm/remove_selection.xpm</iconset>
|
||||
<iconset>
|
||||
<normaloff>../xpm/remove_selection.xpm</normaloff>../xpm/remove_selection.xpm</iconset>
|
||||
</property>
|
||||
<property name="shortcut" >
|
||||
<string/>
|
||||
@ -59,7 +53,8 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset>../xpm/selected_to_top.png</iconset>
|
||||
<iconset>
|
||||
<normaloff>../xpm/selected_to_top.png</normaloff>../xpm/selected_to_top.png</iconset>
|
||||
</property>
|
||||
<property name="shortcut" >
|
||||
<string>Ctrl+T</string>
|
||||
@ -75,7 +70,8 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset>../xpm/switch_selection.png</iconset>
|
||||
<iconset>
|
||||
<normaloff>../xpm/switch_selection.png</normaloff>../xpm/switch_selection.png</iconset>
|
||||
</property>
|
||||
<property name="shortcut" >
|
||||
<string>Ctrl+S</string>
|
||||
@ -94,7 +90,8 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset>../xpm/copy_selection.png</iconset>
|
||||
<iconset>
|
||||
<normaloff>../xpm/copy_selection.png</normaloff>../xpm/copy_selection.png</iconset>
|
||||
</property>
|
||||
<property name="shortcut" >
|
||||
<string>Ctrl+C</string>
|
||||
@ -117,66 +114,12 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="5" >
|
||||
<widget class="QToolButton" name="mAddAttributeButton" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip" >
|
||||
<string>New column</string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset>../xpm/new_attribute.png</iconset>
|
||||
</property>
|
||||
<property name="shortcut" >
|
||||
<string>Ctrl+N</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="6" >
|
||||
<widget class="QToolButton" name="mDeleteAttributeButton" >
|
||||
<property name="toolTip" >
|
||||
<string>Delete column</string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset>../xpm/delete_attribute.png</iconset>
|
||||
</property>
|
||||
<property name="shortcut" >
|
||||
<string>Ctrl+X</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="7" >
|
||||
<widget class="QToolButton" name="btnEdit" >
|
||||
<property name="toolTip" >
|
||||
<string>Toggle editing mode</string>
|
||||
</property>
|
||||
<property name="whatsThis" >
|
||||
<string>Click to toggle table editing</string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string/>
|
||||
</property>
|
||||
<property name="checkable" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="8" >
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<property name="sizeHint" stdset="0" >
|
||||
<size>
|
||||
<width>421</width>
|
||||
<height>20</height>
|
||||
@ -184,17 +127,7 @@
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="9" >
|
||||
<widget class="QgsAttributeTable" native="1" name="tblAttributes" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="9" >
|
||||
<item row="2" column="0" colspan="7" >
|
||||
<layout class="QHBoxLayout" >
|
||||
<item>
|
||||
<widget class="QLabel" name="textLabel1" >
|
||||
@ -251,10 +184,36 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="9" >
|
||||
<item row="3" column="0" colspan="7" >
|
||||
<widget class="QDialogButtonBox" name="buttonBox" >
|
||||
<property name="standardButtons" >
|
||||
<set>QDialogButtonBox::Close|QDialogButtonBox::Help|QDialogButtonBox::NoButton</set>
|
||||
<set>QDialogButtonBox::Close|QDialogButtonBox::Help</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="7" >
|
||||
<widget class="QgsAttributeTable" native="1" name="tblAttributes" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="5" >
|
||||
<widget class="QToolButton" name="mToggleEditingButton" >
|
||||
<property name="toolTip" >
|
||||
<string>Toggle editing mode</string>
|
||||
</property>
|
||||
<property name="whatsThis" >
|
||||
<string>Click to toggle table editing</string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string/>
|
||||
</property>
|
||||
<property name="checkable" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -274,9 +233,6 @@
|
||||
<tabstop>mInvertSelectionButton</tabstop>
|
||||
<tabstop>mCopySelectedRowsButton</tabstop>
|
||||
<tabstop>mZoomMapToSelectedRowsButton</tabstop>
|
||||
<tabstop>mAddAttributeButton</tabstop>
|
||||
<tabstop>mDeleteAttributeButton</tabstop>
|
||||
<tabstop>btnEdit</tabstop>
|
||||
<tabstop>mSearchText</tabstop>
|
||||
<tabstop>mSearchColumns</tabstop>
|
||||
<tabstop>mSearchButton</tabstop>
|
||||
|
@ -213,6 +213,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2" >
|
||||
<widget class="QCheckBox" name="cbxAttributeTableDocked" >
|
||||
<property name="text" >
|
||||
<string>Open attribute table in a dock window</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@ -223,8 +230,8 @@
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>547</width>
|
||||
<height>51</height>
|
||||
<width>577</width>
|
||||
<height>21</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
|
@ -5,8 +5,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>552</width>
|
||||
<height>600</height>
|
||||
<width>839</width>
|
||||
<height>675</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize" >
|
||||
@ -19,21 +19,287 @@
|
||||
<string>Layer Properties</string>
|
||||
</property>
|
||||
<property name="windowIcon" >
|
||||
<iconset/>
|
||||
<iconset>
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
</property>
|
||||
<property name="modal" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<item row="1" column="0" >
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="spacing" >
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="margin" >
|
||||
<number>1</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbnLoadDefaultStyle" >
|
||||
<property name="text" >
|
||||
<string>Restore Default Style</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbnSaveDefaultStyle" >
|
||||
<property name="text" >
|
||||
<string>Save As Default</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbnLoadStyle" >
|
||||
<property name="text" >
|
||||
<string>Load Style ...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbnSaveStyleAs" >
|
||||
<property name="text" >
|
||||
<string>Save Style ...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="0" >
|
||||
<widget class="QDialogButtonBox" name="buttonBox" >
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons" >
|
||||
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" >
|
||||
<widget class="QTabWidget" name="tabWidget" >
|
||||
<property name="enabled" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="autoFillBackground" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="tabShape" >
|
||||
<enum>QTabWidget::Rounded</enum>
|
||||
</property>
|
||||
<property name="currentIndex" >
|
||||
<number>0</number>
|
||||
<number>5</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab1" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>817</width>
|
||||
<height>557</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="title" >
|
||||
<string>General</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="0" >
|
||||
<widget class="QGroupBox" name="indexGroupBox" >
|
||||
<property name="title" >
|
||||
<string>Options</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="0" >
|
||||
<widget class="QLabel" name="textLabel3" >
|
||||
<property name="text" >
|
||||
<string>Display name</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>txtDisplayName</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="2" >
|
||||
<widget class="QLineEdit" name="txtDisplayName" />
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QLabel" name="textLabel2" >
|
||||
<property name="toolTip" >
|
||||
<string>Display field for the Identify Results dialog box</string>
|
||||
</property>
|
||||
<property name="whatsThis" >
|
||||
<string>This sets the display field for the Identify Results dialog box</string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Display field</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>displayFieldComboBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="2" >
|
||||
<widget class="QComboBox" name="displayFieldComboBox" >
|
||||
<property name="whatsThis" >
|
||||
<string>Use this control to set which field is placed at the top level of the Identify Results dialog box.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="3" >
|
||||
<widget class="QLineEdit" name="leSpatialRefSys" >
|
||||
<property name="readOnly" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1" >
|
||||
<widget class="QPushButton" name="pbnIndex" >
|
||||
<property name="text" >
|
||||
<string>Create Spatial Index</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2" >
|
||||
<widget class="QPushButton" name="pbnChangeSpatialRefSys" >
|
||||
<property name="text" >
|
||||
<string>Change CRS</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QGroupBox" name="chkUseScaleDependentRendering" >
|
||||
<property name="title" >
|
||||
<string>Use scale dependent rendering</string>
|
||||
</property>
|
||||
<property name="checkable" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<property name="margin" >
|
||||
<number>11</number>
|
||||
</property>
|
||||
<item row="0" column="2" >
|
||||
<widget class="QLabel" name="textLabel1_2_2" >
|
||||
<property name="text" >
|
||||
<string>Maximum</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>spinMaximumScale</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" >
|
||||
<widget class="QLabel" name="textLabel1" >
|
||||
<property name="text" >
|
||||
<string>Minimum</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>spinMinimumScale</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" >
|
||||
<widget class="QSpinBox" name="spinMinimumScale" >
|
||||
<property name="toolTip" >
|
||||
<string>Minimum scale at which this layer will be displayed. </string>
|
||||
</property>
|
||||
<property name="minimum" >
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum" >
|
||||
<number>100000000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3" >
|
||||
<widget class="QSpinBox" name="spinMaximumScale" >
|
||||
<property name="toolTip" >
|
||||
<string>Maximum scale at which this layer will be displayed. </string>
|
||||
</property>
|
||||
<property name="minimum" >
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum" >
|
||||
<number>100000000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" >
|
||||
<widget class="QGroupBox" name="grpSubset" >
|
||||
<property name="title" >
|
||||
<string>Subset</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<property name="margin" >
|
||||
<number>11</number>
|
||||
</property>
|
||||
<item row="0" column="0" colspan="2" >
|
||||
<widget class="QTextEdit" name="txtSubsetSQL" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="acceptDrops" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="acceptRichText" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0" >
|
||||
<size>
|
||||
<width>480</width>
|
||||
<height>21</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="1" >
|
||||
<widget class="QPushButton" name="pbnQueryBuilder" >
|
||||
<property name="text" >
|
||||
<string>Query Builder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab2" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>817</width>
|
||||
<height>552</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<attribute name="title" >
|
||||
<string>Symbology</string>
|
||||
</attribute>
|
||||
@ -134,227 +400,44 @@
|
||||
<property name="currentIndex" >
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="page" />
|
||||
<widget class="QWidget" name="page_2" />
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab2" >
|
||||
<attribute name="title" >
|
||||
<string>General</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="0" >
|
||||
<widget class="QGroupBox" name="indexGroupBox" >
|
||||
<property name="title" >
|
||||
<string>Options</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<item row="0" column="0" >
|
||||
<widget class="QLabel" name="textLabel3" >
|
||||
<property name="text" >
|
||||
<string>Display name</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>txtDisplayName</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="2" >
|
||||
<widget class="QLineEdit" name="txtDisplayName" />
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QLabel" name="textLabel2" >
|
||||
<property name="toolTip" >
|
||||
<string>Display field for the Identify Results dialog box</string>
|
||||
</property>
|
||||
<property name="whatsThis" >
|
||||
<string>This sets the display field for the Identify Results dialog box</string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string>Display field</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>displayFieldComboBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="2" >
|
||||
<widget class="QComboBox" name="displayFieldComboBox" >
|
||||
<property name="whatsThis" >
|
||||
<string>Use this control to set which field is placed at the top level of the Identify Results dialog box.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="3" >
|
||||
<widget class="QLineEdit" name="leSpatialRefSys" >
|
||||
<property name="readOnly" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1" >
|
||||
<widget class="QPushButton" name="pbnIndex" >
|
||||
<property name="text" >
|
||||
<string>Create Spatial Index</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2" >
|
||||
<widget class="QPushButton" name="pbnChangeSpatialRefSys" >
|
||||
<property name="text" >
|
||||
<string>Change CRS</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<widget class="QGroupBox" name="chkUseScaleDependentRendering" >
|
||||
<property name="title" >
|
||||
<string>Use scale dependent rendering</string>
|
||||
</property>
|
||||
<property name="checkable" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<property name="leftMargin" >
|
||||
<number>11</number>
|
||||
<widget class="QWidget" name="page" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>100</width>
|
||||
<height>30</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="topMargin" >
|
||||
<number>11</number>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_2" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>799</width>
|
||||
<height>502</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="rightMargin" >
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="bottomMargin" >
|
||||
<number>11</number>
|
||||
</property>
|
||||
<item row="0" column="2" >
|
||||
<widget class="QLabel" name="textLabel1_2_2" >
|
||||
<property name="text" >
|
||||
<string>Maximum</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>spinMaximumScale</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" >
|
||||
<widget class="QLabel" name="textLabel1" >
|
||||
<property name="text" >
|
||||
<string>Minimum</string>
|
||||
</property>
|
||||
<property name="buddy" >
|
||||
<cstring>spinMinimumScale</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" >
|
||||
<widget class="QSpinBox" name="spinMinimumScale" >
|
||||
<property name="toolTip" >
|
||||
<string>Minimum scale at which this layer will be displayed. </string>
|
||||
</property>
|
||||
<property name="minimum" >
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum" >
|
||||
<number>100000000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3" >
|
||||
<widget class="QSpinBox" name="spinMaximumScale" >
|
||||
<property name="toolTip" >
|
||||
<string>Maximum scale at which this layer will be displayed. </string>
|
||||
</property>
|
||||
<property name="minimum" >
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum" >
|
||||
<number>100000000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" >
|
||||
<widget class="QGroupBox" name="grpSubset" >
|
||||
<property name="title" >
|
||||
<string>Subset</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" >
|
||||
<property name="leftMargin" >
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="topMargin" >
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="rightMargin" >
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="bottomMargin" >
|
||||
<number>11</number>
|
||||
</property>
|
||||
<item row="0" column="0" colspan="2" >
|
||||
<widget class="QTextEdit" name="txtSubsetSQL" >
|
||||
<property name="enabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="acceptDrops" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="acceptRichText" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<spacer>
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType" >
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" >
|
||||
<size>
|
||||
<width>480</width>
|
||||
<height>21</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="1" >
|
||||
<widget class="QPushButton" name="pbnQueryBuilder" >
|
||||
<property name="text" >
|
||||
<string>Query Builder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab3" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>817</width>
|
||||
<height>552</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="title" >
|
||||
<string>Metadata</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" >
|
||||
<property name="leftMargin" >
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="topMargin" >
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="rightMargin" >
|
||||
<number>11</number>
|
||||
</property>
|
||||
<property name="bottomMargin" >
|
||||
<property name="margin" >
|
||||
<number>11</number>
|
||||
</property>
|
||||
<item row="0" column="0" >
|
||||
@ -370,6 +453,14 @@
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab4" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>817</width>
|
||||
<height>552</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="title" >
|
||||
<string>Labels</string>
|
||||
</attribute>
|
||||
@ -406,6 +497,14 @@
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab5" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>817</width>
|
||||
<height>552</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="title" >
|
||||
<string>Actions</string>
|
||||
</attribute>
|
||||
@ -428,63 +527,118 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" >
|
||||
<layout class="QHBoxLayout" >
|
||||
<property name="spacing" >
|
||||
<number>3</number>
|
||||
</property>
|
||||
<property name="leftMargin" >
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="topMargin" >
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="rightMargin" >
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="bottomMargin" >
|
||||
<number>1</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbnLoadDefaultStyle" >
|
||||
<property name="text" >
|
||||
<string>Restore Default Style</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbnSaveDefaultStyle" >
|
||||
<property name="text" >
|
||||
<string>Save As Default</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbnLoadStyle" >
|
||||
<property name="text" >
|
||||
<string>Load Style ...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pbnSaveStyleAs" >
|
||||
<property name="text" >
|
||||
<string>Save Style ...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="0" >
|
||||
<widget class="QDialogButtonBox" name="buttonBox" >
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons" >
|
||||
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab6" >
|
||||
<property name="geometry" >
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>817</width>
|
||||
<height>557</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="title" >
|
||||
<string>Attributes</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout" >
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" >
|
||||
<property name="sizeConstraint" >
|
||||
<enum>QLayout::SetNoConstraint</enum>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QToolButton" name="mAddAttributeButton" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip" >
|
||||
<string>New column</string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset>
|
||||
<normaloff>../xpm/new_attribute.png</normaloff>../xpm/new_attribute.png</iconset>
|
||||
</property>
|
||||
<property name="shortcut" >
|
||||
<string>Ctrl+N</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="mDeleteAttributeButton" >
|
||||
<property name="toolTip" >
|
||||
<string>Delete column</string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon" >
|
||||
<iconset>
|
||||
<normaloff>../xpm/delete_attribute.png</normaloff>../xpm/delete_attribute.png</iconset>
|
||||
</property>
|
||||
<property name="shortcut" >
|
||||
<string>Ctrl+X</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="mToggleEditingButton" >
|
||||
<property name="toolTip" >
|
||||
<string>Toggle editing mode</string>
|
||||
</property>
|
||||
<property name="whatsThis" >
|
||||
<string>Click to toggle table editing</string>
|
||||
</property>
|
||||
<property name="text" >
|
||||
<string/>
|
||||
</property>
|
||||
<property name="checkable" >
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer" >
|
||||
<property name="orientation" >
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0" >
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTableWidget" name="tblAttributes" >
|
||||
<property name="sizePolicy" >
|
||||
<sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize" >
|
||||
<size>
|
||||
<width>256</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sortingEnabled" >
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<zorder>tblAttributes</zorder>
|
||||
<zorder></zorder>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
Loading…
x
Reference in New Issue
Block a user