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:
jef 2008-08-20 12:15:14 +00:00
parent 03ef707a0d
commit 43278d720b
63 changed files with 4123 additions and 3848 deletions

View File

@ -13,18 +13,6 @@ class QgsFeature
//! Constructor //! Constructor
QgsFeature(int id = 0, QString typeName = "" ); 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 */ /** copy ctor needed due to internal pointer */
QgsFeature(const QgsFeature & rhs ); QgsFeature(const QgsFeature & rhs );

View File

@ -88,7 +88,6 @@ class QgsVectorDataProvider : QgsDataProvider
*/ */
virtual QGis::WKBTYPE geometryType() const = 0; virtual QGis::WKBTYPE geometryType() const = 0;
/** /**
* Number of features in the layer * Number of features in the layer
* @return long containing number of features * @return long containing number of features
@ -230,7 +229,7 @@ class QgsVectorDataProvider : QgsDataProvider
QList<int> allAttributesList(); QList<int> allAttributesList();
/**Returns the names of the numerical types*/ /**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 * Set whether provider should return also features that don't have

View File

@ -1,12 +1,27 @@
class QgsVectorLayer : QgsMapLayer class QgsVectorLayer : QgsMapLayer
{ {
%TypeHeaderCode %TypeHeaderCode
#include <qgsvectorlayer.h> #include "qgsvectorlayer.h"
%End %End
public: 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 */ /** Constructor */
QgsVectorLayer(QString baseName = 0, QString path = 0, QString providerLib = 0); 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 */ /** Returns the bounding box of the selected features. If there is no selection, QgsRect(0,0,0,0) is returned */
QgsRect boundingBoxOfSelected(); 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 */ /** Copies the symbology settings from another layer. Returns true in case of success */
bool copySymbologySettings(const QgsMapLayer& other); bool copySymbologySettings(const QgsMapLayer& other);
@ -92,12 +103,12 @@ public:
QString providerType() const; QString providerType() const;
/** reads vector layer specific state from project file DOM node. /** 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 ); virtual bool readXml( QDomNode & layer_node );
/** write vector layer specific state to project file DOM 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 ); virtual bool writeXml( QDomNode & layer_node, QDomDocument & doc );
@ -130,17 +141,20 @@ public:
*/ */
virtual QString subsetString(); virtual QString subsetString();
/**Returns the features contained in the rectangle. Considers the changed, added, deleted and permanent features void select(QList<int> fetchAttributes = QList<int>(),
@return 0 in case of success*/ QgsRect rect = QgsRect(),
int featuresInRectangle(const QgsRect& searchRect, QList<QgsFeature>& features /Out/, bool fetchGeometries = true, bool fetchAttributes = true); 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*/ @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 /** Adds a feature
@param lastFeatureInBatch If True, will also go to the effort of e.g. updating the extents. @param alsoUpdateExtent 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 @return True in case of success and False in case of error
*/ */
bool addFeature(QgsFeature& f, bool alsoUpdateExtent = TRUE); bool addFeature(QgsFeature& f, bool alsoUpdateExtent = TRUE);
@ -168,49 +182,60 @@ public:
bool deleteSelectedFeatures(); bool deleteSelectedFeatures();
/**Adds a ring to polygon/multipolygon features /**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 \ @return
existing rings, 5 no feature found where ring can be inserted*/ 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); int addRing(const QList<QgsPoint>& ring);
/**Adds a new island polygon to a multipolygon feature /**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, \ @return
3 if new polygon ring not disjoint with existing rings, 4 if no feature was selected, 5 if several features are selected, \ 0 in case of success,
6 if selected geometry not found*/ 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); 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 featureId id of the feature to translate
@param dx translation of x-coordinate @param dx translation of x-coordinate
@param dy translation of y-coordinate @param dy translation of y-coordinate
@return 0 in case of success*/ @return 0 in case of success*/
int translateFeature(int featureId, double dx, double dy); 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 splitLine line that splits the layer features
@param topologicalEditing true if topological editing is enabled @param topologicalEditing true if topological editing is enabled
@return 0 in case of success, 1 if several intersections but only 1 split done, \ @return
2 if intersection too complex to be handled, else other error*/ 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); 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 polygon (or multipolygon) geometries in this vector layer
@param geom geometry to modify @param geom geometry to modify
@return 0 in case of success*/ @return 0 in case of success*/
int removePolygonIntersections(QgsGeometry* geom); int removePolygonIntersections(QgsGeometry* geom);
/**Adds topological points for every vertex of the /**Adds topological points for every vertex of the geometry
geometry @param geom the geometry where each vertex is added to segments of other features
@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
Note: geom is not going to be modified by the function @return 0 in case of success*/
@return 0 in case of success*/
int addTopologicalPoints(QgsGeometry* geom); int addTopologicalPoints(QgsGeometry* geom);
/**Adds a vertex to segments which intersect point p but don't /**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, 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 no additional vertex is inserted. This method is usefull for topological
editing. editing.
@param p position of the vertex @param p position of the vertex
@return 0 in case of success*/ @return 0 in case of success*/
int addTopologicalPoints(const QgsPoint& p); int addTopologicalPoints(const QgsPoint& p);
/**Inserts vertices to the snapped segments. /**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 @return 0 in case of success
*/ */
int snapWithContext(const QgsPoint& startPoint, double snappingTolerance, QMultiMap<double, QgsSnappingResult>& snappingResults /Out/, int snapWithContext(const QgsPoint& startPoint, double snappingTolerance, QMultiMap<double, QgsSnappingResult>& snappingResults /Out/,
QgsSnapper::SNAP_TO snap_to); 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);
/** Draws the layer using coordinate transformation /** Draws the layer using coordinate transformation
* @return FALSE if an error occurred during drawing * @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); void drawLabels(QPainter * p, const QgsRect& viewExtent, const QgsMapToPixel* cXf, const QgsCoordinateTransform* ct, double scale);
/** returns array of added features */ /** returns list of attributes */
QList<QgsFeature>& addedFeatures(); QList<int> pendingAllAttributesList();
/** returns array of deleted feature IDs */ /** returns fields list which are not commited */
QSet<int>& deletedFeatureIds(); const QMap<int, QgsField> &pendingFields();
/** returns array of features with changed attributes */
QMap<int, QMap<int, QVariant> >& changedAttributes();
/** returns feature count after commit */
int pendingFeatureCount();
/** Sets whether some features are modified or not */ /** Sets whether some features are modified or not */
void setModified(bool modified = TRUE, bool onlyGeometryWasModified = FALSE); void setModified(bool modified = TRUE, bool onlyGeometryWasModified = FALSE);
/** Make layer editable */ /** Make layer editable */
bool startEditing(); 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. 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(); bool commitChanges();
const QStringList &commitErrors();
/** Stop editing and discard the edits */ /** Stop editing and discard the edits */
bool rollBack(); 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: public slots:
/** Select feature by its ID, optionally emit signal selectionChanged() */ /** 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 */ /** This signal is emitted when modifications has been done on layer */
void wasModified(bool onlyGeometry); 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 private: // Private methods
/** vector layers are not copyable */ /** vector layers are not copyable */

View File

@ -36,9 +36,8 @@
#include "qgsproject.h" #include "qgsproject.h"
#include "qgsrasterlayer.h" #include "qgsrasterlayer.h"
#include "qgsrasterlayerproperties.h" #include "qgsrasterlayerproperties.h"
#include "qgsvectorlayer.h"
#include "qgsvectorlayerproperties.h" #include "qgsvectorlayerproperties.h"
#include "qgsvectordataprovider.h" #include "qgsattributetabledisplay.h"
#include <cfloat> #include <cfloat>
#include <iostream> #include <iostream>
@ -1811,29 +1810,39 @@ void QgsLegend::legendLayerZoomNative()
void QgsLegend::legendLayerAttributeTable() void QgsLegend::legendLayerAttributeTable()
{ {
if(!mMapCanvas || mMapCanvas->isDrawing()) if(!mMapCanvas || mMapCanvas->isDrawing())
{ {
return; return;
} }
QgsVectorLayer *vlayer = 0;
// try whether it's a legend layer // try whether it's a legend layer
QgsLegendLayer* ll = dynamic_cast<QgsLegendLayer*>(currentItem()); QgsLegendLayer* ll = dynamic_cast<QgsLegendLayer*>(currentItem());
if (ll) if (ll)
{ {
ll->table(); vlayer = dynamic_cast<QgsVectorLayer*>(ll->firstMapLayer());
return;
} }
// try whether it's a legend layer file if(!vlayer) {
QgsLegendLayerFile* llf = dynamic_cast<QgsLegendLayerFile*>(currentItem()); // try whether it's a legend layer file
if (llf) QgsLegendLayerFile* llf = dynamic_cast<QgsLegendLayerFile*>(currentItem());
{ if (llf)
llf->table(); {
return; vlayer = dynamic_cast<QgsVectorLayer*>(llf->layer());
}
} }
// nothing selected if(vlayer)
QMessageBox::information(this, tr("No Layer Selected"), {
tr("To open an attribute table, you must select a vector layer in the legend")); 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) void QgsLegend::readProject(const QDomDocument & doc)

View File

@ -43,7 +43,7 @@
QgsLegendLayerFile::QgsLegendLayerFile(QTreeWidgetItem * theLegendItem, QString theString, QgsMapLayer* theLayer) 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 // Set the initial visibility flag for layers
// This user option allows the user to turn off inital drawing of // 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); QgsVectorLayer *isVectLyr = dynamic_cast < QgsVectorLayer * >(currentLayer);
if (isVectLyr) if (isVectLyr)
{ {
// get notifications of changed selection - used to update attribute table connect(mLyr.layer(), SIGNAL(editingStarted()), this, SLOT(updateLegendItem()));
connect(mLyr.layer(), SIGNAL(selectionChanged()), this, SLOT(selectionChanged())); connect(mLyr.layer(), SIGNAL(editingStopped()), this, SLOT(updateLegendItem()));
// 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(layerNameChanged()), this, SLOT(layerNameChanged())); 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) QgsLegendItem::DRAG_ACTION QgsLegendLayerFile::accept(LEGEND_ITEM_TYPE type)
{ {
return NO_ACTION; return NO_ACTION;
@ -219,112 +208,16 @@ void QgsLegendLayerFile::showInOverview()
legend()->updateOverview(); 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() void QgsLegendLayerFile::saveAsShapefile()
{ {
saveAsShapefileGeneral(FALSE); saveAsShapefileGeneral(FALSE);
} }
void QgsLegendLayerFile::table()
{
QgsAttributeTableDisplay::attributeTable( dynamic_cast<QgsVectorLayer*>(mLyr.layer()) );
}
void QgsLegendLayerFile::saveSelectionAsShapefile() void QgsLegendLayerFile::saveSelectionAsShapefile()
{ {
saveAsShapefileGeneral(TRUE); 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() bool QgsLegendLayerFile::isEditing()
{ {
QgsVectorLayer* vlayer = dynamic_cast<QgsVectorLayer*>(mLyr.layer()); QgsVectorLayer* vlayer = dynamic_cast<QgsVectorLayer*>(mLyr.layer());
@ -491,7 +321,6 @@ void QgsLegendLayerFile::layerNameChanged()
legend()->setName(this, name); legend()->setName(this, name);
} }
void QgsLegendLayerFile::addToPopupMenu(QMenu& theMenu, QAction* toggleEditingAction) void QgsLegendLayerFile::addToPopupMenu(QMenu& theMenu, QAction* toggleEditingAction)
{ {
QgsMapLayer* lyr = layer(); QgsMapLayer* lyr = layer();
@ -526,9 +355,9 @@ void QgsLegendLayerFile::addToPopupMenu(QMenu& theMenu, QAction* toggleEditingAc
||(cap & QgsVectorDataProvider::DeleteFeatures)) ||(cap & QgsVectorDataProvider::DeleteFeatures))
{ {
if(toggleEditingAction) if(toggleEditingAction)
{ {
theMenu.addAction(toggleEditingAction); theMenu.addAction(toggleEditingAction);
} }
} }
// save as shapefile // save as shapefile

View File

@ -1,6 +1,6 @@
/*************************************************************************** /***************************************************************************
* Copyright (C) 2005 by Tim Sutton * * Copyright (C) 2005 by Tim Sutton *
* aps02ts@macbuntu * * aps02ts@macbuntu *
* * * *
* This program is free software; you can redistribute it and/or modify * * 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 * * it under the terms of the GNU General Public License as published by *
@ -26,7 +26,6 @@
#include "qgsmapcanvas.h" #include "qgsmapcanvas.h"
class QgsMapLayer; class QgsMapLayer;
class QgsAttributeTableDisplay;
/** /**
@author Tim Sutton @author Tim Sutton
@ -37,7 +36,7 @@ class QgsLegendLayerFile : public QgsLegendItem
public: public:
QgsLegendLayerFile(QTreeWidgetItem * theLegendItem, QString theString, QgsMapLayer* theLayer); QgsLegendLayerFile(QTreeWidgetItem * theLegendItem, QString theString, QgsMapLayer* theLayer);
~QgsLegendLayerFile();
bool isLeafNode() {return true;} bool isLeafNode() {return true;}
DRAG_ACTION accept(LEGEND_ITEM_TYPE type); DRAG_ACTION accept(LEGEND_ITEM_TYPE type);
QgsLegendItem::DRAG_ACTION accept(const QgsLegendItem* li) const; QgsLegendItem::DRAG_ACTION accept(const QgsLegendItem* li) const;
@ -47,16 +46,12 @@ public:
QPixmap getOriginalPixmap() const; QPixmap getOriginalPixmap() const;
/** updates item to the current state of the layer */
void updateLegendItem();
void setIconAppearance(bool inOverview, bool editable); void setIconAppearance(bool inOverview, bool editable);
/**Returns a label for a layer. Is static such that /**Returns a label for a layer. Is static such that
the name can be passed to the constructor of QgsLegendLayerFile*/ the name can be passed to the constructor of QgsLegendLayerFile*/
static QString nameFromLayer(QgsMapLayer* layer); static QString nameFromLayer(QgsMapLayer* layer);
void setVisible(bool visible = TRUE); void setVisible(bool visible = TRUE);
bool isVisible(); bool isVisible();
@ -67,28 +62,18 @@ public:
void addToPopupMenu(QMenu& theMenu, QAction* toggleEditingAction); void addToPopupMenu(QMenu& theMenu, QAction* toggleEditingAction);
public slots: public slots:
/** updates item to the current state of the layer */
void updateLegendItem();
/**Open attribute table*/ /**Open attribute table*/
void 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*/ /**Save as shapefile*/
void saveAsShapefile(); void saveAsShapefile();
/**Save selection as shapefile*/ /**Save selection as shapefile*/
void saveSelectionAsShapefile(); void saveSelectionAsShapefile();
/**Toggle editing for layer*/
void toggleEditing();
/**Return editing status for layer*/ /**Return editing status for layer*/
bool isEditing(); bool isEditing();
@ -97,7 +82,7 @@ public:
/**Layer name has changed - set it also in legend*/ /**Layer name has changed - set it also in legend*/
void layerNameChanged(); void layerNameChanged();
protected: protected:
/**Save as shapefile (called from saveAsShapefile and saveSelectionAsShapefile)*/ /**Save as shapefile (called from saveAsShapefile and saveSelectionAsShapefile)*/
@ -105,10 +90,6 @@ public:
/** layer identified by its layer id */ /** layer identified by its layer id */
QgsMapCanvasLayer mLyr; QgsMapCanvasLayer mLyr;
/** Pointer to the table display object if there is one, otherwise NULL */
QgsAttributeTableDisplay* mTableDisplay;
}; };
#endif #endif

View File

@ -156,25 +156,20 @@ OSErr openDocumentsAEHandler(const AppleEvent *event, AppleEvent *reply, SRefCon
} }
} }
// Open files now if application has been initialized QgisApp *qgis = QgisApp::instance();
QWidgetList wl = QApplication::topLevelWidgets(); if(qgis)
for (QWidgetList::iterator it = wl.begin(); it != wl.end(); ++it)
{ {
QgisApp *qgis = dynamic_cast<QgisApp *>(*it); if (!myProjectFileName.isEmpty())
if (qgis && qgis->objectName() == "QgisApp")
{ {
if (!myProjectFileName.isEmpty()) qgis->openProject(myProjectFileName);
{
qgis->openProject(myProjectFileName);
}
for (QStringList::Iterator myIterator = myFileList.begin();
myIterator != myFileList.end(); ++myIterator )
{
QString fileName = *myIterator;
qgis->openLayer(fileName);
}
break;
} }
for (QStringList::Iterator myIterator = myFileList.begin();
myIterator != myFileList.end(); ++myIterator )
{
QString fileName = *myIterator;
qgis->openLayer(fileName);
}
break;
} }
} }
return noErr; return noErr;

File diff suppressed because it is too large Load Diff

View File

@ -163,6 +163,9 @@ class QgisApp : public QMainWindow
* (as documented in Qt documentation. * (as documented in Qt documentation.
*/ */
void setupProxy(); void setupProxy();
static QgisApp *instance() { return smInstance; }
//! Helper to get a theme icon. It will fall back to the //! Helper to get a theme icon. It will fall back to the
//default theme if the active theme does not have the required //default theme if the active theme does not have the required
//icon. //icon.
@ -320,6 +323,7 @@ public slots:
void refreshMapCanvas(); void refreshMapCanvas();
//! returns pointer to map legend //! returns pointer to map legend
QgsLegend *legend() { return mMapLegend; } QgsLegend *legend() { return mMapLegend; }
//! starts/stops editing mode of the current layer //! starts/stops editing mode of the current layer
void toggleEditing(); void toggleEditing();
@ -330,7 +334,6 @@ public slots:
Is called from the legend when the current legend item has changed*/ Is called from the legend when the current legend item has changed*/
void activateDeactivateLayerRelatedActions(QgsMapLayer* layer); void activateDeactivateLayerRelatedActions(QgsMapLayer* layer);
public slots: public slots:
/** Add a dock widget to the main window. Overloaded from QMainWindow. /** Add a dock widget to the main window. Overloaded from QMainWindow.
* After adding the dock widget to the ui (by delegating to the QMainWindow * After adding the dock widget to the ui (by delegating to the QMainWindow
@ -368,9 +371,13 @@ public slots:
void measure(); void measure();
//! Measure area //! Measure area
void measureArea(); void measureArea();
//! show the attribute table for the currently selected layer //! show the attribute table for the currently selected layer
void attributeTable(); void attributeTable();
//! starts/stops editing mode of a layer
void toggleEditing(QgsMapLayer *layer);
//! show python console //! show python console
void showPythonDialog(); void showPythonDialog();
@ -644,8 +651,6 @@ class Tools
QString mStartupPath; QString mStartupPath;
//! full path name of the current map file (if it has been saved or loaded) //! full path name of the current map file (if it has been saved or loaded)
QString mFullPathName; QString mFullPathName;
//! A dock to show the attribute table (user optional)
QPointer<QDockWidget> mpTableDockWidget;
//! interface to QgisApp for plugins //! interface to QgisApp for plugins
QgisAppInterface *mQgisInterface; QgisAppInterface *mQgisInterface;
@ -697,6 +702,8 @@ class Tools
bool mFullScreenMode; bool mFullScreenMode;
QgsPythonDialog* mPythonConsole; QgsPythonDialog* mPythonConsole;
QgsPythonUtils* mPythonUtils; QgsPythonUtils* mPythonUtils;
static QgisApp *smInstance;
}; };
#endif #endif

View File

@ -21,34 +21,34 @@
QgsAddAttrDialog::QgsAddAttrDialog(QgsVectorDataProvider* provider, QWidget *parent, Qt::WFlags fl) QgsAddAttrDialog::QgsAddAttrDialog(QgsVectorDataProvider* provider, QWidget *parent, Qt::WFlags fl)
: QDialog(parent, fl), mDataProvider(provider) : QDialog(parent, fl), mDataProvider(provider)
{ {
setupUi(this); setupUi(this);
//fill data types into the combo box //fill data types into the combo box
const QSet<QString>& typelist=mDataProvider->supportedNativeTypes(); const QgsNativeTypeMap &typelist=mDataProvider->supportedNativeTypes();
for(QSet<QString>::const_iterator it = typelist.constBegin(); it != typelist.constEnd(); ++it) for(QgsNativeTypeMap::const_iterator it = typelist.constBegin(); it != typelist.constEnd(); ++it)
{ {
mTypeBox->addItem(*it); mTypeBox->addItem(it.key());
} }
} }
QgsAddAttrDialog::QgsAddAttrDialog(const std::list<QString>& typelist, QWidget *parent, Qt::WFlags fl) QgsAddAttrDialog::QgsAddAttrDialog(const std::list<QString>& typelist, QWidget *parent, Qt::WFlags fl)
: QDialog(parent, fl), mDataProvider(0) : QDialog(parent, fl), mDataProvider(0)
{ {
setupUi(this); setupUi(this);
for(std::list<QString>::const_iterator iter=typelist.begin();iter!=typelist.end();++iter) for(std::list<QString>::const_iterator iter=typelist.begin();iter!=typelist.end();++iter)
{ {
mTypeBox->addItem(*iter); mTypeBox->addItem(*iter);
} }
} }
QString QgsAddAttrDialog::name() const QString QgsAddAttrDialog::name() const
{ {
return mNameEdit->text(); return mNameEdit->text();
} }
QString QgsAddAttrDialog::type() const QString QgsAddAttrDialog::type() const
{ {
return mTypeBox->currentText(); return mTypeBox->currentText();
} }

View File

@ -30,8 +30,6 @@ back to QgsVectorLayer.
class QgsAttributeAction; class QgsAttributeAction;
typedef QMap<int, QgsField> QgsFieldMap;
class QgsAttributeActionDialog: public QWidget, private Ui::QgsAttributeActionDialogBase class QgsAttributeActionDialog: public QWidget, private Ui::QgsAttributeActionDialogBase
{ {
Q_OBJECT; Q_OBJECT;

View File

@ -31,8 +31,11 @@
#include <QLabel> #include <QLabel>
#include <QFrame> #include <QFrame>
#include <QScrollArea> #include <QScrollArea>
#include <QCompleter>
#include <QSpinBox>
#include <QDoubleSpinBox>
QgsAttributeDialog::QgsAttributeDialog(QgsVectorLayer *vl, QgsFeature * thepFeature) QgsAttributeDialog::QgsAttributeDialog(QgsVectorLayer *vl, QgsFeature *thepFeature)
: QDialog(), : QDialog(),
mSettingsPath("/Windows/AttributeDialog/"), mSettingsPath("/Windows/AttributeDialog/"),
mpFeature(thepFeature), mpFeature(thepFeature),
@ -67,7 +70,7 @@ QgsAttributeDialog::QgsAttributeDialog(QgsVectorLayer *vl, QgsFeature * thepFeat
int classificationField = -1; int classificationField = -1;
QStringList values; QMap<QString,QString> classes;
const QgsUniqueValueRenderer *uvr = dynamic_cast<const QgsUniqueValueRenderer *>( mLayer->renderer() ); const QgsUniqueValueRenderer *uvr = dynamic_cast<const QgsUniqueValueRenderer *>( mLayer->renderer() );
if( uvr ) if( uvr )
@ -78,7 +81,13 @@ QgsAttributeDialog::QgsAttributeDialog(QgsVectorLayer *vl, QgsFeature * thepFeat
for(int i=0; i<symbols.size(); i++) 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 != myAttributes.end();
++it) ++it)
{ {
QString myFieldName = theFieldMap[it.key()].name(); const QgsField &field = theFieldMap[it.key()];
int myFieldType = theFieldMap[it.key()].type(); QString myFieldName = field.name();
int myFieldType = field.type();
QLabel * mypLabel = new QLabel(); QLabel * mypLabel = new QLabel();
mypInnerLayout->addWidget(mypLabel,index,0); mypInnerLayout->addWidget(mypLabel,index,0);
QVariant myFieldValue = it.value(); QVariant myFieldValue = it.value();
QWidget *myWidget; QWidget *myWidget;
if(classificationField!=it.key())
QgsVectorLayer::EditType editType = vl->editType( it.key() );
switch( editType )
{ {
QLineEdit *le = new QLineEdit(); case QgsVectorLayer::Range:
//the provider may have provided a default value so use it
le->setText(myFieldValue.toString());
if( myFieldType==QVariant::Int )
{ {
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; case QgsVectorLayer::UniqueValues:
}
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 )
{ {
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 ) if( myFieldType==QVariant::Int )
@ -168,10 +263,9 @@ void QgsAttributeDialog::accept()
it != myAttributes.end(); it != myAttributes.end();
++it) ++it)
{ {
const QgsFieldMap &theFieldMap = mLayer->getDataProvider()->fields(); const QgsField &theField = mLayer->pendingFields()[it.key()];
QgsVectorLayer::EditType editType = mLayer->editType( it.key() );
//Q_ASSERT(myIndex <= mpWidgets.size()); QString myFieldName = theField.name();
QString myFieldName = theFieldMap[it.key()].name();
bool myFlag=false; bool myFlag=false;
QString myFieldValue; QString myFieldValue;
@ -184,40 +278,62 @@ void QgsAttributeDialog::accept()
QComboBox *cb = dynamic_cast<QComboBox *>(mpWidgets.value(myIndex)); QComboBox *cb = dynamic_cast<QComboBox *>(mpWidgets.value(myIndex));
if(cb) 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); mpFeature->changeAttribute( it.key(), QVariant(myIntValue) );
if (myFlag && ! myFieldValue.isEmpty())
{
mpFeature->changeAttribute( it.key(), QVariant(myIntValue) );
}
else
{
mpFeature->changeAttribute( it.key(), QVariant(QString::null) );
}
} }
break; else
case QVariant::Double:
{ {
double myDblValue = myFieldValue.toDouble(&myFlag); mpFeature->changeAttribute( it.key(), QVariant(QString::null) );
if (myFlag && ! myFieldValue.isEmpty())
{
mpFeature->changeAttribute( it.key(), QVariant(myDblValue) );
}
else
{
mpFeature->changeAttribute( it.key(), QVariant(QString::null) );
}
} }
break; }
default: //string break;
mpFeature->changeAttribute(it.key(),QVariant( myFieldValue ) ); case QVariant::Double:
break; {
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; ++myIndex;
} }
@ -235,4 +351,3 @@ void QgsAttributeDialog::restoreGeometry()
QSettings settings; QSettings settings;
QDialog::restoreGeometry(settings.value(mSettingsPath+"geometry").toByteArray()); QDialog::restoreGeometry(settings.value(mSettingsPath+"geometry").toByteArray());
} }

View File

@ -20,7 +20,6 @@
#include <QValidator> #include <QValidator>
#include "qgsattributetable.h" #include "qgsattributetable.h"
#include "qgsfeature.h"
#include "qgsfield.h" #include "qgsfield.h"
#include "qgslogger.h" #include "qgslogger.h"
#include "qgsvectordataprovider.h" #include "qgsvectordataprovider.h"
@ -33,31 +32,44 @@
#include <QMenu> #include <QMenu>
QgsAttributeTableItemDelegate::QgsAttributeTableItemDelegate(const QgsFieldMap & fields, QObject *parent) QgsAttributeTableItemDelegate::QgsAttributeTableItemDelegate(QgsAttributeTable *table, QObject *parent)
: QItemDelegate(parent), mFields(fields) : 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); QWidget *editor = QItemDelegate::createEditor(parent, option, index);
QLineEdit *le = dynamic_cast<QLineEdit*>(editor); 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(); QgsDebugMsg( QString("horizontalHeaderItem %1 not found").arg(col) );
if( mFields[col-1].type()==QVariant::Int ) return editor;
{
le->setValidator( new QIntValidator(le) );
}
else if( mFields[col-1].type()==QVariant::Double )
{
le->setValidator( new QDoubleValidator(le) );
}
} }
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; return editor;
} }
QgsAttributeTable::QgsAttributeTable(QWidget * parent): QgsAttributeTable::QgsAttributeTable(QWidget * parent) :
QTableWidget(parent), QTableWidget(parent),
lockKeyPressed(false), lockKeyPressed(false),
mEditable(false), mEditable(false),
@ -69,14 +81,12 @@ QgsAttributeTable::QgsAttributeTable(QWidget * parent):
f.setFamily("Helvetica"); f.setFamily("Helvetica");
f.setPointSize(9); f.setPointSize(9);
setFont(f); setFont(f);
mDelegate = new QgsAttributeTableItemDelegate(mFields, this); mDelegate = new QgsAttributeTableItemDelegate(this);
setItemDelegate(mDelegate); setItemDelegate(mDelegate);
setSelectionBehavior(QAbstractItemView::SelectRows); setSelectionBehavior(QAbstractItemView::SelectRows);
connect(this, SIGNAL(itemSelectionChanged()), this, SLOT(handleChangedSelections())); 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(horizontalHeader(), SIGNAL(sectionClicked(int)), this, SLOT(columnClicked(int)));
connect(verticalHeader(), SIGNAL(sectionClicked(int)), this, SLOT(rowClicked(int))); connect(verticalHeader(), SIGNAL(sectionClicked(int)), this, SLOT(rowClicked(int)));
setReadOnly(true);
setFocus(); setFocus();
} }
@ -90,14 +100,17 @@ void QgsAttributeTable::setReadOnly(bool b)
{ {
setEditTriggers(b ? QAbstractItemView::NoEditTriggers : setEditTriggers(b ? QAbstractItemView::NoEditTriggers :
QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed); QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed);
if(!b) {
setColumnReadOnly(0, true);
}
} }
void QgsAttributeTable::setColumnReadOnly(int col, bool ro) void QgsAttributeTable::setColumnReadOnly(int col, bool ro)
{ {
for (int i = 0; i < rowCount(); ++i) for (int i = 0; i < rowCount(); ++i)
{ {
QTableWidgetItem *item = this->item(i, col); QTableWidgetItem *twi = item(i, col);
item->setFlags(ro ? item->flags() & ~Qt::ItemIsEditable : item->flags() | Qt::ItemIsEditable); twi->setFlags(ro ? twi->flags() & ~Qt::ItemIsEditable : twi->flags() | Qt::ItemIsEditable);
} }
} }
@ -173,16 +186,16 @@ void QgsAttributeTable::keyReleaseEvent(QKeyEvent * ev)
void QgsAttributeTable::handleChangedSelections() void QgsAttributeTable::handleChangedSelections()
{ {
emit selectionRemoved(false); emit selectionRemoved(false);
QList<QTableWidgetSelectionRange> selectedItemRanges = selectedRanges(); QList<QTableWidgetSelectionRange> selectedItemRanges = selectedRanges();
QList<QTableWidgetSelectionRange>::const_iterator range_it = selectedItemRanges.constBegin(); QList<QTableWidgetSelectionRange>::const_iterator range_it = selectedItemRanges.constBegin();
for (; range_it != selectedItemRanges.constEnd(); ++range_it) for (; range_it != selectedItemRanges.constEnd(); ++range_it)
{ {
for (int index = range_it->topRow(); index <= range_it->bottomRow(); index++) 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 //don't send the signal repaintRequested() from here
@ -203,19 +216,8 @@ void QgsAttributeTable::selectRowWithId(int id)
void QgsAttributeTable::sortColumn(int col, bool ascending) void QgsAttributeTable::sortColumn(int col, bool ascending)
{ {
//if the first entry contains a letter, sort alphanumerically, otherwise numerically int type = horizontalHeaderItem(col)->data(QgsAttributeTable::AttributeType).toInt();
QString firstentry = item(0, col)->text(); qsort(0, rowCount() - 1, col, ascending, type!=QVariant::Int && type==QVariant::Double);
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);
} }
@ -302,7 +304,8 @@ void QgsAttributeTable::qsort(int lower, int upper, int col, bool ascending, boo
j = upper; j = upper;
for (;;) 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 while (compareItems(item(--j, col)->text(), v, ascending, alphanumeric) == 1 && j > 0); //make sure that j does not get negative
if (i >= j) if (i >= j)
{ {
@ -381,45 +384,6 @@ void QgsAttributeTable::popupItemSelected(QAction* menuAction)
mActions.doAction(id, mActionValues, mClickedOnValue); 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 */ /* Deprecated: See QgisApp::editCopy() instead */
void QgsAttributeTable::copySelectedRows() void QgsAttributeTable::copySelectedRows()
{ {
@ -463,157 +427,60 @@ void QgsAttributeTable::copySelectedRows()
clipboard->setText(toClipboard, QClipboard::Clipboard); 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) mAttrIdxMap.insert(fldIt.key(), h);
{
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);
}
}
} }
if (isSuccessful) QgsFeatureList features;
if( layer->selectedFeatureCount()==0 )
{ {
mEdited=false; layer->select(layer->pendingAllAttributesList(), QgsRect(), false);
clearEditingStructures();
QgsFeature f;
while( layer->getNextFeature(f) )
features << f;
}
else
{
features = layer->selectedFeatures();
} }
return isSuccessful; setRowCount( features.size() );
}
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(provider->featureCount() + addedFeatures.size() - deletedFeatures.size()); for(int i=0; i<features.size(); i++)
setColumnCount(fieldcount+1); putFeatureInTable(i, features[i]);
setHorizontalHeaderItem(0, new QTableWidgetItem("id")); //label for the id-column
int h = 1; // Default row height is too tall
QgsFieldMap::const_iterator fldIt; resizeRowsToContents();
for (fldIt = mFields.begin(); fldIt != mFields.end(); ++fldIt)
{
QgsDebugMsg("field " + QString::number(fldIt.key()) + ": " + fldIt->name() +
" | " + QString(QVariant::typeToName(fldIt->type())) );
setHorizontalHeaderItem(h++, new QTableWidgetItem(fldIt->name())); // Make each column wide enough to show all the contents
} for (int i=0; i<columnCount(); i++)
resizeColumnToContents(i);
//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);
}
}
} }
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 // Prevent a crash if a provider doesn't update the feature count properly
if(row >= rowCount()) if(row >= rowCount())
@ -623,21 +490,35 @@ void QgsAttributeTable::putFeatureInTable(int row, QgsFeature& fet)
//id-field //id-field
int id = fet.featureId(); int id = fet.featureId();
QTableWidgetItem *item = new QTableWidgetItem(QString::number(id)); QTableWidgetItem *twi = new QTableWidgetItem(QString::number(id));
item->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter); twi->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
setItem(row, 0, item); setItem(row, 0, twi);
insertFeatureId(id, row); //insert the id into the search tree of qgsattributetable 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 // get the field values
if( it->isNull() ) if( it->isNull() )
{ {
if( mFields[h-1].type()==QVariant::Int || mFields[h-1].type()==QVariant::Double ) if( isNum )
value=""; value="";
else else
value="NULL"; value="NULL";
@ -645,58 +526,10 @@ void QgsAttributeTable::putFeatureInTable(int row, QgsFeature& fet)
value = it->toString(); value = it->toString();
} }
bool isNum; twi = new QTableWidgetItem(value);
value.toFloat(&isNum); if (isNum)
item = new QTableWidgetItem(value); twi->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
if (isNum) item->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter); setItem(row, h, twi);
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;
}
} }
} }
@ -852,3 +685,54 @@ bool QgsAttributeTable::checkSelectionChanges()
return true; 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() ]--;
}
}

View File

@ -21,6 +21,7 @@
#include "qgsattributeaction.h" #include "qgsattributeaction.h"
#include "qgsvectorlayer.h" #include "qgsvectorlayer.h"
#include "qgsfield.h"
#include <QItemDelegate> #include <QItemDelegate>
#include <QTableWidget> #include <QTableWidget>
@ -31,18 +32,21 @@
*@author Gary E.Sherman *@author Gary E.Sherman
*/ */
class QgsAttributeTable;
class QgsAttributeTableItemDelegate: public QItemDelegate class QgsAttributeTableItemDelegate: public QItemDelegate
{ {
Q_OBJECT Q_OBJECT
public: 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; QWidget * createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index ) const;
private: private:
const QgsFieldMap & mFields; QgsAttributeTable *mTable;
}; };
class QgsAttributeTable:public QTableWidget class QgsAttributeTable : public QTableWidget
{ {
Q_OBJECT Q_OBJECT
@ -50,9 +54,17 @@ class QgsAttributeTable:public QTableWidget
QgsAttributeTable(QWidget * parent = 0); QgsAttributeTable(QWidget * parent = 0);
~QgsAttributeTable(); ~QgsAttributeTable();
enum {
AttributeIndex = Qt::UserRole,
AttributeName = Qt::UserRole+1,
AttributeType = Qt::UserRole+2,
};
void setReadOnly(bool b); void setReadOnly(bool b);
void setColumnReadOnly(int col, bool ro); 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); void insertFeatureId(int id, int row);
/**Selects the row which belongs to the feature with the specified id*/ /**Selects the row which belongs to the feature with the specified id*/
void selectRowWithId(int id); void selectRowWithId(int id);
@ -66,38 +78,11 @@ class QgsAttributeTable:public QTableWidget
bool edited() const {return mEdited;} bool edited() const {return mEdited;}
/**Switches editing mode on and off*/ /**Switches editing mode on and off*/
void setEditable(bool enabled){mEditable=enabled;} 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 /** Copies the selected rows to the clipboard
Deprecated: See QgisApp::editCopy() instead */ Deprecated: See QgisApp::editCopy() instead */
void copySelectedRows(); 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*/ /**Swaps the selected rows such that the selected ones are on the top of the table*/
void bringSelectedToTop(); void bringSelectedToTop();
/** Selects rows with chosen feature IDs */ /** Selects rows with chosen feature IDs */
@ -107,38 +92,42 @@ class QgsAttributeTable:public QTableWidget
/** Shows all rows */ /** Shows all rows */
void showAllRows(); 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: public slots:
void columnClicked(int col); void columnClicked(int col);
void rowClicked(int row); void rowClicked(int row);
// Called when the user chooses an item on the popup menu // Called when the user chooses an item on the popup menu
void popupItemSelected(QAction * menuAction); void popupItemSelected(QAction * menuAction);
void attributeValueChanged(int fid, int idx, const QVariant &value);
void featureDeleted(int fid);
protected slots: protected slots:
void handleChangedSelections(); void handleChangedSelections();
/**Writes changed values to 'mChangedValues'*/
void storeChangedValue(int row, int column);
protected: protected:
/**Flag telling if the ctrl-button or the shift-button is pressed*/ /**Flag telling if the ctrl-button or the shift-button is pressed*/
bool lockKeyPressed; bool lockKeyPressed;
/**Search tree to find a row corresponding to a feature id*/ /**Search tree to find a row corresponding to a feature id*/
QMap<int,int> rowIdMap; QMap<int,int> rowIdMap;
/**Map attribute index to columns*/
QMap<int,int> mAttrIdxMap;
bool mEditable; bool mEditable;
/**True if table has been edited and contains uncommited changes*/ /**True if table has been edited and contains uncommited changes*/
bool mEdited; 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()*/ /**Stors the numbers of the last selected rows. This is used to check for selection changes before emit repaintRequested()*/
std::set<int> mLastSelectedRows; 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); int compareItems(QString s1, QString s2, bool ascending, bool alphanumeric);
void keyPressEvent(QKeyEvent* ev); void keyPressEvent(QKeyEvent* ev);
void keyReleaseEvent(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); void qsort(int lower, int upper, int col, bool ascending, bool alphanumeric);
/**Called when the user requests a popup menu*/ /**Called when the user requests a popup menu*/
void contextMenuEvent(QContextMenuEvent* event); void contextMenuEvent(QContextMenuEvent* event);
/**Clears mAddedAttributes, mDeletedAttributes and mChangedValues*/
void clearEditingStructures();
/**Removes the column belonging to an attribute from the table /**Removes the column belonging to an attribute from the table
@name attribut name*/ @name attribut name*/
void removeAttrColumn(const QString& name); void removeAttrColumn(const QString& name);
/** puts attributes of feature to the chosen table row */ /** 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); 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. /**This function compares the current selection and the selection of the last repaint.
Also, mLastSelectedRows is updated*/ Returns true if there are differences in the selection.
Also, mLastSelectedRows is updated*/
bool checkSelectionChanges(); bool checkSelectionChanges();
signals: signals:
@ -165,8 +153,6 @@ class QgsAttributeTable:public QTableWidget
void selectionRemoved(bool); void selectionRemoved(bool);
/**Is emitted when a set of related selection and deselection signals have been emitted*/ /**Is emitted when a set of related selection and deselection signals have been emitted*/
void repaintRequested(); void repaintRequested();
/**Is emitted when a attribute of a added feature is changed*/
void featureAttributeChanged(int row, int column);
private: private:
void swapRows(int row1, int row2); void swapRows(int row1, int row2);
@ -179,10 +165,10 @@ class QgsAttributeTable:public QTableWidget
QgsAttributeTableItemDelegate *mDelegate; QgsAttributeTableItemDelegate *mDelegate;
QgsFieldMap mFields;
// Track previous columm for QTableView sortIndicator wrong direction workaround // Track previous columm for QTableView sortIndicator wrong direction workaround
int mPreviousSortIndicatorColumn; int mPreviousSortIndicatorColumn;
QgsVectorLayer *mLayer;
}; };
#endif #endif

View File

@ -21,8 +21,6 @@
#include "qgisapp.h" #include "qgisapp.h"
#include "qgsapplication.h" #include "qgsapplication.h"
#include "qgsaddattrdialog.h"
#include "qgsdelattrdialog.h"
#include "qgsfeature.h" #include "qgsfeature.h"
#include "qgsfield.h" #include "qgsfield.h"
#include "qgslogger.h" #include "qgslogger.h"
@ -39,249 +37,174 @@
#include <QPixmap> #include <QPixmap>
#include <QSettings> #include <QSettings>
#include <QToolButton> #include <QToolButton>
#include <QDockWidget>
QgsAttributeTableDisplay::QgsAttributeTableDisplay(QgsVectorLayer* layer, QgisApp * qgisApp) QgsAttributeTableDisplay::QgsAttributeTableDisplay(QgsVectorLayer* layer)
: QDialog(0, Qt::Window), : QDialog(0, Qt::Window),
mLayer(layer), mLayer(layer),
mQgisApp(qgisApp) mDock(NULL)
{ {
setupUi(this); setupUi(this);
restorePosition(); restorePosition();
setTheme(); setTheme();
mToggleEditingButton->setEnabled( layer->getDataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues );
mToggleEditingButton->setChecked( layer->isEditable() );
connect(mRemoveSelectionButton, SIGNAL(clicked()), this, SLOT(removeSelection())); connect(mRemoveSelectionButton, SIGNAL(clicked()), this, SLOT(removeSelection()));
connect(mSelectedToTopButton, SIGNAL(clicked()), this, SLOT(selectedToTop())); connect(mSelectedToTopButton, SIGNAL(clicked()), this, SLOT(selectedToTop()));
connect(mInvertSelectionButton, SIGNAL(clicked()), this, SLOT(invertSelection())); connect(mInvertSelectionButton, SIGNAL(clicked()), this, SLOT(invertSelection()));
connect(mCopySelectedRowsButton, SIGNAL(clicked()), this, SLOT(copySelectedRowsToClipboard())); connect(mCopySelectedRowsButton, SIGNAL(clicked()), this, SLOT(copySelectedRowsToClipboard()));
connect(mZoomMapToSelectedRowsButton, SIGNAL(clicked()), this, SLOT(zoomMapToSelectedRows())); 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(mSearchButton, SIGNAL(clicked()), this, SLOT(search()));
connect(mSearchShowResults, SIGNAL(activated(int)), this, SLOT(searchShowResultsChanged(int))); connect(mSearchShowResults, SIGNAL(activated(int)), this, SLOT(searchShowResultsChanged(int)));
connect(btnAdvancedSearch, SIGNAL(clicked()), this, SLOT(advancedSearch())); connect(btnAdvancedSearch, SIGNAL(clicked()), this, SLOT(advancedSearch()));
connect(buttonBox, SIGNAL(helpRequested()), this, SLOT(showHelp())); connect(buttonBox, SIGNAL(helpRequested()), this, SLOT(showHelp()));
connect(buttonBox->button(QDialogButtonBox::Close), SIGNAL(clicked()), connect(buttonBox->button(QDialogButtonBox::Close), SIGNAL(clicked()), this, SLOT(close()));
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);
int cap=layer->getDataProvider()->capabilities(); connect(mToggleEditingButton, SIGNAL(clicked()), this, SLOT(toggleEditing()));
if((cap&QgsVectorDataProvider::ChangeAttributeValues) connect(this, SIGNAL(editingToggled(QgsMapLayer *)), QgisApp::instance(), SLOT(toggleEditing(QgsMapLayer *)));
||(cap&QgsVectorDataProvider::AddAttributes)
||(cap&QgsVectorDataProvider::DeleteAttributes)) // etablish connection to table
{ connect(tblAttributes, SIGNAL(cellChanged(int, int)), this, SLOT(changeFeatureAttribute(int,int)));
btnEdit->setEnabled(true);
} // etablish connections to layer
else connect(mLayer, SIGNAL(layerDeleted()), this, SLOT(close()));
{
btnEdit->setEnabled(false); 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 // fill in mSearchColumns with available columns
QgsVectorDataProvider* provider = mLayer->getDataProvider(); const QgsFieldMap& xfields = mLayer->pendingFields();
if (provider) QgsFieldMap::const_iterator fldIt;
for (fldIt = xfields.constBegin(); fldIt != xfields.constEnd(); ++fldIt)
{ {
const QgsFieldMap& xfields = provider->fields(); mSearchColumns->addItem(fldIt->name());
QgsFieldMap::const_iterator fldIt;
for (fldIt = xfields.constBegin(); fldIt != xfields.constEnd(); ++fldIt)
{
mSearchColumns->addItem(fldIt->name());
}
} }
// TODO: create better labels // TODO: create better labels
mSearchShowResults->addItem(tr("select")); mSearchShowResults->addItem(tr("select"));
mSearchShowResults->addItem(tr("select and bring to top")); mSearchShowResults->addItem(tr("select and bring to top"));
mSearchShowResults->addItem(tr("show only matching")); 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() 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() void QgsAttributeTableDisplay::setTheme()
{ {
mAddAttributeButton->setIcon(QgisApp::getThemeIcon("/mActionNewAttribute.png"));
mRemoveSelectionButton->setIcon(QgisApp::getThemeIcon("/mActionUnselectAttributes.png")); mRemoveSelectionButton->setIcon(QgisApp::getThemeIcon("/mActionUnselectAttributes.png"));
mSelectedToTopButton->setIcon(QgisApp::getThemeIcon("/mActionSelectedToTop.png")); mSelectedToTopButton->setIcon(QgisApp::getThemeIcon("/mActionSelectedToTop.png"));
mInvertSelectionButton->setIcon(QgisApp::getThemeIcon("/mActionInvertSelection.png")); mInvertSelectionButton->setIcon(QgisApp::getThemeIcon("/mActionInvertSelection.png"));
mCopySelectedRowsButton->setIcon(QgisApp::getThemeIcon("/mActionCopySelected.png")); mCopySelectedRowsButton->setIcon(QgisApp::getThemeIcon("/mActionCopySelected.png"));
mZoomMapToSelectedRowsButton->setIcon(QgisApp::getThemeIcon("/mActionZoomToSelected.png")); mZoomMapToSelectedRowsButton->setIcon(QgisApp::getThemeIcon("/mActionZoomToSelected.png"));
mAddAttributeButton->setIcon(QgisApp::getThemeIcon("/mActionNewAttribute.png")); mToggleEditingButton->setIcon(QgisApp::getThemeIcon("/mActionToggleEditing.png"));
mDeleteAttributeButton->setIcon(QgisApp::getThemeIcon("/mActionDeleteAttribute.png"));
btnEdit->setIcon(QgisApp::getThemeIcon("/mActionToggleEditing.png"));
} }
void QgsAttributeTableDisplay::setTitle(QString title) void QgsAttributeTableDisplay::editingToggled()
{ {
setWindowTitle(title); mToggleEditingButton->setChecked( mLayer->isEditable() );
} tblAttributes->setReadOnly( !mLayer->isEditable() );
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();
} }
void QgsAttributeTableDisplay::selectedToTop() void QgsAttributeTableDisplay::selectedToTop()
{ {
table()->bringSelectedToTop(); tblAttributes->bringSelectedToTop();
} }
void QgsAttributeTableDisplay::invertSelection() void QgsAttributeTableDisplay::invertSelection()
{ {
if(mLayer) if(!mLayer)
{ return;
QApplication::setOverrideCursor(Qt::WaitCursor);
mLayer->invertSelection(); QApplication::setOverrideCursor(Qt::WaitCursor);
QApplication::restoreOverrideCursor(); mLayer->invertSelection();
} QApplication::restoreOverrideCursor();
} }
void QgsAttributeTableDisplay::removeSelection() void QgsAttributeTableDisplay::removeSelection()
{ {
table()->clearSelection(); tblAttributes->clearSelection();
mLayer->triggerRepaint(); mLayer->triggerRepaint();
} }
void QgsAttributeTableDisplay::copySelectedRowsToClipboard() void QgsAttributeTableDisplay::copySelectedRowsToClipboard()
{ {
// Deprecated QgisApp::instance()->editCopy(mLayer);
// table()->copySelectedRows();
// Use the Application's copy method instead
mQgisApp->editCopy(mLayer);
} }
void QgsAttributeTableDisplay::zoomMapToSelectedRows() void QgsAttributeTableDisplay::zoomMapToSelectedRows()
{ {
mQgisApp->zoomToSelected(); QgisApp::instance()->zoomToSelected();
} }
void QgsAttributeTableDisplay::search() void QgsAttributeTableDisplay::search()
{ {
// if selected field is numeric, numeric comparison will be used int type = tblAttributes->item(0, mSearchColumns->currentIndex())->data(QgsAttributeTable::AttributeType).toInt();
// else attributes containing entered text will be matched
QgsVectorDataProvider* provider = mLayer->getDataProvider();
int item = mSearchColumns->currentIndex();
QVariant::Type type = provider->fields()[item].type();
bool numeric = (type == QVariant::Int || type == QVariant::Double); bool numeric = (type == QVariant::Int || type == QVariant::Double);
QString str; QString str;
@ -314,25 +237,25 @@ void QgsAttributeTableDisplay::searchShowResultsChanged(int item)
if (item == 2) // show only matching if (item == 2) // show only matching
{ {
table()->showRowsWithId(mSearchIds); tblAttributes->showRowsWithId(mSearchIds);
} }
else else
{ {
// make sure that all rows are shown // make sure that all rows are shown
table()->showAllRows(); tblAttributes->showAllRows();
// select matching // select matching
mLayer->setSelectedFeatures(mSearchIds); mLayer->setSelectedFeatures(mSearchIds);
if (item == 1) // select matching and bring to top if (item == 1) // select matching and bring to top
table()->bringSelectedToTop(); tblAttributes->bringSelectedToTop();
} }
QApplication::restoreOverrideCursor(); QApplication::restoreOverrideCursor();
} }
void QgsAttributeTableDisplay::doSearch(const QString& searchString) void QgsAttributeTableDisplay::doSearch(QString searchString)
{ {
mSearchString = searchString; mSearchString = searchString;
@ -343,6 +266,7 @@ void QgsAttributeTableDisplay::doSearch(const QString& searchString)
QMessageBox::critical(this, tr("Search string parsing error"), search.parserErrorMsg()); QMessageBox::critical(this, tr("Search string parsing error"), search.parserErrorMsg());
return; return;
} }
QgsSearchTreeNode* searchTree = search.tree(); QgsSearchTreeNode* searchTree = search.tree();
if (searchTree == NULL) if (searchTree == NULL)
{ {
@ -354,24 +278,19 @@ void QgsAttributeTableDisplay::doSearch(const QString& searchString)
QApplication::setOverrideCursor(Qt::WaitCursor); 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(); 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()) if (searchTree->hasError())
break; break;
} }
@ -386,22 +305,13 @@ void QgsAttributeTableDisplay::doSearch(const QString& searchString)
// update table // update table
searchShowResultsChanged(mSearchShowResults->currentIndex()); searchShowResultsChanged(mSearchShowResults->currentIndex());
QString str; QString str;
if (mSearchIds.size()) if (mSearchIds.size())
str.sprintf(tr("Found %d matching features.","", mSearchIds.size()).toUtf8(), mSearchIds.size()); str.sprintf(tr("Found %d matching features.","", mSearchIds.size()).toUtf8(), mSearchIds.size());
else else
str = tr("No matching features found."); str = tr("No matching features found.");
QMessageBox::information(this, tr("Search results"), str); QMessageBox::information(this, tr("Search results"), str);
}
void QgsAttributeTableDisplay::closeEvent(QCloseEvent* ev)
{
saveWindowLocation();
ev->ignore();
emit deleted();
delete this;
} }
void QgsAttributeTableDisplay::restorePosition() void QgsAttributeTableDisplay::restorePosition()
@ -423,16 +333,77 @@ void QgsAttributeTableDisplay::showHelp()
void QgsAttributeTableDisplay::changeFeatureAttribute(int row, int column) void QgsAttributeTableDisplay::changeFeatureAttribute(int row, int column)
{ {
QgsFeatureList &flist = mLayer->addedFeatures(); if(column==0)
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())
return; 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);
} }

View File

@ -22,47 +22,41 @@
#include "ui_qgsattributetablebase.h" #include "ui_qgsattributetablebase.h"
class QDockWidget;
class QgsAttributeTable; class QgsAttributeTable;
class QgsVectorLayer; class QgsVectorLayer;
class QgisApp; class QgisApp;
class QgsAttributeActions;
/** /**
*@author Gary E.Sherman *@author Gary E.Sherman
*/ */
class QgsAttributeTableDisplay:public QDialog, private Ui::QgsAttributeTableBase class QgsAttributeTableDisplay : public QDialog, private Ui::QgsAttributeTableBase
{ {
Q_OBJECT Q_OBJECT
public: public:
/** static QgsAttributeTableDisplay *attributeTable(QgsVectorLayer *layer);
\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);
~QgsAttributeTableDisplay(); ~QgsAttributeTableDisplay();
QgsAttributeTable *table(); void fillTable();
void setTitle(QString title);
protected: protected:
QgsAttributeTableDisplay(QgsVectorLayer* layer);
QgsVectorLayer* mLayer; 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 */ /** array of feature IDs that match last searched condition */
QgsFeatureIds mSearchIds; QgsFeatureIds mSearchIds;
protected slots: protected slots:
void deleteAttributes();
void addAttribute();
void on_btnEdit_toggled(bool theFlag);
void startEditing();
void stopEditing();
void selectedToTop(); void selectedToTop();
void invertSelection(); void invertSelection();
void removeSelection(); void removeSelection();
@ -72,12 +66,18 @@ class QgsAttributeTableDisplay:public QDialog, private Ui::QgsAttributeTableBase
void advancedSearch(); void advancedSearch();
void searchShowResultsChanged(int item); void searchShowResultsChanged(int item);
void showHelp(); void showHelp();
void toggleEditing();
void attributeAdded(int idx);
void attributeDeleted(int idx);
public slots: public slots:
void changeFeatureAttribute(int row, int column); void changeFeatureAttribute(int row, int column);
void editingToggled();
void selectionChanged();
signals: signals:
void deleted(); void editingToggled(QgsMapLayer *);
private: private:
/** Set the icon theme for this dialog */ /** Set the icon theme for this dialog */
@ -88,7 +88,11 @@ class QgsAttributeTableDisplay:public QDialog, private Ui::QgsAttributeTableBase
QString mSearchString; QString mSearchString;
QDockWidget *mDock;
static const int context_id = 831088384; static const int context_id = 831088384;
static QMap<QgsVectorLayer *, QgsAttributeTableDisplay *> smTables;
}; };
#endif #endif

View File

@ -227,14 +227,12 @@ void QgsBookmarks::zoomToBookmark()
QString xmax = QString::fromUtf8((const char *)sqlite3_column_text(ppStmt, 2)); QString xmax = QString::fromUtf8((const char *)sqlite3_column_text(ppStmt, 2));
QString ymax = QString::fromUtf8((const char *)sqlite3_column_text(ppStmt, 3)); QString ymax = QString::fromUtf8((const char *)sqlite3_column_text(ppStmt, 3));
// set the extent to the bookmark // set the extent to the bookmark
dynamic_cast<QgisApp*>(mParent)->setExtent(QgsRect(xmin.toDouble(), QgisApp::instance()->setExtent(QgsRect(xmin.toDouble(),
ymin.toDouble(), ymin.toDouble(),
xmax.toDouble(), xmax.toDouble(),
ymax.toDouble())); ymax.toDouble()));
// redraw the map // redraw the map
dynamic_cast<QgisApp*>(mParent)->getMapCanvas()->refresh(); QgisApp::instance()->getMapCanvas()->refresh();
} }
} }

View File

@ -23,11 +23,9 @@
#include <QList> #include <QList>
#include <QMap> #include <QMap>
class QgsFeature; #include "qgsfield.h"
class QgsField; #include "qgsfeature.h"
typedef QList<QgsFeature> QgsFeatureList;
typedef QMap<int, QgsField> QgsFieldMap;
/** /**
@ -74,18 +72,18 @@ public:
* when it's done with it. * when it's done with it.
*/ */
QgsFeatureList copyOf(); QgsFeatureList copyOf();
/* /*
* Clears the internal clipboard. * Clears the internal clipboard.
*/ */
void clear(); void clear();
/* /*
* Inserts a copy of the feature on the internal clipboard. * Inserts a copy of the feature on the internal clipboard.
*/ */
void insert( QgsFeature& feature ); void insert( QgsFeature& feature );
private: private:
/** QGIS-internal vector feature clipboard. /** QGIS-internal vector feature clipboard.

View File

@ -38,8 +38,8 @@ email : sherman at mrcc.com
#include <cassert> #include <cassert>
#include <iostream> #include <iostream>
QgsDbSourceSelect::QgsDbSourceSelect(QgisApp *app, Qt::WFlags fl) QgsDbSourceSelect::QgsDbSourceSelect(QWidget *parent, Qt::WFlags fl)
: QDialog(app, fl), mColumnTypeThread(NULL), qgisApp(app), pd(0) : QDialog(parent, fl), mColumnTypeThread(NULL), pd(0)
{ {
setupUi(this); setupUi(this);
btnAdd->setEnabled(false); btnAdd->setEnabled(false);

View File

@ -54,7 +54,7 @@ class QgsDbSourceSelect : public QDialog, private Ui::QgsDbSourceSelectBase
public: public:
//! Constructor //! Constructor
QgsDbSourceSelect(QgisApp *app, Qt::WFlags fl = QgisGui::ModalDialogFlags); QgsDbSourceSelect(QWidget *parent = 0, Qt::WFlags fl = QgisGui::ModalDialogFlags);
//! Destructor //! Destructor
~QgsDbSourceSelect(); ~QgsDbSourceSelect();
//! Opens the create connection dialog to build a new connection //! Opens the create connection dialog to build a new connection
@ -136,8 +136,6 @@ class QgsDbSourceSelect : public QDialog, private Ui::QgsDbSourceSelectBase
QStringList m_selectedTables; QStringList m_selectedTables;
// Storage for the range of layer type icons // Storage for the range of layer type icons
QMap<QString, QPair<QString, QIcon> > mLayerIcons; QMap<QString, QPair<QString, QIcon> > mLayerIcons;
//! Pointer to the qgis application mainwindow
QgisApp *qgisApp;
PGconn *pd; PGconn *pd;
static const int context_id = 939347163; static const int context_id = 939347163;
//! Model that acts as datasource for mTableTreeWidget //! Model that acts as datasource for mTableTreeWidget

View File

@ -186,6 +186,15 @@ void QgsIdentifyResults::addDerivedAttribute(QTreeWidgetItem * fnode, QString fi
new QTreeWidgetItem(daRootNode, labels); 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) void QgsIdentifyResults::addAction(QTreeWidgetItem * fnode, int id, QString field, QString value)
{ {
QStringList labels; QStringList labels;
@ -198,7 +207,7 @@ void QgsIdentifyResults::addAction(QTreeWidgetItem * fnode, int id, QString fiel
/** Add a feature node to the list */ /** Add a feature node to the list */
QTreeWidgetItem *QgsIdentifyResults::addNode(QString label) QTreeWidgetItem *QgsIdentifyResults::addNode(QString label)
{ {
return (new QTreeWidgetItem(lstResults, QStringList(label))); return new QTreeWidgetItem(lstResults, QStringList(label));
} }
void QgsIdentifyResults::setTitle(QString title) void QgsIdentifyResults::setTitle(QString title)
@ -251,15 +260,21 @@ void QgsIdentifyResults::setActions( const QgsAttributeAction& actions )
void QgsIdentifyResults::clicked ( QTreeWidgetItem *item ) 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() void QgsIdentifyResults::on_buttonHelp_clicked()
{ {
@ -325,7 +340,7 @@ void QgsIdentifyResults::extractAllItemData(QTreeWidgetItem* item)
parent = child; parent = child;
mValues.clear(); mValues.clear();
// For the code below we // For the code below we
// need to do the comparison on the text strings rather than the // need to do the comparison on the text strings rather than the
// pointers because if the user clicked on the parent, we need // 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 ) { if (parent->child(j)->text(0) == mDerivedLabel ) {
for (int k = 0; k < parent->child(j)->childCount(); ++k) for (int k = 0; k < parent->child(j)->childCount(); ++k)
{ {
mValues.push_back( mValues.push_back(
std::make_pair(mDerivedLabel + "." std::make_pair(mDerivedLabel + "."
+ parent->child(j)->child(k)->text(0), + parent->child(j)->child(k)->text(0),
parent->child(j)->child(k)->text(1))); parent->child(j)->child(k)->text(1)));
if (item == parent->child(j)->child(k)) if (item == parent->child(j)->child(k))
{ {
mClickedOnValue = valuesIndex; mClickedOnValue = valuesIndex;
} }
valuesIndex++; valuesIndex++;
} }
} }
else // do the actual feature attributes else // do the actual feature attributes
{ {
mValues.push_back(std::make_pair(parent->child(j)->text(0), 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)) if (item == parent->child(j))
{ {
mClickedOnValue = valuesIndex; mClickedOnValue = valuesIndex;
} }
valuesIndex++; valuesIndex++;

View File

@ -57,6 +57,9 @@ class QgsIdentifyResults: public QDialog, private Ui::QgsIdentifyResultsBase
/** Add an action to the feature display node */ /** Add an action to the feature display node */
void addAction(QTreeWidgetItem *parent, int id, QString field, QString value); 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 */ /** Add a feature node to the feature display */
QTreeWidgetItem * addNode(QString label); QTreeWidgetItem * addNode(QString label);
/** Set the title for the identify results dialog */ /** Set the title for the identify results dialog */
@ -85,6 +88,7 @@ class QgsIdentifyResults: public QDialog, private Ui::QgsIdentifyResultsBase
signals: signals:
void selectedFeatureChanged(int featureId); void selectedFeatureChanged(int featureId);
void editFeature(int featureId);
public slots: public slots:
@ -110,26 +114,27 @@ class QgsIdentifyResults: public QDialog, private Ui::QgsIdentifyResultsBase
private: private:
QgsAttributeAction mActions; bool mEditable;
int mClickedOnValue; QgsAttributeAction mActions;
QMenu* mActionPopup; int mClickedOnValue;
std::vector<std::pair<QString, QString> > mValues; QMenu* mActionPopup;
static const int context_id = 689216579; std::vector<std::pair<QString, QString> > mValues;
int mCurrentFeatureId; static const int context_id = 689216579;
QString mDerivedLabel; int mCurrentFeatureId;
QString mDerivedLabel;
/** /**
Keeps track of what derived-attribute (e.g. Length, Area) Keeps track of what derived-attribute (e.g. Length, Area)
root nodes have been generated for each feature in this widget. root nodes have been generated for each feature in this widget.
First item: Feature root node First item: Feature root node
Second item: Derived-attribute root node for that feature Second item: Derived-attribute root node for that feature
*/ */
std::map<QTreeWidgetItem *, QTreeWidgetItem *> mDerivedAttributeRootNodes; std::map<QTreeWidgetItem *, QTreeWidgetItem *> mDerivedAttributeRootNodes;
// Convenience function to populate mValues with all of the item names and // Convenience function to populate mValues with all of the item names and
// values for a item, including the derived ones. // values for a item, including the derived ones.
void extractAllItemData(QTreeWidgetItem* item); void extractAllItemData(QTreeWidgetItem* item);
}; };
#endif #endif

View File

@ -42,419 +42,420 @@ QgsMapToolAddFeature::~QgsMapToolAddFeature()
void QgsMapToolAddFeature::canvasReleaseEvent(QMouseEvent * e) void QgsMapToolAddFeature::canvasReleaseEvent(QMouseEvent * e)
{ {
QgsVectorLayer *vlayer = dynamic_cast <QgsVectorLayer*>(mCanvas->currentLayer()); QgsVectorLayer *vlayer = dynamic_cast <QgsVectorLayer*>(mCanvas->currentLayer());
if (!vlayer) if (!vlayer)
{ {
QMessageBox::information(0, QObject::tr("Not a vector layer"), QMessageBox::information(0, QObject::tr("Not a vector layer"),
QObject::tr("The current layer is not a vector layer")); QObject::tr("The current layer is not a vector layer"));
return; return;
} }
QGis::WKBTYPE layerWKBType = vlayer->geometryType(); QGis::WKBTYPE layerWKBType = vlayer->geometryType();
//no support for adding features to 2.5D types yet //no support for adding features to 2.5D types yet
if(layerWKBType == QGis::WKBLineString25D || layerWKBType == QGis::WKBPolygon25D || \ if(layerWKBType == QGis::WKBLineString25D || layerWKBType == QGis::WKBPolygon25D || \
layerWKBType == QGis::WKBMultiLineString25D || layerWKBType == QGis::WKBPoint25D || layerWKBType == QGis::WKBMultiPoint25D) 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")); 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; delete mRubberBand;
mRubberBand = NULL; mRubberBand = NULL;
mCapturing = FALSE; mCapturing = FALSE;
mCaptureList.clear(); mCaptureList.clear();
mCanvas->refresh(); mCanvas->refresh();
return; return;
} }
QgsVectorDataProvider* provider = vlayer->getDataProvider(); QgsVectorDataProvider* provider = vlayer->getDataProvider();
if(!(provider->capabilities() & QgsVectorDataProvider::AddFeatures)) if(!(provider->capabilities() & QgsVectorDataProvider::AddFeatures))
{ {
QMessageBox::information(0, QObject::tr("Layer cannot be added to"), 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.")); QObject::tr("The data provider for this layer does not support the addition of features."));
return; return;
} }
if (!vlayer->isEditable()) if (!vlayer->isEditable())
{ {
QMessageBox::information(0, QObject::tr("Layer not editable"), QMessageBox::information(0, QObject::tr("Layer not editable"),
QObject::tr("Cannot edit the vector layer. To make it editable, go to the file item " 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'.")); "of the layer, right click and check 'Allow Editing'."));
return; return;
} }
// POINT CAPTURING // POINT CAPTURING
if (mTool == CapturePoint) 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 QMessageBox::information(0, QObject::tr("Wrong editing tool"),
if(vlayer->vectorType() != QGis::Point) 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 QgsPoint idPoint; //point in map coordinates
QList<QgsSnappingResult> snapResults; QList<QgsSnappingResult> snapResults;
QgsPoint savePoint; //point in layer coordinates QgsPoint savePoint; //point in layer coordinates
if(mSnapper.snapToBackgroundLayers(e->pos(), snapResults) == 0) if(mSnapper.snapToBackgroundLayers(e->pos(), snapResults) == 0)
{
idPoint = snapPointFromResults(snapResults, e->pos());
try
{ {
idPoint = snapPointFromResults(snapResults, e->pos()); savePoint = toLayerCoords(vlayer, idPoint);
try QgsDebugMsg("savePoint = " + savePoint.stringRep());
{ }
savePoint = toLayerCoords(vlayer, idPoint); catch(QgsCsException &cse)
QgsDebugMsg("savePoint = " + savePoint.stringRep()); {
} Q_UNUSED(cse);
catch(QgsCsException &cse) QMessageBox::information(0, QObject::tr("Coordinate transform error"), \
{ QObject::tr("Cannot transform the point to the layers coordinate system"));
Q_UNUSED(cse); return;
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 // emit signal - QgisApp can catch it and save point position to clipboard
QgsAttributeDialog * mypDialog = new QgsAttributeDialog( vlayer, f ); // FIXME: is this still actual or something old that's not used anymore?
if (mypDialog->exec()) //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"); QgsFeature* f = new QgsFeature(0,"WKBPoint");
vlayer->addFeature(*f);
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) 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 QMessageBox::information(0, QObject::tr("Wrong editing tool"),
if(mTool == CaptureLine && vlayer->vectorType() != QGis::Line) QObject::tr("Cannot apply the 'capture line' 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;
}
//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;
}
//add point to list and to rubber band //check we only use the polygon tool for polygon/multipolygon layers
int error = addVertex(e->pos()); if(mTool == CapturePolygon && vlayer->vectorType() != QGis::Polygon)
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())
{ {
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 mCaptureList.clear();
int topologicalEditing = QgsProject::instance()->readNumEntry("Digitizing", "/TopologicalEditing", 0); return;
if(topologicalEditing) }
//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; // add the fields to the QgsFeature
delete mypDialog; const QgsFieldMap fields = vlayer->pendingFields();
for(QgsFieldMap::const_iterator it = fields.begin(); it != fields.end(); ++it)
// delete the elements of mCaptureList {
mCaptureList.clear(); f->addAttribute(it.key(), provider->getDefaultValue(it.key()));
mCanvas->refresh(); }
}
} 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();
}
}
} }

View File

@ -31,6 +31,7 @@
#include "qgsspatialrefsys.h" #include "qgsspatialrefsys.h"
#include "qgsvectordataprovider.h" #include "qgsvectordataprovider.h"
#include "qgsvectorlayer.h" #include "qgsvectorlayer.h"
#include "qgsattributedialog.h"
#include <QSettings> #include <QSettings>
#include <QMessageBox> #include <QMessageBox>
@ -73,7 +74,7 @@ void QgsMapToolIdentify::canvasReleaseEvent(QMouseEvent * e)
return; return;
} }
QgsMapLayer* layer = mCanvas->currentLayer(); mLayer = mCanvas->currentLayer();
// delete rubber band if there was any // delete rubber band if there was any
delete mRubberBand; delete mRubberBand;
@ -81,31 +82,31 @@ void QgsMapToolIdentify::canvasReleaseEvent(QMouseEvent * e)
// call identify method for selected layer // call identify method for selected layer
if (layer) if (mLayer)
{ {
// In the special case of the WMS provider, // In the special case of the WMS provider,
// coordinates are sent back to the server as pixel coordinates // coordinates are sent back to the server as pixel coordinates
// not the layer's native CRS. So identify on screen coordinates! // not the layer's native CRS. So identify on screen coordinates!
if ( 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 else
{ {
// convert screen coordinates to map coordinates // convert screen coordinates to map coordinates
QgsPoint idPoint = mCanvas->getCoordinateTransform()->toMapCoordinates(e->x(), e->y()); 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 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) if (!layer)
return; return;
@ -140,7 +142,7 @@ void QgsMapToolIdentify::identifyRasterLayer(QgsRasterLayer* layer, const QgsPoi
QgsAttributeAction aa; QgsAttributeAction aa;
mResults = new QgsIdentifyResults(aa, mCanvas->window()); mResults = new QgsIdentifyResults(aa, mCanvas->window());
mResults->setAttribute(Qt::WA_DeleteOnClose); 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(accepted()), this, SLOT(resultsDialogGone()));
connect(mResults, SIGNAL(rejected()), this, SLOT(resultsDialogGone())); connect(mResults, SIGNAL(rejected()), this, SLOT(resultsDialogGone()));
mResults->restorePosition(); 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) if (!layer)
{ {
return; return;
@ -193,7 +196,7 @@ void QgsMapToolIdentify::identifyRasterWmsLayer(QgsRasterLayer* layer, const Qgs
if(xMinView < xMinLayer) if(xMinView < xMinLayer)
{ {
i = (int)(point.x() - (xMinLayer - xMinView) / mupp); i = (int)(point.x() - (xMinLayer - xMinView) / mupp);
} }
else else
{ {
@ -214,7 +217,7 @@ void QgsMapToolIdentify::identifyRasterWmsLayer(QgsRasterLayer* layer, const Qgs
if (text.isEmpty()) if (text.isEmpty())
{ {
showError(layer); showError();
return; return;
} }
@ -225,8 +228,9 @@ void QgsMapToolIdentify::identifyRasterWmsLayer(QgsRasterLayer* layer, const Qgs
viewer->showMessage(); // deletes itself on close 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) if (!layer)
return; return;
@ -250,8 +254,7 @@ void QgsMapToolIdentify::identifyVectorLayer(QgsVectorLayer* layer, const QgsPoi
//QgsFeature feat; //QgsFeature feat;
QgsAttributeAction& actions = *layer->actions(); QgsAttributeAction& actions = *layer->actions();
QString fieldIndex = layer->displayField(); QString fieldIndex = layer->displayField();
QgsVectorDataProvider* dataProvider = layer->getDataProvider(); const QgsFieldMap& fields = layer->pendingFields();
const QgsFieldMap& fields = dataProvider->fields();
// init distance/area calculator // init distance/area calculator
QgsDistanceArea calc; QgsDistanceArea calc;
@ -259,6 +262,22 @@ void QgsMapToolIdentify::identifyVectorLayer(QgsVectorLayer* layer, const QgsPoi
calc.setEllipsoid(ellipsoid); calc.setEllipsoid(ellipsoid);
calc.setSourceSRS(layer->srs().srsid()); 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 // display features falling within the search radius
if(!mResults) if(!mResults)
{ {
@ -268,6 +287,8 @@ void QgsMapToolIdentify::identifyVectorLayer(QgsVectorLayer* layer, const QgsPoi
connect(mResults, SIGNAL(accepted()), this, SLOT(resultsDialogGone())); connect(mResults, SIGNAL(accepted()), this, SLOT(resultsDialogGone()));
connect(mResults, SIGNAL(rejected()), this, SLOT(resultsDialogGone())); connect(mResults, SIGNAL(rejected()), this, SLOT(resultsDialogGone()));
connect(mResults, SIGNAL(selectedFeatureChanged(int)), this, SLOT(highlightFeature(int))); 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 // restore the identify window position and show it
mResults->restorePosition(); mResults->restorePosition();
} }
@ -281,12 +302,9 @@ void QgsMapToolIdentify::identifyVectorLayer(QgsVectorLayer* layer, const QgsPoi
QApplication::setOverrideCursor(Qt::WaitCursor); QApplication::setOverrideCursor(Qt::WaitCursor);
int lastFeatureId = 0; int lastFeatureId = 0;
QgsFeatureList::iterator f_it = mFeatureList.begin();
QList<QgsFeature> featureList; for(; f_it != mFeatureList.end(); ++f_it)
layer->featuresInRectangle(r, featureList, true, true);
QList<QgsFeature>::iterator f_it = featureList.begin();
for(; f_it != featureList.end(); ++f_it)
{ {
featureCount++; featureCount++;
@ -294,6 +312,10 @@ void QgsMapToolIdentify::identifyVectorLayer(QgsVectorLayer* layer, const QgsPoi
featureNode->setData(0, Qt::UserRole, QVariant(f_it->featureId())); // save feature id featureNode->setData(0, Qt::UserRole, QVariant(f_it->featureId())); // save feature id
lastFeatureId = f_it->featureId(); lastFeatureId = f_it->featureId();
featureNode->setText(0, fieldIndex); featureNode->setText(0, fieldIndex);
if( layer->isEditable() )
mResults->addEdit( featureNode, f_it->featureId() );
const QgsAttributeMap& attr = f_it->attributeMap(); const QgsAttributeMap& attr = f_it->attributeMap();
for (QgsAttributeMap::const_iterator it = attr.begin(); it != attr.end(); ++it) 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); mResults->addDerivedAttribute(featureNode, "Y", str);
} }
// Add actions // Add actions
QgsAttributeAction::aIter iter = actions.begin(); QgsAttributeAction::aIter iter = actions.begin();
for (register int i = 0; iter != actions.end(); ++iter, ++i) for (register int i = 0; iter != actions.end(); ++iter, ++i)
{ {
mResults->addAction( featureNode, i, QObject::tr("action"), iter->name() ); mResults->addAction( featureNode, i, QObject::tr("action"), iter->name() );
} }
} }
QgsDebugMsg("Feature count on identify: " + QString::number(featureCount)); 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 //also test the not commited features //todo: eliminate copy past code
mResults->setTitle(layer->name() + " - " + QString::number(featureCount) + QObject::tr(" features found")); mResults->setTitle(layer->name() + " - " + QString::number(featureCount) + QObject::tr(" features found"));
if (featureCount == 1) if (featureCount == 1)
{ {
mResults->showAllAttributes(); mResults->showAllAttributes();
mResults->setTitle(layer->name() + " - " + QObject::tr(" 1 feature found") ); mResults->setTitle(layer->name() + " - " + QObject::tr(" 1 feature found") );
@ -369,228 +390,14 @@ void QgsMapToolIdentify::identifyVectorLayer(QgsVectorLayer* layer, const QgsPoi
{ {
QString title = layer->name(); QString title = layer->name();
title += QString( tr("- %1 features found","Identify results window title",featureCount) ).arg(featureCount); title += QString( tr("- %1 features found","Identify results window title",featureCount) ).arg(featureCount);
mResults->setTitle(title); mResults->setTitle(title);
} }
QApplication::restoreOverrideCursor(); QApplication::restoreOverrideCursor();
mResults->show(); mResults->show();
} }
#if 0 //MH: old state of the function void QgsMapToolIdentify::showError()
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)
{ {
// QMessageBox::warning( // QMessageBox::warning(
// this, // this,
@ -600,10 +407,10 @@ void QgsMapToolIdentify::showError(QgsMapLayer * mapLayer)
// ); // );
QgsMessageViewer * mv = new QgsMessageViewer(); QgsMessageViewer * mv = new QgsMessageViewer();
mv->setWindowTitle( mapLayer->errorCaptionString() ); mv->setWindowTitle( mLayer->errorCaptionString() );
mv->setMessageAsPlainText( mv->setMessageAsPlainText(
QObject::tr("Could not identify objects on") + " " + mapLayer->name() + " " + QObject::tr("because") + ":\n" + QObject::tr("Could not identify objects on") + " " + mLayer->name() + " " + QObject::tr("because") + ":\n" +
mapLayer->errorString() mLayer->errorString()
); );
mv->exec(); // deletes itself on close mv->exec(); // deletes itself on close
} }
@ -625,7 +432,7 @@ void QgsMapToolIdentify::deactivate()
void QgsMapToolIdentify::highlightFeature(int featureId) void QgsMapToolIdentify::highlightFeature(int featureId)
{ {
QgsVectorLayer* layer = dynamic_cast<QgsVectorLayer*>(mCanvas->currentLayer()); QgsVectorLayer* layer = dynamic_cast<QgsVectorLayer*>(mLayer);
if (!layer) if (!layer)
return; return;
@ -653,3 +460,41 @@ void QgsMapToolIdentify::highlightFeature(int featureId)
mRubberBand->show(); 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();
}

View File

@ -19,6 +19,7 @@
#include "qgsmaptool.h" #include "qgsmaptool.h"
#include "qgspoint.h" #include "qgspoint.h"
#include "qgsfeature.h"
#include <QObject> #include <QObject>
@ -60,6 +61,9 @@ class QgsMapToolIdentify : public QgsMapTool
public slots: public slots:
//! creates rubberband on top of the feature to highlight it //! creates rubberband on top of the feature to highlight it
void highlightFeature(int featureId); void highlightFeature(int featureId);
//! edit a feature
void editFeature(int featureId);
private: private:
@ -68,7 +72,7 @@ class QgsMapToolIdentify : public QgsMapTool
* *
* \param point[in] The coordinate (as the CRS of the raster layer) * \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 * \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 * \note WMS Servers prefer to receive coordinates in image space not CRS space, therefore
* this special variant of identifyRasterLayer. * 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 * \brief function for identifying features at a coordinate in a vector layer
* *
* \param point[in] The coordinate (as the CRS of the 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. //! 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 //! Pointer to the identify results dialog for name/value pairs
QgsIdentifyResults *mResults; QgsIdentifyResults *mResults;
@ -97,6 +103,11 @@ class QgsMapToolIdentify : public QgsMapTool
//! Rubber band for highlighting identified feature //! Rubber band for highlighting identified feature
QgsRubberBand* mRubberBand; QgsRubberBand* mRubberBand;
QgsMapLayer *mLayer;
//! list of identified features
QgsFeatureList mFeatureList;
private slots: private slots:
// Let us know when the QgsIdentifyResults dialog box has been closed // Let us know when the QgsIdentifyResults dialog box has been closed
void resultsDialogGone(); void resultsDialogGone();

View File

@ -56,65 +56,65 @@ void QgsMapToolMoveFeature::canvasPressEvent(QMouseEvent * e)
QgsVectorLayer* vlayer = currentVectorLayer(); QgsVectorLayer* vlayer = currentVectorLayer();
if(!vlayer) if(!vlayer)
{ {
return; return;
} }
if(!vlayer->isEditable()) if(!vlayer->isEditable())
{ {
QMessageBox::information(0, QObject::tr("Layer not editable"), \ QMessageBox::information(0, QObject::tr("Layer not editable"),
QObject::tr("Cannot edit the vector layer. To make it editable, go to the file item " \ 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'.")); "of the layer, right click and check 'Allow Editing'."));
return; return;
} }
//find first geometry under mouse cursor and store iterator to it //find first geometry under mouse cursor and store iterator to it
QgsPoint layerCoords = toLayerCoords((QgsMapLayer*)vlayer, e->pos()); QgsPoint layerCoords = toLayerCoords((QgsMapLayer*)vlayer, e->pos());
QSettings settings; QSettings settings;
double searchRadius = settings.value("/qgis/digitizing/search_radius_vertex_edit", 10).toDouble(); double searchRadius = settings.value("/qgis/digitizing/search_radius_vertex_edit", 10).toDouble();
QgsRect selectRect(layerCoords.x()-searchRadius, layerCoords.y()-searchRadius, \ QgsRect selectRect(layerCoords.x()-searchRadius, layerCoords.y()-searchRadius,
layerCoords.x()+searchRadius, layerCoords.y()+searchRadius); layerCoords.x()+searchRadius, layerCoords.y()+searchRadius);
QList<QgsFeature> featureList; vlayer->select(QgsAttributeList(), selectRect, true);
vlayer->featuresInRectangle(selectRect, featureList, true, false);
//find the closest feature
if(featureList.size() > 0) 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 double currentDistance = pointGeometry->distance(*f.geometry());
QgsGeometry* pointGeometry = QgsGeometry::fromPoint(layerCoords); if(currentDistance < minDistance)
if(!pointGeometry) {
{ minDistance = currentDistance;
return; cf = f;
} }
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;
} }
}
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) void QgsMapToolMoveFeature::canvasReleaseEvent(QMouseEvent * e)

View File

@ -49,7 +49,6 @@ QgsOptions::QgsOptions(QWidget *parent, Qt::WFlags fl) :
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
connect(this, SIGNAL(accepted()), this, SLOT(saveOptions())); connect(this, SIGNAL(accepted()), this, SLOT(saveOptions()));
qparent = parent;
// read the current browser and set it // read the current browser and set it
QSettings settings; QSettings settings;
#ifdef QGISDEBUG #ifdef QGISDEBUG
@ -116,6 +115,7 @@ QgsOptions::QgsOptions(QWidget *parent, Qt::WFlags fl) :
chkAddedVisibility->setChecked(settings.value("/qgis/new_layers_visible",true).toBool()); chkAddedVisibility->setChecked(settings.value("/qgis/new_layers_visible",true).toBool());
cbxLegendClassifiers->setChecked(settings.value("/qgis/showLegendClassifiers",false).toBool()); cbxLegendClassifiers->setChecked(settings.value("/qgis/showLegendClassifiers",false).toBool());
cbxHideSplash->setChecked(settings.value("/qgis/hideSplash",false).toBool()); cbxHideSplash->setChecked(settings.value("/qgis/hideSplash",false).toBool());
cbxAttributeTableDocked->setChecked(settings.value("/qgis/dockAttributeTable",false).toBool());
//set the colour for selections //set the colour for selections
int myRed = settings.value("/qgis/default_selection_color_red",255).toInt(); 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 // Slot to change the theme as user scrolls through the choices
QString newt = newThemeName; QString newt = newThemeName;
((QgisApp*)qparent)->setTheme(newt); QgisApp::instance()->setTheme(newt);
} }
QString QgsOptions::theme() QString QgsOptions::theme()
{ {
@ -260,6 +260,7 @@ void QgsOptions::saveOptions()
settings.setValue("/Map/identifyRadius", spinBoxIdentifyValue->value()); settings.setValue("/Map/identifyRadius", spinBoxIdentifyValue->value());
settings.setValue("/qgis/showLegendClassifiers",cbxLegendClassifiers->isChecked()); settings.setValue("/qgis/showLegendClassifiers",cbxLegendClassifiers->isChecked());
settings.setValue("/qgis/hideSplash",cbxHideSplash->isChecked()); settings.setValue("/qgis/hideSplash",cbxHideSplash->isChecked());
settings.setValue("/qgis/dockAttributeTable",cbxAttributeTableDocked->isChecked());
settings.setValue("/qgis/new_layers_visible",chkAddedVisibility->isChecked()); settings.setValue("/qgis/new_layers_visible",chkAddedVisibility->isChecked());
settings.setValue("/qgis/enable_anti_aliasing",chkAntiAliasing->isChecked()); settings.setValue("/qgis/enable_anti_aliasing",chkAntiAliasing->isChecked());
settings.setValue("/qgis/use_qimage_to_render", !(chkUseQPixmap->isChecked())); settings.setValue("/qgis/use_qimage_to_render", !(chkUseQPixmap->isChecked()));

View File

@ -93,9 +93,6 @@ class QgsOptions :public QDialog, private Ui::QgsOptionsBase
// //
QStringList i18nList(); QStringList i18nList();
//! Pointer to our parent
QWidget *qparent;
//!Global default projection used for new layers added that have no projection //!Global default projection used for new layers added that have no projection
long mGlobalSRSID; long mGlobalSRSID;

View File

@ -43,10 +43,9 @@
static long DEFAULT_WMS_EPSG = 4326; // WGS 84 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), : QDialog(parent, fl),
m_Epsg(DEFAULT_WMS_EPSG), m_Epsg(DEFAULT_WMS_EPSG),
qgisApp(app),
mWmsProvider(0) mWmsProvider(0)
{ {
setupUi(this); setupUi(this);

View File

@ -44,7 +44,7 @@ class QgsServerSourceSelect : public QDialog, private Ui::QgsServerSourceSelectB
public: public:
//! Constructor //! Constructor
QgsServerSourceSelect(QgisApp *app, QWidget *parent = 0, Qt::WFlags fl = QgisGui::ModalDialogFlags); QgsServerSourceSelect(QWidget *parent = 0, Qt::WFlags fl = QgisGui::ModalDialogFlags);
//! Destructor //! Destructor
~QgsServerSourceSelect(); ~QgsServerSourceSelect();
//! Populate the connection list combo box //! 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 //! The mime type, the text to use in the button and a unique number
QMap<QString, QPair<QString, int> > m_PotentialFormats; QMap<QString, QPair<QString, int> > m_PotentialFormats;
//! Pointer to the qgis application mainwindow
QgisApp *qgisApp;
//! The widget that controls the image format radio buttons //! The widget that controls the image format radio buttons
QButtonGroup* m_imageFormatGroup; QButtonGroup* m_imageFormatGroup;
QHBoxLayout* m_imageFormatLayout; QHBoxLayout* m_imageFormatLayout;

View File

@ -19,6 +19,7 @@
#include <memory> #include <memory>
#include "qgisapp.h"
#include "qgsapplication.h" #include "qgsapplication.h"
#include "qgsattributeactiondialog.h" #include "qgsattributeactiondialog.h"
#include "qgscontexthelp.h" #include "qgscontexthelp.h"
@ -32,7 +33,6 @@
#include "qgsproject.h" #include "qgsproject.h"
#include "qgssinglesymboldialog.h" #include "qgssinglesymboldialog.h"
#include "qgsuniquevaluedialog.h" #include "qgsuniquevaluedialog.h"
#include "qgsvectordataprovider.h"
#include "qgsvectorlayer.h" #include "qgsvectorlayer.h"
#include "qgsvectorlayerproperties.h" #include "qgsvectorlayerproperties.h"
#include "qgsconfig.h" #include "qgsconfig.h"
@ -48,15 +48,18 @@
#include <QFileDialog> #include <QFileDialog>
#include <QFileInfo> #include <QFileInfo>
#include <QSettings> #include <QSettings>
#include <QComboBox>
#include <QCheckBox>
#if QT_VERSION < 0x040300 #if QT_VERSION < 0x040300
#define toPlainText() text() #define toPlainText() text()
#endif #endif
QgsVectorLayerProperties::QgsVectorLayerProperties(QgsVectorLayer * lyr, QgsVectorLayerProperties::QgsVectorLayerProperties(
QWidget * parent, QgsVectorLayer *lyr,
Qt::WFlags fl) QWidget * parent,
Qt::WFlags fl)
: QDialog(parent, fl), : QDialog(parent, fl),
layer(lyr), layer(lyr),
mRendererDialog(0) mRendererDialog(0)
@ -66,6 +69,21 @@ QgsVectorLayerProperties::QgsVectorLayerProperties(QgsVectorLayer * lyr,
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject())); connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
connect(buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(apply())); connect(buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(apply()));
connect(this, SIGNAL(accepted()), 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 // Create the Label dialog tab
QVBoxLayout *layout = new QVBoxLayout( labelOptionsFrame ); QVBoxLayout *layout = new QVBoxLayout( labelOptionsFrame );
@ -73,18 +91,31 @@ QgsVectorLayerProperties::QgsVectorLayerProperties(QgsVectorLayer * lyr,
labelDialog = new QgsLabelDialog ( layer->label(), labelOptionsFrame); labelDialog = new QgsLabelDialog ( layer->label(), labelOptionsFrame);
layout->addWidget( labelDialog ); layout->addWidget( labelDialog );
labelOptionsFrame->setLayout(layout); labelOptionsFrame->setLayout(layout);
connect(labelDialog, SIGNAL(labelSourceSet()), connect(labelDialog, SIGNAL(labelSourceSet()), this, SLOT(setLabelCheckBox()));
this, SLOT(setLabelCheckBox()));
// Create the Actions dialog tab // Create the Actions dialog tab
QgsVectorDataProvider *dp = dynamic_cast<QgsVectorDataProvider *>(layer->getDataProvider());
QVBoxLayout *actionLayout = new QVBoxLayout( actionOptionsFrame ); QVBoxLayout *actionLayout = new QVBoxLayout( actionOptionsFrame );
actionLayout->setMargin(0); actionLayout->setMargin(0);
QgsFieldMap fields = dp->fields(); const QgsFieldMap &fields = layer->pendingFields();
actionDialog = new QgsAttributeActionDialog ( layer->actions(), fields, actionDialog = new QgsAttributeActionDialog ( layer->actions(), fields, actionOptionsFrame );
actionOptionsFrame );
actionLayout->addWidget( actionDialog ); 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(); reset();
if(layer->getDataProvider())//enable spatial index button group if supported by provider 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->setText(layer->srs().proj4String());
leSpatialRefSys->setCursorPosition(0); leSpatialRefSys->setCursorPosition(0);
connect(sliderTransparency, SIGNAL(valueChanged(int)), this, SLOT(sliderTransparency_valueChanged(int))); connect(sliderTransparency, SIGNAL(valueChanged(int)), this, SLOT(sliderTransparency_valueChanged(int)));
tabWidget->setCurrentIndex(0);
} // QgsVectorLayerProperties ctor } // 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() QgsVectorLayerProperties::~QgsVectorLayerProperties()
{ {
disconnect(labelDialog, SIGNAL(labelSourceSet()), disconnect(labelDialog, SIGNAL(labelSourceSet()), this, SLOT(setLabelCheckBox()));
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) void QgsVectorLayerProperties::sliderTransparency_valueChanged(int theValue)
{ {
//set the transparency percentage label to a suitable value //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 " "layer is shown here. This is currently only supported for PostgreSQL "
"layers. To enter or modify the query, click on the Query Builder button")); "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 //see if we are dealing with a pg layer here
if(layer->providerType() == "postgres") if(layer->providerType() == "postgres")
{ {
@ -188,7 +368,7 @@ void QgsVectorLayerProperties::reset( void )
} }
//get field list for display field combo //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) for (QgsFieldMap::const_iterator it = myFields.begin(); it != myFields.end(); ++it)
{ {
displayFieldComboBox->addItem( it->name() ); displayFieldComboBox->addItem( it->name() );
@ -249,7 +429,7 @@ void QgsVectorLayerProperties::reset( void )
SLOT(alterLayerDialog(const QString &))); SLOT(alterLayerDialog(const QString &)));
// reset fields in label dialog // reset fields in label dialog
layer->label()->setFields ( layer->getDataProvider()->fields() ); layer->label()->setFields ( layer->pendingFields() );
//set the metadata contents //set the metadata contents
QString myStyle = QgsApplication::reportStyleSheet(); QString myStyle = QgsApplication::reportStyleSheet();
@ -311,6 +491,69 @@ void QgsVectorLayerProperties::apply()
layer->setLabelOn(labelCheckBox->isChecked()); layer->setLabelOn(labelCheckBox->isChecked());
layer->setLayerName(displayName()); 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 = QgsSingleSymbolDialog *sdialog =
dynamic_cast < QgsSingleSymbolDialog * >(widgetStackRenderers->currentWidget()); dynamic_cast < QgsSingleSymbolDialog * >(widgetStackRenderers->currentWidget());
@ -354,11 +597,8 @@ void QgsVectorLayerProperties::on_pbnQueryBuilder_clicked()
// launch the query builder using the PostgreSQL connection // launch the query builder using the PostgreSQL connection
// from the provider // from the provider
// get the data provider // cast to postgres provider type
QgsVectorDataProvider *dp = QgsPostgresProvider * myPGProvider = (QgsPostgresProvider *) layer->getDataProvider() ; // FIXME use dynamic cast
dynamic_cast<QgsVectorDataProvider *>(layer->getDataProvider());
// cast to postgres provider type
QgsPostgresProvider * myPGProvider = (QgsPostgresProvider *) dp;
// create the query builder object using the table name // create the query builder object using the table name
// and postgres connection from the provider // and postgres connection from the provider
QgsDataSourceURI uri(myPGProvider->dataSourceUri()); QgsDataSourceURI uri(myPGProvider->dataSourceUri());
@ -541,7 +781,7 @@ QString QgsVectorLayerProperties::getMetadata()
} }
#if 0
// //
// Add the info about each field in the attribute table // Add the info about each field in the attribute table
// //
@ -569,8 +809,7 @@ QString QgsVectorLayerProperties::getMetadata()
myMetadata += "</th>"; myMetadata += "</th>";
//get info for each field by looping through them //get info for each field by looping through them
QgsVectorDataProvider *myDataProvider = dynamic_cast<QgsVectorDataProvider *>(layer->getDataProvider()); const QgsFieldMap& myFields = layer->pendingFields();
const QgsFieldMap& myFields = myDataProvider->fields();
for (QgsFieldMap::const_iterator it = myFields.begin(); it != myFields.end(); ++it) for (QgsFieldMap::const_iterator it = myFields.begin(); it != myFields.end(); ++it)
{ {
const QgsField& myField = *it; const QgsField& myField = *it;
@ -594,15 +833,17 @@ QString QgsVectorLayerProperties::getMetadata()
//close field list //close field list
myMetadata += "</table>"; //end of nested table myMetadata += "</table>"; //end of nested table
#endif
myMetadata += "</td></tr>"; //end of stats container table row myMetadata += "</td></tr>"; //end of stats container table row
// //
// Close the table // Close the table
// //
myMetadata += "</table>"; myMetadata += "</table>";
myMetadata += "</body></html>"; myMetadata += "</body></html>";
return myMetadata; return myMetadata;
} }

View File

@ -23,15 +23,20 @@
#include "ui_qgsvectorlayerpropertiesbase.h" #include "ui_qgsvectorlayerpropertiesbase.h"
#include "qgisgui.h" #include "qgisgui.h"
#include "qgsrenderer.h" #include "qgsrenderer.h"
#include "qgsaddattrdialog.h"
#include "qgsdelattrdialog.h"
#include "qgsfield.h"
class QgsMapLayer;
class QgsAttributeActionDialog; class QgsAttributeActionDialog;
class QgsLabelDialog; class QgsLabelDialog;
class QgsVectorLayer; class QgsVectorLayer;
class QgsVectorLayerProperties : public QDialog, private Ui::QgsVectorLayerPropertiesBase
class QgsVectorLayerProperties : public QDialog, private Ui::QgsVectorLayerPropertiesBase{ {
Q_OBJECT Q_OBJECT;
public: public:
QgsVectorLayerProperties(QgsVectorLayer *lyr = 0,QWidget *parent = 0, Qt::WFlags fl = QgisGui::ModalDialogFlags); QgsVectorLayerProperties(QgsVectorLayer *lyr = 0,QWidget *parent = 0, Qt::WFlags fl = QgisGui::ModalDialogFlags);
~QgsVectorLayerProperties(); ~QgsVectorLayerProperties();
/**Sets the legend type to "single symbol", "graduated symbol" or "continuous color"*/ /**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*/ /**Sets the attribute that is used in the Identify Results dialog box*/
void setDisplayField(QString name); 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); void alterLayerDialog(const QString& string);
/** Reset to original (vector layer) values */ /** Reset to original (vector layer) values */
void reset(); void reset();
/** Get metadata about the layer in nice formatted html */ /** Get metadata about the layer in nice formatted html */
QString getMetadata(); QString getMetadata();
/** Set transparency based on slider position */ /** Set transparency based on slider position */
void sliderTransparency_valueChanged(int theValue); void sliderTransparency_valueChanged(int theValue);
/** Toggles on the label check box */ /** Toggles on the label check box */
void setLabelCheckBox(); void setLabelCheckBox();
/** Called when apply button is pressed or dialog is accepted */ /** Called when apply button is pressed or dialog is accepted */
void apply(); void apply();
/** toggle editing of layer */
void toggleEditing();
/** editing of layer was toggled */
void editingToggled();
// //
//methods reimplemented from qt designer base class //methods reimplemented from qt designer base class
// //
@ -67,13 +95,21 @@ class QgsVectorLayerProperties : public QDialog, private Ui::QgsVectorLayerPrope
void on_pbnSaveDefaultStyle_clicked(); void on_pbnSaveDefaultStyle_clicked();
void on_pbnLoadStyle_clicked(); void on_pbnLoadStyle_clicked();
void on_pbnSaveStyleAs_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; QgsVectorLayer *layer;
/**Renderer dialog which is shown*/ /**Renderer dialog which is shown*/
QDialog* mRendererDialog; QDialog* mRendererDialog;
@ -83,14 +119,19 @@ class QgsVectorLayerProperties : public QDialog, private Ui::QgsVectorLayerPrope
QgsLabelDialog* labelDialog; QgsLabelDialog* labelDialog;
/**Actions dialog. If apply is pressed, the actions are stored for later use */ /**Actions dialog. If apply is pressed, the actions are stored for later use */
QgsAttributeActionDialog* actionDialog; 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*/ /**Buffer pixmap which takes the picture of renderers before they are assigned to the vector layer*/
//QPixmap bufferPixmap; //QPixmap bufferPixmap;
static const int context_id = 94000531; static const int context_id = 94000531;
}; };
inline QString QgsVectorLayerProperties::displayName() inline QString QgsVectorLayerProperties::displayName()
{ {
return txtDisplayName->text(); return txtDisplayName->text();
} }
#endif #endif

View File

@ -34,9 +34,7 @@ General purpose distance and area calculator
*/ */
class CORE_EXPORT QgsDistanceArea class CORE_EXPORT QgsDistanceArea
{ {
public: public:
//! Constructor //! Constructor
QgsDistanceArea(); QgsDistanceArea();

View File

@ -18,20 +18,12 @@ email : sherman at mrcc.com
#include "qgsgeometry.h" #include "qgsgeometry.h"
#include "qgsrect.h" #include "qgsrect.h"
#include <iostream>
#include <cfloat>
#ifdef WIN32
#include <limits>
#endif
#include <cstring>
#include <assert.h>
/** \class QgsFeature /** \class QgsFeature
* \brief Encapsulates a spatial feature with attributes * \brief Encapsulates a spatial feature with attributes
*/ */
QgsFeature::QgsFeature(int id, QString typeName) QgsFeature::QgsFeature(int id, QString typeName)
: mFid(id), : mFid(id),
mGeometry(0), mGeometry(0),
mOwnsGeometry(0), mOwnsGeometry(0),
mValid(false), mValid(false),
@ -41,101 +33,40 @@ QgsFeature::QgsFeature(int id, QString typeName)
// NOOP // 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 ) QgsFeature::QgsFeature( QgsFeature const & rhs )
: mFid( rhs.mFid ), : mFid( rhs.mFid ),
mAttributes( rhs.mAttributes ), mAttributes( rhs.mAttributes ),
mValid( rhs.mValid ), mValid( rhs.mValid ),
mDirty( rhs.mDirty ), mDirty( rhs.mDirty ),
mTypeName( rhs.mTypeName ) mTypeName( rhs.mTypeName ),
mGeometry( 0 ),
mOwnsGeometry( false )
{ {
// copy embedded geometry // copy embedded geometry
if ( rhs.mGeometry ) if ( rhs.mGeometry )
{ {
mGeometry = new QgsGeometry( *(rhs.mGeometry) ); setGeometry( *rhs.mGeometry );
mOwnsGeometry = TRUE;
} }
else
{
mGeometry = 0;
mOwnsGeometry = FALSE;
}
} }
QgsFeature & QgsFeature::operator=( QgsFeature const & rhs ) QgsFeature & QgsFeature::operator=( QgsFeature const & rhs )
{ {
if ( &rhs == this ) if ( &rhs == this )
{ return *this; } return *this;
mFid = rhs.mFid ; mFid = rhs.mFid;
mDirty = rhs.mDirty ; mDirty = rhs.mDirty;
mAttributes = rhs.mAttributes ; mAttributes = rhs.mAttributes;
mValid = rhs.mValid ; mValid = rhs.mValid;
mTypeName = rhs.mTypeName; mTypeName = rhs.mTypeName;
mGeometry = 0;
mOwnsGeometry = false;
// copy embedded geometry
delete mGeometry;
if ( rhs.mGeometry ) if ( rhs.mGeometry )
{ setGeometry( *rhs.mGeometry );
mGeometry = new QgsGeometry( *(rhs.mGeometry) );
mOwnsGeometry = TRUE;
}
else
{
mGeometry = 0;
mOwnsGeometry = FALSE;
}
return *this; return *this;
} // QgsFeature::operator=( QgsFeature const & rhs ) } // QgsFeature::operator=( QgsFeature const & rhs )
@ -144,13 +75,9 @@ QgsFeature & QgsFeature::operator=( QgsFeature const & rhs )
//! Destructor //! Destructor
QgsFeature::~QgsFeature() QgsFeature::~QgsFeature()
{ {
// Destruct the attached geometry only if we still own it. // Destruct the attached geometry only if we still own it.
if ( (mOwnsGeometry) && (mGeometry) ) if ( mOwnsGeometry && mGeometry )
{
delete mGeometry; delete mGeometry;
}
} }
/** /**
@ -197,17 +124,15 @@ void QgsFeature::changeAttribute(int field, QVariant attr)
mAttributes[field] = attr; mAttributes[field] = attr;
} }
QgsGeometry *QgsFeature::geometry()
QgsGeometry * QgsFeature::geometry()
{ {
return mGeometry; return mGeometry;
} }
QgsGeometry *QgsFeature::geometryAndOwnership()
QgsGeometry * QgsFeature::geometryAndOwnership()
{ {
mOwnsGeometry = FALSE; mOwnsGeometry = false;
return mGeometry; return mGeometry;
} }
@ -218,7 +143,6 @@ QgsGeometry * QgsFeature::geometryAndOwnership()
void QgsFeature::setFeatureId(int id) void QgsFeature::setFeatureId(int id)
{ {
mFid = id; mFid = id;
} }
@ -239,45 +163,29 @@ void QgsFeature::setTypeName(QString typeName)
void QgsFeature::setGeometry(const QgsGeometry& geom) void QgsFeature::setGeometry(const QgsGeometry& geom)
{ {
// Destruct the attached geometry only if we still own it, before assigning new one. setGeometry( new QgsGeometry(geom) );
if ( (mOwnsGeometry) && (mGeometry) )
{
delete mGeometry;
mGeometry = 0;
}
mGeometry = new QgsGeometry(geom);
mOwnsGeometry = TRUE;
} }
void QgsFeature::setGeometry(QgsGeometry* geom) void QgsFeature::setGeometry(QgsGeometry* geom)
{ {
// Destruct the attached geometry only if we still own it, before assigning new one. // Destruct the attached geometry only if we still own it, before assigning new one.
if ( (mOwnsGeometry) && (mGeometry) ) if ( mOwnsGeometry && mGeometry )
{ {
delete mGeometry; delete mGeometry;
mGeometry = 0; mGeometry = 0;
} }
mGeometry = geom; mGeometry = geom;
mOwnsGeometry = TRUE; mOwnsGeometry = true;
} }
/** Set the pointer to the feature geometry /** Set the pointer to the feature geometry
*/ */
void QgsFeature::setGeometryAndOwnership(unsigned char *geom, size_t length) void QgsFeature::setGeometryAndOwnership(unsigned char *geom, size_t length)
{ {
// Destruct the attached geometry only if we still own it, before assigning new one. QgsGeometry *g = new QgsGeometry();
if ( (mOwnsGeometry) && (mGeometry) ) g->setWkbAndOwnership(geom, length);
{ setGeometry(g);
delete mGeometry;
mGeometry = 0;
}
mGeometry = new QgsGeometry();
mGeometry->setWkbAndOwnership(geom, length);
mOwnsGeometry = TRUE;
} }
@ -298,5 +206,5 @@ bool QgsFeature::isDirty() const
void QgsFeature::resetDirty() void QgsFeature::resetDirty()
{ {
mDirty = FALSE; mDirty = false;
} }

View File

@ -20,10 +20,11 @@ email : sherman at mrcc.com
#include <QMap> #include <QMap>
#include <QString> #include <QString>
#include <QVariant> #include <QVariant>
#include <QList>
class QgsGeometry; class QgsGeometry;
class QgsRect; class QgsRect;
class QgsFeature;
// key = field index, value = field value // key = field index, value = field value
typedef QMap<int, QVariant> QgsAttributeMap; typedef QMap<int, QVariant> QgsAttributeMap;
@ -37,6 +38,7 @@ typedef QMap<int, QgsGeometry> QgsGeometryMap;
// key = field index, value = field name // key = field index, value = field name
typedef QMap<int, QString> QgsFieldNameMap; typedef QMap<int, QString> QgsFieldNameMap;
typedef QList<QgsFeature> QgsFeatureList;
/** /**
* @class QgsFeature - Feature attribute class. * @class QgsFeature - Feature attribute class.
@ -44,25 +46,12 @@ typedef QMap<int, QString> QgsFieldNameMap;
* *
* @author Gary E.Sherman * @author Gary E.Sherman
*/ */
class CORE_EXPORT QgsFeature { class CORE_EXPORT QgsFeature
{
public: public:
//! Constructor //! Constructor
QgsFeature(int id = 0, QString typeName = "" ); 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 */ /** copy ctor needed due to internal pointer */
QgsFeature( QgsFeature const & rhs ); 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) * You would normally do this after it's saved to permanent storage (e.g. disk, an ACID-compliant database)
*/ */
void resetDirty(); void resetDirty();
/** /**
* Get the geometry object associated with this feature * Get the geometry object associated with this feature
*/ */
QgsGeometry * geometry(); QgsGeometry *geometry();
/** /**
* Get the geometry object associated with this feature * Get the geometry object associated with this feature
* The caller assumes responsibility for the QgsGeometry*'s destruction. * The caller assumes responsibility for the QgsGeometry*'s destruction.
*/ */
QgsGeometry * geometryAndOwnership(); QgsGeometry *geometryAndOwnership();
/** Set this feature's geometry from another QgsGeometry object (deep copy) /** 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 */ /** map of attributes accessed by field index */
QgsAttributeMap mAttributes; QgsAttributeMap mAttributes;
/** pointer to geometry in binary WKB format /** pointer to geometry in binary WKB format
This is usually set by a call to OGRGeometry::exportToWkb() This is usually set by a call to OGRGeometry::exportToWkb()
*/ */
QgsGeometry* mGeometry; QgsGeometry* mGeometry;
/** Indicator if the mGeometry is owned by this QgsFeature. /** Indicator if the mGeometry is owned by this QgsFeature.
If so, this QgsFeature takes responsibility for the mGeometry's destruction. If so, this QgsFeature takes responsibility for the mGeometry's destruction.
*/ */
bool mOwnsGeometry; bool mOwnsGeometry;
//! Flag to indicate if this feature is valid //! Flag to indicate if this feature is valid
// TODO: still applies? [MD] // TODO: still applies? [MD]
@ -200,4 +189,5 @@ class CORE_EXPORT QgsFeature {
}; // class QgsFeature }; // class QgsFeature
#endif #endif

View File

@ -145,4 +145,7 @@ private:
}; // class QgsField }; // class QgsField
// key = field index, value=field data
typedef QMap<int, QgsField> QgsFieldMap;
#endif #endif

View File

@ -482,7 +482,7 @@ QgsLabelAttributes *QgsLabel::layerAttributes ( void )
void QgsLabel::labelPoint ( std::vector<QgsPoint>& points, QgsFeature & feature ) void QgsLabel::labelPoint ( std::vector<QgsPoint>& points, QgsFeature & feature )
{ {
QgsGeometry* geometry = feature.geometry(); QgsGeometry *geometry = feature.geometry();
unsigned char *geom = geometry->wkbBuffer(); unsigned char *geom = geometry->wkbBuffer();
size_t geomlen = geometry->wkbSize(); size_t geomlen = geometry->wkbSize();
QGis::WKBTYPE wkbType = geometry->wkbType(); QGis::WKBTYPE wkbType = geometry->wkbType();

View File

@ -83,7 +83,7 @@ public:
void renderLabel ( QPainter* painter, const QgsRect& viewExtent, void renderLabel ( QPainter* painter, const QgsRect& viewExtent,
const QgsCoordinateTransform* coordTransform, const QgsCoordinateTransform* coordTransform,
const QgsMapToPixel *transform, 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 /** Reads the renderer configuration from an XML file
@param rnode the DOM node to read @param rnode the DOM node to read
@ -132,7 +132,7 @@ private:
int width, int height, int alignment); int width, int height, int alignment);
/** Get label point for simple feature in map units */ /** 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. */ /** Get label point for the given feature in wkb format. */
unsigned char* labelPoint( QgsPoint& point, unsigned char* wkb, size_t wkblen); unsigned char* labelPoint( QgsPoint& point, unsigned char* wkb, size_t wkblen);

View File

@ -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); 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<<*/ /**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) 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(!file || strcmp(dfile, file) != 0)
if(dfile) //exit if QGIS_DEBUG_FILE is set and the message comes from the wrong file {
{ return;
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
}
} }
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*/ /**Goes to qWarning*/
static void warning(const QString& msg); static void warning(const QString& msg);

View File

@ -24,11 +24,10 @@
#include <QString> #include <QString>
#include <QVariant> #include <QVariant>
class QgsSearchTreeValue; #include <qgsfield.h>
class QgsField; #include <qgsfeature.h>
typedef QMap<int, QgsField> QgsFieldMap; class QgsSearchTreeValue;
typedef QMap<int, QVariant> QgsAttributeMap;
/** /**
* QgsSearchTreeNode * QgsSearchTreeNode

View File

@ -24,7 +24,7 @@
#include <cmath> #include <cmath>
QgsSnapper::QgsSnapper(QgsMapRenderer* mapRender): mMapRenderer(mapRender) QgsSnapper::QgsSnapper(QgsMapRenderer* mapRenderer): mMapRenderer(mapRenderer)
{ {
} }

View File

@ -68,7 +68,7 @@ QString QgsVectorDataProvider::dataComment() const
return QString(); return QString();
} }
bool QgsVectorDataProvider::addFeatures(QgsFeatureList & flist) bool QgsVectorDataProvider::addFeatures(QgsFeatureList &flist)
{ {
return false; return false;
} }
@ -220,7 +220,7 @@ QString QgsVectorDataProvider::capabilitiesString() const
int QgsVectorDataProvider::indexFromFieldName(const QString& fieldName) 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) for (QgsFieldMap::const_iterator it = theFields.begin(); it != theFields.end(); ++it)
{ {
@ -248,7 +248,7 @@ void QgsVectorDataProvider::setFetchFeaturesWithoutGeom(bool fetch)
mFetchFeaturesWithoutGeom = fetch; mFetchFeaturesWithoutGeom = fetch;
} }
const QSet<QString>& QgsVectorDataProvider::supportedNativeTypes() const const QgsNativeTypeMap &QgsVectorDataProvider::supportedNativeTypes() const
{ {
return mSupportedNativeTypes; return mSupportedNativeTypes;
} }
@ -261,15 +261,15 @@ QVariant QgsVectorDataProvider::minValue(int index)
QgsDebugMsg("Warning: access requested to invalid field index: " + QString::number(index)); QgsDebugMsg("Warning: access requested to invalid field index: " + QString::number(index));
return QVariant(); return QVariant();
} }
if (mCacheMinMaxDirty) if (mCacheMinMaxDirty)
{ {
fillMinMaxCache(); fillMinMaxCache();
} }
if (!mCacheMinValues.contains(index)) if (!mCacheMinValues.contains(index))
return QVariant(); return QVariant();
return mCacheMinValues[index]; return mCacheMinValues[index];
} }
@ -280,7 +280,7 @@ QVariant QgsVectorDataProvider::maxValue(int index)
QgsDebugMsg("Warning: access requested to invalid field index: " + QString::number(index)); QgsDebugMsg("Warning: access requested to invalid field index: " + QString::number(index));
return QVariant(); return QVariant();
} }
if (mCacheMinMaxDirty) if (mCacheMinMaxDirty)
{ {
fillMinMaxCache(); fillMinMaxCache();

View File

@ -26,9 +26,11 @@ class QTextCodec;
//QGIS Includes //QGIS Includes
#include "qgis.h" #include "qgis.h"
#include "qgsdataprovider.h" #include "qgsdataprovider.h"
#include "qgsvectorlayer.h" #include "qgsvectorlayer.h"
#include "qgsfield.h"
typedef QMap<QString, QString> QgsNewAttributesMap;
typedef QMap<QString, QVariant::Type> QgsNativeTypeMap;
/** Base class for vector data providers /** 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 a map of indexes with field names for this layer
* @return map of fields * @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 * 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 * Adds a list of features
* @return true in case of success and false in case of failure * @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 * Deletes a feature
* @param id list containing feature ids to delete * @param id list containing feature ids to delete
* @return true in case of success and false in case of failure * @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 * Adds new attributes
@ -246,24 +248,24 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider
* Set encoding used for accessing data from layer * Set encoding used for accessing data from layer
*/ */
virtual void setEncoding(const QString& e); virtual void setEncoding(const QString& e);
/** /**
* Get encoding which is used for accessing data * Get encoding which is used for accessing data
*/ */
QString encoding() const; QString encoding() const;
/** /**
* Returns the index of a field name or -1 if the field does not exist * Returns the index of a field name or -1 if the field does not exist
*/ */
int indexFromFieldName(const QString& fieldName) const; int indexFromFieldName(const QString& fieldName) const;
/** /**
* Return list of indexes to fetch all attributes in getNextFeature() * Return list of indexes to fetch all attributes in getNextFeature()
*/ */
virtual QgsAttributeList allAttributesList(); virtual QgsAttributeList allAttributesList();
/**Returns the names of the numerical types*/ /**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 * 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); void setFetchFeaturesWithoutGeom(bool fetch);
protected: protected:
void fillMinMaxCache(); void fillMinMaxCache();
bool mCacheMinMaxDirty; bool mCacheMinMaxDirty;
QMap<int, QVariant> mCacheMinValues, mCacheMaxValues; QMap<int, QVariant> mCacheMinValues, mCacheMaxValues;
/** Encoding */ /** Encoding */
QTextCodec* mEncoding; QTextCodec* mEncoding;
@ -292,7 +293,7 @@ class CORE_EXPORT QgsVectorDataProvider : public QgsDataProvider
QgsAttributeList mAttributesToFetch; QgsAttributeList mAttributesToFetch;
/**The names of the providers native types*/ /**The names of the providers native types*/
QSet<QString> mSupportedNativeTypes; QgsNativeTypeMap mSupportedNativeTypes;
}; };
#endif #endif

View File

@ -219,7 +219,7 @@ bool QgsVectorFileWriter::addFeature(QgsFeature& feature)
} }
// build geometry from WKB // build geometry from WKB
QgsGeometry* geom = feature.geometry(); QgsGeometry *geom = feature.geometry();
if (geom->wkbType() != mWkbType) if (geom->wkbType() != mWkbType)
{ {
@ -234,7 +234,7 @@ bool QgsVectorFileWriter::addFeature(QgsFeature& feature)
OGRGeometryH mGeom2 = createEmptyGeometry(geom->wkbType()); 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) if (err != OGRERR_NONE)
{ {
QgsDebugMsg("Failed to import geometry from WKB: " + QString::number(err)); QgsDebugMsg("Failed to import geometry from WKB: " + QString::number(err));
@ -247,7 +247,7 @@ bool QgsVectorFileWriter::addFeature(QgsFeature& feature)
} }
else 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) if (err != OGRERR_NONE)
{ {
QgsDebugMsg("Failed to import geometry from WKB: " + QString::number(err)); QgsDebugMsg("Failed to import geometry from WKB: " + QString::number(err));

View File

@ -21,8 +21,7 @@
#define _QGSVECTORFILEWRITER_H_ #define _QGSVECTORFILEWRITER_H_
#include "qgsvectorlayer.h" #include "qgsvectorlayer.h"
#include "qgsfield.h"
#include <QString>
typedef void *OGRDataSourceH; typedef void *OGRDataSourceH;
typedef void *OGRLayerH; typedef void *OGRLayerH;
@ -41,7 +40,7 @@ class QTextCodec;
class CORE_EXPORT QgsVectorFileWriter class CORE_EXPORT QgsVectorFileWriter
{ {
public: public:
enum WriterError enum WriterError
{ {
NoError = 0, NoError = 0,
@ -64,36 +63,36 @@ class CORE_EXPORT QgsVectorFileWriter
const QgsFieldMap& fields, const QgsFieldMap& fields,
QGis::WKBTYPE geometryType, QGis::WKBTYPE geometryType,
const QgsSpatialRefSys* srs); const QgsSpatialRefSys* srs);
/** checks whether there were any errors in constructor */ /** checks whether there were any errors in constructor */
WriterError hasError(); WriterError hasError();
/** add feature to the currently opened shapefile */ /** add feature to the currently opened shapefile */
bool addFeature(QgsFeature& feature); bool addFeature(QgsFeature& feature);
/** close opened shapefile for writing */ /** close opened shapefile for writing */
~QgsVectorFileWriter(); ~QgsVectorFileWriter();
/** Delete a shapefile (and its accompanying shx / dbf / prf) /** Delete a shapefile (and its accompanying shx / dbf / prf)
* @param QString theFileName - /path/to/file.shp * @param QString theFileName - /path/to/file.shp
* @return bool true if the file was deleted successfully * @return bool true if the file was deleted successfully
*/ */
static bool deleteShapeFile(QString theFileName); static bool deleteShapeFile(QString theFileName);
protected: protected:
OGRGeometryH createEmptyGeometry(QGis::WKBTYPE wkbType); OGRGeometryH createEmptyGeometry(QGis::WKBTYPE wkbType);
OGRDataSourceH mDS; OGRDataSourceH mDS;
OGRLayerH mLayer; OGRLayerH mLayer;
OGRGeometryH mGeom; OGRGeometryH mGeom;
QgsFieldMap mFields; QgsFieldMap mFields;
/** contains error value if construction was not successfull */ /** contains error value if construction was not successfull */
WriterError mError; WriterError mError;
QTextCodec* mCodec; QTextCodec* mCodec;
/** geometry type which is being used */ /** geometry type which is being used */
QGis::WKBTYPE mWkbType; QGis::WKBTYPE mWkbType;
}; };

File diff suppressed because it is too large Load Diff

View File

@ -22,20 +22,20 @@
#include <QMap> #include <QMap>
#include <QSet> #include <QSet>
#include <QList> #include <QList>
#include <QPair> #include <QStringList>
#include "qgis.h" #include "qgis.h"
#include "qgsmaplayer.h" #include "qgsmaplayer.h"
#include "qgsfeature.h" #include "qgsfeature.h"
#include "qgssnapper.h" #include "qgssnapper.h"
#include "qgsfeature.h"
#include "qgsfield.h"
class QPainter; class QPainter;
class QImage; class QImage;
class QgsAttributeAction; class QgsAttributeAction;
class QgsCoordinateTransform; class QgsCoordinateTransform;
class QgsField;
class QgsFeature;
class QgsGeometry; class QgsGeometry;
class QgsGeometryVertexIndex; class QgsGeometryVertexIndex;
class QgsMapToPixel; class QgsMapToPixel;
@ -44,34 +44,39 @@ class QgsRect;
class QgsRenderer; class QgsRenderer;
class QgsVectorDataProvider; class QgsVectorDataProvider;
class QgsGeometry; class QgsGeometry;
class QgsRect; 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> QgsFeatureIds;
typedef QSet<int> QgsAttributeIds; typedef QSet<int> QgsAttributeIds;
// key = attribute name, value = attribute type
typedef QMap<QString, QString> QgsNewAttributesMap;
typedef QMap<int, QgsField> QgsFieldMap;
/*! \class QgsVectorLayer /*! \class QgsVectorLayer
* \brief Vector layer backed by a data source provider * \brief Vector layer backed by a data source provider
*/ */
class CORE_EXPORT QgsVectorLayer : public QgsMapLayer class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
{ {
Q_OBJECT Q_OBJECT
public: 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 */ /** Constructor */
QgsVectorLayer(QString path = 0, QString baseName = 0, QgsVectorLayer(QString path = 0, QString baseName = 0,
@ -113,35 +118,31 @@ public:
/** The number of features that are selected in this layer */ /** The number of features that are selected in this layer */
int selectedFeatureCount(); int selectedFeatureCount();
/** Select features found within the search rectangle (in layer's coordinates) */ /** Select features found within the search rectangle (in layer's coordinates) */
void select(QgsRect & rect, bool lock); void select(QgsRect & rect, bool lock);
/** Select not selected features and deselect selected ones */ /** Select not selected features and deselect selected ones */
void invertSelection(); void invertSelection();
/** Get a copy of the user-selected features */ /** Get a copy of the user-selected features */
QgsFeatureList selectedFeatures(); QgsFeatureList selectedFeatures();
/** Return reference to identifiers of selected features */ /** Return reference to identifiers of selected features */
const QgsFeatureIds& selectedFeaturesIds() const; const QgsFeatureIds& selectedFeaturesIds() const;
/** Change selection to the new set of features */ /** Change selection to the new set of features */
void setSelectedFeatures(const QgsFeatureIds& ids); 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 */ /** Returns the bounding box of the selected features. If there is no selection, QgsRect(0,0,0,0) is returned */
QgsRect boundingBoxOfSelected(); 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 */ /** Copies the symbology settings from another layer. Returns true in case of success */
bool copySymbologySettings(const QgsMapLayer& other); bool copySymbologySettings(const QgsMapLayer& other);
/** Returns true if this layer can be in the same symbology group with another layer */ /** Returns true if this layer can be in the same symbology group with another layer */
bool isSymbologyCompatible(const QgsMapLayer& other) const; bool isSymbologyCompatible(const QgsMapLayer& other) const;
/** Returns a pointer to the renderer */ /** Returns a pointer to the renderer */
const QgsRenderer* renderer() const; const QgsRenderer* renderer() const;
@ -196,13 +197,15 @@ public:
*/ */
virtual QString subsetString(); virtual QString subsetString();
/**Returns the features contained in the rectangle. Considers the changed, added, deleted and permanent features void select(QgsAttributeList fetchAttributes,
@return 0 in case of success*/ QgsRect rect = QgsRect(),
int featuresInRectangle(const QgsRect& searchRect, QList<QgsFeature>& features, bool fetchGeometries = true, bool fetchAttributes = true); bool fetchGeometry = true);
bool getNextFeature(QgsFeature& feature);
/**Gets the feature at the given feature id. Considers the changed, added, deleted and permanent features /**Gets the feature at the given feature id. Considers the changed, added, deleted and permanent features
@return 0 in case of success*/ @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 /** Adds a feature
@param lastFeatureInBatch If True, will also go to the effort of e.g. updating the extents. @param lastFeatureInBatch If True, will also go to the effort of e.g. updating the extents.
@ -233,14 +236,24 @@ public:
bool deleteSelectedFeatures(); bool deleteSelectedFeatures();
/**Adds a ring to polygon/multipolygon features /**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 \ @return
existing rings, 5 no feature found where ring can be inserted*/ 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); int addRing(const QList<QgsPoint>& ring);
/**Adds a new island polygon to a multipolygon feature /**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, \ @return
3if new polygon ring not disjoint with existing rings, 4 if no feature was selected, 5 if several features are selected, \ 0 in case of success,
6 if selected geometry not found*/ 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); int addIsland(const QList<QgsPoint>& ring);
/**Translates feature by dx, dy /**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*/ @return 0 in case of success*/
int splitFeatures(const QList<QgsPoint>& splitLine, bool topologicalEditing = false); 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 polygon (or multipolygon) geometries in this vector layer
@param geom geometry to modify @param geom geometry to modify
@return 0 in case of success*/ @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 @param snap_to to segment / to vertex
@return 0 in case of success @return 0 in case of success
*/ */
int snapWithContext(const QgsPoint& startPoint, double snappingTolerance, QMultiMap<double, QgsSnappingResult>& snappingResults, \ int snapWithContext(const QgsPoint& startPoint, double snappingTolerance, QMultiMap<double, QgsSnappingResult>& snappingResults,
QgsSnapper::SNAP_TO snap_to); 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);
/** Draws the layer /** Draws the layer
* @return FALSE if an error occurred during drawing * @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); void drawLabels(QPainter * p, const QgsRect& viewExtent, const QgsMapToPixel* cXf, const QgsCoordinateTransform* ct, double scale);
/** returns array of added features */ /** returns fields list which are not commited */
QgsFeatureList& addedFeatures(); const QgsFieldMap &pendingFields();
/** returns array of deleted feature IDs */ /** returns list of attributes */
QgsFeatureIds& deletedFeatureIds(); QgsAttributeList pendingAllAttributesList();
/** returns array of features with changed attributes */ /** returns feature count after commit */
QgsChangedAttributesMap& changedAttributes(); int pendingFeatureCount();
/** Sets whether some features are modified or not */ /** Sets whether some features are modified or not */
void setModified(bool modified = TRUE, bool onlyGeometryWasModified = FALSE); void setModified(bool modified = TRUE, bool onlyGeometryWasModified = FALSE);
/** Make layer editable */ /** Make layer editable */
bool startEditing(); 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. Attempts to commit any changes to disk. Returns the result of the attempt.
If a commit fails, the in-memory changes are left alone. 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 disallowed value in a Postgres database - the user can re-edit and try
again. again.
The commits (in this version) occur in four distinct stages, The commits occur in distinct stages,
(add features, change attributes, change geometries, delete features) (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. so if a stage fails, it's difficult to roll back cleanly.
Therefore any error message also includes which stage failed so Therefore any error message also includes which stage failed so
that the user has some chance of repairing the damage cleanly. that the user has some chance of repairing the damage cleanly.
*/ */
bool commitChanges(); bool commitChanges();
const QStringList &commitErrors();
/** Stop editing and discard the edits */ /** Stop editing and discard the edits */
bool rollBack(); 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() */ /** Select feature by its ID, optionally emit signal selectionChanged() */
void select(int featureId, bool emitSignal = TRUE); void select(int featureId, bool emitSignal = TRUE);
@ -405,6 +423,15 @@ signals:
/** This signal is emitted when modifications has been done on layer */ /** This signal is emitted when modifications has been done on layer */
void wasModified(bool onlyGeometry); 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 private: // Private methods
enum VertexMarkerType enum VertexMarkerType
@ -424,7 +451,7 @@ private: // Private methods
@todo XXX should this return bool? Throw exceptions? @todo XXX should this return bool? Throw exceptions?
*/ */
bool setDataProvider( QString const & provider ); bool setDataProvider( QString const & provider );
/** Draws features. May cause projections exceptions to be generated /** Draws features. May cause projections exceptions to be generated
* (i.e., code that calls this function needs to catch them * (i.e., code that calls this function needs to catch them
*/ */
@ -433,7 +460,7 @@ private: // Private methods
const QgsMapToPixel* cXf, const QgsMapToPixel* cXf,
const QgsCoordinateTransform* ct, const QgsCoordinateTransform* ct,
QImage* marker, QImage* marker,
double widthScale, double widthScale,
double markerScaleFactor, double markerScaleFactor,
bool drawingToEditingCanvas); bool drawingToEditingCanvas);
@ -447,19 +474,19 @@ private: // Private methods
/** Draw the linestring as given in the WKB format. Returns a pointer /** 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). * to the byte after the end of the line string binary data stream (WKB).
*/ */
unsigned char* drawLineString(unsigned char* WKBlinestring, unsigned char *drawLineString(unsigned char *WKBlinestring,
QPainter* p, QPainter *p,
const QgsMapToPixel* mtp, const QgsMapToPixel *mtp,
const QgsCoordinateTransform* ct, const QgsCoordinateTransform *ct,
bool drawingToEditingCanvas); bool drawingToEditingCanvas);
/** Draw the polygon as given in the WKB format. Returns a pointer to /** 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). * the byte after the end of the polygon binary data stream (WKB).
*/ */
unsigned char* drawPolygon(unsigned char* WKBpolygon, unsigned char *drawPolygon(unsigned char *WKBpolygon,
QPainter* p, QPainter *p,
const QgsMapToPixel* mtp, const QgsMapToPixel *mtp,
const QgsCoordinateTransform* ct, const QgsCoordinateTransform *ct,
bool drawingToEditingCanvas); bool drawingToEditingCanvas);
/** Goes through all features and finds a free id (e.g. to give it temporarily to a not-commited feature) */ /** 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 snappingResult list to which the result is appended
@param snap_to snap to vertex or to segment @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; QMultiMap<double, QgsSnappingResult>& snappingResults, QgsSnapper::SNAP_TO snap_to) const;
/**Little helper function that gives bounding box from a list of points. /**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*/ /**Reads vertex marker type from settings*/
QgsVectorLayer::VertexMarkerType currentVertexMarkerType(); 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 private: // Private attributes
@ -513,36 +545,48 @@ private: // Private attributes
/** Flag indicating whether the layer has been modified since the last commit */ /** Flag indicating whether the layer has been modified since the last commit */
bool mModified; bool mModified;
/** cache of the committed geometries retrieved *for the current display* */ /** cache of the committed geometries retrieved *for the current display* */
QgsGeometryMap mCachedGeometries; QgsGeometryMap mCachedGeometries;
/** Set holding the feature IDs that are activated. Note that if a feature /** Set holding the feature IDs that are activated. Note that if a feature
subsequently gets deleted (i.e. by its addition to mDeletedFeatureIds), subsequently gets deleted (i.e. by its addition to mDeletedFeatureIds),
it always needs to be removed from mSelectedFeatureIds as well. it always needs to be removed from mSelectedFeatureIds as well.
*/ */
QgsFeatureIds mSelectedFeatureIds; QgsFeatureIds mSelectedFeatureIds;
/** Deleted feature IDs which are not commited. Note a feature can be added and then deleted /** 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 again before the change is committed - in that case the added feature would be removed
from mAddedFeatures only and *not* entered here. from mAddedFeatures only and *not* entered here.
*/ */
QgsFeatureIds mDeletedFeatureIds; QgsFeatureIds mDeletedFeatureIds;
/** New features which are not commited. Note a feature can be added and then changed, /** 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; QgsFeatureList mAddedFeatures;
/** Changed attributes which are not commited */ /** Changed attributes values which are not commited */
QgsChangedAttributesMap mChangedAttributes; 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. */ /** Changed geometries which are not commited. */
QgsGeometryMap mChangedGeometries; QgsGeometryMap mChangedGeometries;
/** field map to commit */
QgsFieldMap mUpdatedFields;
/** max field index */
int mMaxUpdatedIndex;
/** Geometry type as defined in enum WKBTYPE (qgis.h) */ /** Geometry type as defined in enum WKBTYPE (qgis.h) */
int mGeometryType; int mGeometryType;
/** Renderer object which holds the information about how to display the features */ /** Renderer object which holds the information about how to display the features */
QgsRenderer *mRenderer; QgsRenderer *mRenderer;
@ -552,6 +596,20 @@ private: // Private attributes
/** Display labels */ /** Display labels */
bool mLabelOn; 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 #endif

View File

@ -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 //first find out the value for the classification attribute
const QgsAttributeMap& attrs = f->attributeMap(); const QgsAttributeMap& attrs = f->attributeMap();

View File

@ -40,7 +40,7 @@ class CORE_EXPORT QgsGraduatedSymbolRenderer: public QgsRenderer
void removeSymbols(); void removeSymbols();
/** Determines if a feature will be rendered or not /** Determines if a feature will be rendered or not
@param f a pointer to the feature to determine if rendering will happen*/ @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 /**Renders an OGRFeature
\param p a painter (usually the one from the current map canvas) \param p a painter (usually the one from the current map canvas)
\param f a pointer to a feature to render \param f a pointer to a feature to render
@ -72,7 +72,7 @@ class CORE_EXPORT QgsGraduatedSymbolRenderer: public QgsRenderer
int mClassificationField; int mClassificationField;
/**List holding the symbols for the individual classes*/ /**List holding the symbols for the individual classes*/
QList<QgsSymbol*> mSymbols; QList<QgsSymbol*> mSymbols;
QgsSymbol* symbolForFeature(const QgsFeature* f); QgsSymbol *symbolForFeature(const QgsFeature* f);
/**Cached copy of all underlying symbols required attribute fields*/ /**Cached copy of all underlying symbols required attribute fields*/
QgsAttributeList mSymbolAttributes; QgsAttributeList mSymbolAttributes;

View File

@ -103,13 +103,13 @@ void QgsSingleSymbolRenderer::renderFeature(QPainter * p, QgsFeature & f, QImage
//first find out the value for the scale classification attribute //first find out the value for the scale classification attribute
const QgsAttributeMap& attrs = f.attributeMap(); const QgsAttributeMap& attrs = f.attributeMap();
fieldScale = sqrt(fabs(attrs[mSymbol->scaleClassificationField()].toDouble())); 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 ) if ( mSymbol->rotationClassificationField() >= 0 )
{ {
const QgsAttributeMap& attrs = f.attributeMap(); const QgsAttributeMap& attrs = f.attributeMap();
rotation = attrs[mSymbol->rotationClassificationField()].toDouble(); 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); *img = mSymbol->getPointSymbolAsImage( widthScale, selected, mSelectionColor, fieldScale, rotation, rasterScaleFactor);

View File

@ -34,7 +34,7 @@ class CORE_EXPORT QgsSingleSymbolRenderer: public QgsRenderer
void addSymbol(QgsSymbol* sy); void addSymbol(QgsSymbol* sy);
/*Returns a pointer to mSymbol*/ /*Returns a pointer to mSymbol*/
const QgsSymbol* symbol() const; 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); 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 /**Reads the renderer configuration from an XML file
@param rnode the DOM node to read @param rnode the DOM node to read

View File

@ -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 //first find out the value
const QgsAttributeMap& attrs = f->attributeMap(); const QgsAttributeMap& attrs = f->attributeMap();

View File

@ -30,7 +30,7 @@ class CORE_EXPORT QgsUniqueValueRenderer: public QgsRenderer
virtual ~QgsUniqueValueRenderer(); virtual ~QgsUniqueValueRenderer();
/** Determines if a feature will be rendered or not /** Determines if a feature will be rendered or not
@param f a pointer to the feature to determine if rendering will happen*/ @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); 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 /**Reads the renderer configuration from an XML file
@param rnode the DOM node to read @param rnode the DOM node to read
@ -64,7 +64,7 @@ class CORE_EXPORT QgsUniqueValueRenderer: public QgsRenderer
/**Symbols for the unique values*/ /**Symbols for the unique values*/
QMap<QString, QgsSymbol*> mSymbols; QMap<QString, QgsSymbol*> mSymbols;
/**Returns the symbol for a feature or 0 if there isn't any*/ /**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*/ /**Cached copy of all underlying symbols required attribute fields*/
QgsAttributeList mSymbolAttributes; QgsAttributeList mSymbolAttributes;
bool mSymbolAttributesDirty; // insertValue was called bool mSymbolAttributesDirty; // insertValue was called

View File

@ -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) double rotation, double rasterScaleFactor)
{ {
//QgsDebugMsg(QString("Symbol scale = %1, and rotation = %2").arg(scale).arg(rotation)); //QgsDebugMsg(QString("Symbol scale = %1, and rotation = %2").arg(scale).arg(rotation));

View File

@ -44,6 +44,8 @@ class QValidator;
// Must be here, so that it is included to moc file // Must be here, so that it is included to moc file
#include "qgsvectorlayer.h" #include "qgsvectorlayer.h"
#include "qgsfield.h"
class QgisInterface; class QgisInterface;
class QgsMapCanvas; class QgsMapCanvas;
@ -490,9 +492,9 @@ public:
* \param qdesc option element in QGIS module description XML file * \param qdesc option element in QGIS module description XML file
* \param gdesc GRASS module XML description file * \param gdesc GRASS module XML description file
*/ */
QgsGrassModuleInput ( QgsGrassModule *module, QgsGrassModuleInput ( QgsGrassModule *module,
QgsGrassModuleStandardOptions *options, QString key, QgsGrassModuleStandardOptions *options, QString key,
QDomElement &qdesc, QDomElement &gdesc, QDomNode &gnode, QDomElement &qdesc, QDomElement &gdesc, QDomNode &gnode,
QWidget * parent = 0 ); QWidget * parent = 0 );
//! Destructor //! Destructor

View File

@ -37,7 +37,7 @@ class GPSData;
*/ */
class QgsGPXProvider : public QgsVectorDataProvider class QgsGPXProvider : public QgsVectorDataProvider
{ {
Q_OBJECT; Q_OBJECT
public: public:

View File

@ -36,16 +36,6 @@ email : sherman at mrcc.com
#include <QString> #include <QString>
#include <QTextCodec> #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 "qgsapplication.h"
#include "qgsdataprovider.h" #include "qgsdataprovider.h"
#include "qgsfeature.h" #include "qgsfeature.h"
@ -134,13 +124,9 @@ QgsOgrProvider::QgsOgrProvider(QString const & uri)
valid = false; valid = false;
} }
// create the geos objects mSupportedNativeTypes.insert("Integer", QVariant::Int);
geometryFactory = new GEOS_GEOM::GeometryFactory(); mSupportedNativeTypes.insert("Real", QVariant::Double);
assert(geometryFactory!=0); mSupportedNativeTypes.insert("String", QVariant::String);
mSupportedNativeTypes.insert("Integer");
mSupportedNativeTypes.insert("Real");
mSupportedNativeTypes.insert("String");
} }
QgsOgrProvider::~QgsOgrProvider() QgsOgrProvider::~QgsOgrProvider()
@ -149,7 +135,6 @@ QgsOgrProvider::~QgsOgrProvider()
ogrDataSource = 0; ogrDataSource = 0;
free(extent_); free(extent_);
extent_ = 0; extent_ = 0;
delete geometryFactory;
if( mSelectionRectangle ) if( mSelectionRectangle )
{ {
OGR_G_DestroyGeometry( mSelectionRectangle ); OGR_G_DestroyGeometry( mSelectionRectangle );

View File

@ -19,23 +19,10 @@ email : sherman at mrcc.com
#include "qgsrect.h" #include "qgsrect.h"
#include "qgsvectordataprovider.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 QgsFeature;
class QgsField; class QgsField;
typedef void *OGRDataSourceH; #include <ogr_api.h>
typedef void *OGRSFDriverH;
typedef void *OGRLayerH;
typedef void *OGRFeatureH;
typedef void *OGRGeometryH;
/** /**
\class QgsOgrProvider \class QgsOgrProvider
@ -264,6 +251,4 @@ class QgsOgrProvider : public QgsVectorDataProvider
bool addFeature(QgsFeature& f); bool addFeature(QgsFeature& f);
/**Deletes one feature*/ /**Deletes one feature*/
bool deleteFeature(int id); bool deleteFeature(int id);
//! The geometry factory
GEOS_GEOM::GeometryFactory *geometryFactory;
}; };

View File

@ -49,7 +49,8 @@
const QString POSTGRES_KEY = "postgres"; const QString POSTGRES_KEY = "postgres";
const QString POSTGRES_DESCRIPTION = "PostgreSQL/PostGIS data provider"; 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; int QgsPostgresProvider::providerIds=0;
QgsPostgresProvider::QgsPostgresProvider(QString const & uri) QgsPostgresProvider::QgsPostgresProvider(QString const & uri)
@ -86,12 +87,9 @@ QgsPostgresProvider::QgsPostgresProvider(QString const & uri)
QgsDebugMsg("Schema is: " + mSchemaName); QgsDebugMsg("Schema is: " + mSchemaName);
QgsDebugMsg("Table name is: " + mTableName); QgsDebugMsg("Table name is: " + mTableName);
//QString logFile = "./pg_provider_" + mTableName + ".log"; connectionRW = NULL;
//pLog.open((const char *)logFile); connectionRO = connectDb( mUri.connInfo() );
//QgsDebugMsg("Opened log file for " + mTableName); if( connectionRO==NULL ) {
connection = connectDb( mUri.connInfo() );
if( connection==NULL ) {
valid = false; valid = false;
return; return;
} }
@ -100,7 +98,7 @@ QgsPostgresProvider::QgsPostgresProvider(QString const & uri)
the problems they will see :) */ the problems they will see :) */
QgsDebugMsg("Checking for GEOS support"); QgsDebugMsg("Checking for GEOS support");
if(!hasGEOS(connection)) if(!hasGEOS(connectionRO))
{ {
showMessageBox(tr("No GEOS Support!"), showMessageBox(tr("No GEOS Support!"),
tr("Your PostGIS installation has no GEOS support.\n" 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 // Check that we can read from the table (i.e., we have
// select permission). // select permission).
QString sql = QString("select * from %1 limit 1").arg(mSchemaTableName); 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) if (PQresultStatus(testAccess) != PGRES_TUPLES_OK)
{ {
showMessageBox(tr("Unable to access relation"), showMessageBox(tr("Unable to access relation"),
@ -136,7 +134,7 @@ QgsPostgresProvider::QgsPostgresProvider(QString const & uri)
"current_schema()") "current_schema()")
.arg( quotedValue(mSchemaTableName) ); .arg( quotedValue(mSchemaTableName) );
testAccess = PQexec( connection, sql.toUtf8() ); testAccess = PQexec( connectionRO, sql.toUtf8() );
if( PQresultStatus(testAccess) != PGRES_TUPLES_OK ) { if( PQresultStatus(testAccess) != PGRES_TUPLES_OK ) {
showMessageBox(tr("Unable to access relation"), showMessageBox(tr("Unable to access relation"),
tr("Unable to determine table access privileges for the ") + mSchemaTableName + tr("Unable to determine table access privileges for the ") + mSchemaTableName +
@ -181,7 +179,7 @@ QgsPostgresProvider::QgsPostgresProvider(QString const & uri)
"relname=%1 AND nspname=%2") "relname=%1 AND nspname=%2")
.arg( quotedValue(mTableName) ) .arg( quotedValue(mTableName) )
.arg( quotedValue(mSchemaName) ); .arg( quotedValue(mSchemaName) );
testAccess = PQexec(connection, sql.toUtf8()); testAccess = PQexec(connectionRO, sql.toUtf8());
if (PQresultStatus(testAccess) == PGRES_TUPLES_OK && PQntuples(testAccess)==1) if (PQresultStatus(testAccess) == PGRES_TUPLES_OK && PQntuples(testAccess)==1)
{ {
enabledCapabilities |= QgsVectorDataProvider::AddAttributes | QgsVectorDataProvider::DeleteAttributes; 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 // Set the postgresql message level so that we don't get the
// 'there is no transaction in progress' warning. // 'there is no transaction in progress' warning.
#ifndef QGISDEBUG #ifndef QGISDEBUG
PQexecNR(connection, QString("set client_min_messages to error").toUtf8()); PQexecNR(connectionRO, QString("set client_min_messages to error").toUtf8());
#endif #endif
// Kick off the long running threads // Kick off the long running threads
@ -240,11 +238,11 @@ QgsPostgresProvider::QgsPostgresProvider(QString const & uri)
#endif #endif
//fill type names into sets //fill type names into sets
mSupportedNativeTypes.insert("double precision"); mSupportedNativeTypes.insert("double precision", QVariant::Double);
mSupportedNativeTypes.insert("int4"); mSupportedNativeTypes.insert("int4", QVariant::Int);
mSupportedNativeTypes.insert("int8"); mSupportedNativeTypes.insert("int8", QVariant::LongLong);
mSupportedNativeTypes.insert("text"); mSupportedNativeTypes.insert("text", QVariant::String);
mSupportedNativeTypes.insert("varchar(30)"); mSupportedNativeTypes.insert("varchar(30)", QVariant::String);
if (primaryKey.isEmpty()) if (primaryKey.isEmpty())
{ {
@ -284,8 +282,10 @@ QgsPostgresProvider::~QgsPostgresProvider()
//pLog.flush(); //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) ) if( connections.contains(conninfo) )
{ {
QgsDebugMsg( QString("Using cached connection for %1").arg(conninfo) ); QgsDebugMsg( QString("Using cached connection for %1").arg(conninfo) );
@ -333,24 +333,42 @@ void QgsPostgresProvider::disconnectDb()
{ {
if(mFetching) if(mFetching)
{ {
PQexecNR(connection, QString("CLOSE qgisf%1").arg(providerId).toUtf8() ); PQexecNR(connectionRO, QString("CLOSE qgisf%1").arg(providerId).toUtf8() );
mFetching=false; mFetching=false;
} }
QMap<QString, Conn *>::iterator i; if(!connectionRO) {
for(i=connections.begin(); i!=connections.end() && i.value()->conn!=connection; i++) 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()->conn==connectionRO );
assert( i.value()->ref>0 ); assert( i.value()->ref>0 );
if( --i.value()->ref==0 ) { if( --i.value()->ref==0 ) {
PQfinish( connection ); PQfinish( connectionRO );
delete i.value(); delete i.value();
connections.remove( i.key() ); 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 QString QgsPostgresProvider::storageType() const
@ -409,7 +427,7 @@ bool QgsPostgresProvider::declareCursor(const QString &cursorName,
QgsDebugMsg("Binary cursor: " + declare); QgsDebugMsg("Binary cursor: " + declare);
return PQexecNR(connection, declare.toUtf8()); return PQexecNR(connectionRO, declare.toUtf8());
} }
catch(PGFieldNotFound) catch(PGFieldNotFound)
{ {
@ -515,7 +533,7 @@ void QgsPostgresProvider::select(QgsAttributeList fetchAttributes, QgsRect rect,
if(mFetching) if(mFetching)
{ {
PQexecNR(connection, QString("CLOSE %1").arg(cursorName).toUtf8() ); PQexecNR(connectionRO, QString("CLOSE %1").arg(cursorName).toUtf8() );
mFetching=false; mFetching=false;
while(!mFeatureQueue.empty()) while(!mFeatureQueue.empty())
@ -575,13 +593,13 @@ bool QgsPostgresProvider::getNextFeature(QgsFeature& feature)
if( mFeatureQueue.empty() ) if( mFeatureQueue.empty() )
{ {
QString fetch = QString("fetch forward %1 from %2").arg(mFeatureQueueSize).arg(cursorName); 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)"); qWarning("PQsendQuery failed (1)");
} }
PGresult *queryResult; PGresult *queryResult;
while( (queryResult = PQgetResult(connection)) ) while( (queryResult = PQgetResult(connectionRO)) )
{ {
int rows = PQntuples(queryResult); int rows = PQntuples(queryResult);
if (rows == 0) 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) ) ) if( !declareCursor( cursorName, fetchAttributes, fetchGeometry, QString("%2=%3").arg(quotedIdentifier(primaryKey)).arg(featureId) ) )
return false; 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) if(queryResult==0)
return false; return false;
@ -636,7 +654,7 @@ bool QgsPostgresProvider::getFeatureAtId(int featureId, QgsFeature& feature, boo
{ {
QgsDebugMsg("feature " + QString::number(featureId) + " not found"); QgsDebugMsg("feature " + QString::number(featureId) + " not found");
PQclear(queryResult); PQclear(queryResult);
PQexecNR(connection, QString("CLOSE %1").arg(cursorName).toUtf8()); PQexecNR(connectionRO, QString("CLOSE %1").arg(cursorName).toUtf8());
return false; return false;
} }
else if(rows != 1) else if(rows != 1)
@ -648,7 +666,7 @@ bool QgsPostgresProvider::getFeatureAtId(int featureId, QgsFeature& feature, boo
PQclear(queryResult); PQclear(queryResult);
PQexecNR(connection, QString("CLOSE %1").arg(cursorName).toUtf8()); PQexecNR(connectionRO, QString("CLOSE %1").arg(cursorName).toUtf8());
return gotit; return gotit;
} }
@ -724,7 +742,7 @@ void QgsPostgresProvider::reset()
if(mFetching) if(mFetching)
{ {
//move cursor to first record //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(); mFeatureQueue.empty();
loadFields(); loadFields();
@ -752,13 +770,13 @@ void QgsPostgresProvider::loadFields()
// Get the relation oid for use in later queries // Get the relation oid for use in later queries
QString sql = QString("SELECT regclass(%1)::oid").arg( quotedValue(mSchemaTableName) ); 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)); QString tableoid = QString::fromUtf8(PQgetvalue(tresult, 0, 0));
PQclear(tresult); PQclear(tresult);
// Get the table description // Get the table description
sql = QString("SELECT description FROM pg_description WHERE objoid=%1 AND objsubid=0").arg( tableoid ); 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) if (PQntuples(tresult) > 0)
mDataComment = QString::fromUtf8(PQgetvalue(tresult, 0, 0)); mDataComment = QString::fromUtf8(PQgetvalue(tresult, 0, 0));
PQclear(tresult); PQclear(tresult);
@ -767,7 +785,7 @@ void QgsPostgresProvider::loadFields()
// field name, type, length, and precision (if numeric) // field name, type, length, and precision (if numeric)
sql = QString("select * from %1 limit 0").arg ( mSchemaTableName ); 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; //--std::cout << "Field: Name, Type, Size, Modifier:" << std::endl;
// The queries inside this loop could possibly be combined into one // 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 // "oid = (SELECT Distinct typelem FROM pg_type WHERE " //needs DISTINCT to guard against 2 or more rows on int2
// "typelem = " + typOid + " AND typlen = -1)"; // "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 fieldTypeName = QString::fromUtf8(PQgetvalue(oidResult, 0, 0));
QString fieldSize = QString::fromUtf8(PQgetvalue(oidResult, 0, 1)); QString fieldSize = QString::fromUtf8(PQgetvalue(oidResult, 0, 1));
PQclear(oidResult); PQclear(oidResult);
@ -795,14 +813,14 @@ void QgsPostgresProvider::loadFields()
sql = QString("SELECT attnum FROM pg_attribute WHERE attrelid=%1 AND attname=%2") sql = QString("SELECT attnum FROM pg_attribute WHERE attrelid=%1 AND attname=%2")
.arg( tableoid ).arg( quotedValue(fieldName) ); .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)); QString attnum = QString::fromUtf8(PQgetvalue(tresult, 0, 0));
PQclear(tresult); PQclear(tresult);
sql = QString("SELECT description FROM pg_description WHERE objoid=%1 AND objsubid=%2") sql = QString("SELECT description FROM pg_description WHERE objoid=%1 AND objsubid=%2")
.arg( tableoid ).arg( attnum ); .arg( tableoid ).arg( attnum );
tresult = PQexec(connection, sql.toUtf8()); tresult = PQexec(connectionRO, sql.toUtf8());
if (PQntuples(tresult) > 0) if (PQntuples(tresult) > 0)
fieldComment = QString::fromUtf8(PQgetvalue(tresult, 0, 0)); fieldComment = QString::fromUtf8(PQgetvalue(tresult, 0, 0));
PQclear(tresult); PQclear(tresult);
@ -859,7 +877,7 @@ QString QgsPostgresProvider::getPrimaryKey()
QgsDebugMsg("Getting unique index using '" + sql + "'"); QgsDebugMsg("Getting unique index using '" + sql + "'");
PGresult *pk = executeDbCommand(connection, sql); PGresult *pk = executeDbCommand(connectionRO, sql);
QgsDebugMsg("Got " + QString::number(PQntuples(pk)) + " rows."); 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") sql = QString("SELECT relkind FROM pg_class WHERE oid=regclass(%1)::oid")
.arg( quotedValue(mSchemaTableName) ); .arg( quotedValue(mSchemaTableName) );
PGresult* tableType = executeDbCommand(connection, sql); PGresult* tableType = executeDbCommand(connectionRO, sql);
QString type = QString::fromUtf8(PQgetvalue(tableType, 0, 0)); QString type = QString::fromUtf8(PQgetvalue(tableType, 0, 0));
PQclear(tableType); PQclear(tableType);
@ -892,7 +910,7 @@ QString QgsPostgresProvider::getPrimaryKey()
sql = QString("SELECT attname FROM pg_attribute WHERE attname='oid' AND attrelid=regclass(%1)") sql = QString("SELECT attname FROM pg_attribute WHERE attname='oid' AND attrelid=regclass(%1)")
.arg( quotedValue(mSchemaTableName) ); .arg( quotedValue(mSchemaTableName) );
PGresult* oidCheck = executeDbCommand(connection, sql); PGresult* oidCheck = executeDbCommand(connectionRO, sql);
if (PQntuples(oidCheck) != 0) if (PQntuples(oidCheck) != 0)
{ {
@ -940,7 +958,7 @@ QString QgsPostgresProvider::getPrimaryKey()
// Get the column name and data type // 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)") 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) ); .arg( col ).arg( quotedValue(mSchemaTableName) );
PGresult* types = executeDbCommand(connection, sql); PGresult* types = executeDbCommand(connectionRO, sql);
if( PQntuples(types) > 0 ) if( PQntuples(types) > 0 )
{ {
@ -968,7 +986,7 @@ QString QgsPostgresProvider::getPrimaryKey()
.arg( col.replace(" ", ",") ) .arg( col.replace(" ", ",") )
.arg( quotedValue(mSchemaTableName) ); .arg( quotedValue(mSchemaTableName) );
PGresult* types = executeDbCommand(connection, sql); PGresult* types = executeDbCommand(connectionRO, sql);
QString colNames; QString colNames;
int numCols = PQntuples(types); int numCols = PQntuples(types);
for (int j = 0; j < numCols; ++j) 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, // If there is an oid on the table, use that instead,
// otherwise give up // otherwise give up
sql = QString("select attname from pg_attribute where attname='oid' and attrelid=regclass(%1)::oid").arg( quotedValue(mSchemaTableName) ); 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) 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 // Get the oid from pg_class for the given schema.relation for use
// in subsequent queries. // in subsequent queries.
sql = QString("select regclass(%1)::oid").arg( quotedValue( quotedIdentifier(schemaName) + "." + quotedIdentifier(tableName) ) ); 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; QString rel_oid;
if (PQntuples(result) == 1) if (PQntuples(result) == 1)
{ {
@ -1100,7 +1118,7 @@ QString QgsPostgresProvider::chooseViewColumn(const tableCols& cols)
"and conrelid=%2 and (contype='p' or contype='u') " "and conrelid=%2 and (contype='p' or contype='u') "
"and array_dims(conkey)='[1:1]'").arg( quotedValue(tableCol) ).arg( rel_oid ); "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") if (PQntuples(result) == 1 && colType == "int4")
suitable[viewCol] = iter->second; 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)") 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( rel_oid )
.arg( quotedValue( i->second.column ) ); .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)) if (PQntuples(result) > 0 && uniqueData(mSchemaName, mTableName, i->first))
{ // Got one. Use it. { // Got one. Use it.
@ -1245,7 +1263,7 @@ bool QgsPostgresProvider::uniqueData(QString schemaName,
.arg( quotedIdentifier(schemaName) ) .arg( quotedIdentifier(schemaName) )
.arg( quotedIdentifier(tableName) ); .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")) if (PQntuples(unique)==1 && QString::fromUtf8(PQgetvalue(unique, 0, 0)).startsWith("t"))
isUnique = true; 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") QString newViewDefSql = QString("SELECT definition FROM pg_views WHERE schemaname=%1 AND viewname=%2")
.arg( quotedValue(ns) ).arg( quotedValue(relname) ); .arg( quotedValue(ns) ).arg( quotedValue(relname) );
PGresult* newViewDefResult = PQexec(connection, newViewDefSql.toUtf8()); PGresult* newViewDefResult = PQexec(connectionRO, newViewDefSql.toUtf8());
int numEntries = PQntuples(newViewDefResult); int numEntries = PQntuples(newViewDefResult);
if(numEntries > 0) //relation is a view 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(relname) )
.arg( quotedValue(newAttNameTable) ); .arg( quotedValue(newAttNameTable) );
PGresult* viewColumnResult = PQexec(connection, viewColumnSql.toUtf8()); PGresult* viewColumnResult = PQexec(connectionRO, viewColumnSql.toUtf8());
if(PQntuples(viewColumnResult) > 0) if(PQntuples(viewColumnResult) > 0)
{ {
QString newTableSchema = QString::fromUtf8(PQgetvalue(viewColumnResult, 0, 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(ns) )
.arg( quotedValue(attname_table) ); .arg( quotedValue(attname_table) );
PGresult* typeSqlResult = PQexec(connection, typeSql.toUtf8()); PGresult* typeSqlResult = PQexec(connectionRO, typeSql.toUtf8());
if(PQntuples(typeSqlResult) < 1) if(PQntuples(typeSqlResult) < 1)
{ {
return 1; return 1;
@ -1446,13 +1464,13 @@ void QgsPostgresProvider::findColumns(tableCols& cols)
"view_schema=%1 AND view_name=%2") "view_schema=%1 AND view_name=%2")
.arg( quotedValue(mSchemaName) ) .arg( quotedValue(mSchemaName) )
.arg( quotedValue(mTableName) ); .arg( quotedValue(mTableName) );
PGresult* viewColumnResult = PQexec(connection, viewColumnSql.toUtf8()); PGresult* viewColumnResult = PQexec(connectionRO, viewColumnSql.toUtf8());
//find out view definition //find out view definition
QString viewDefSql = QString("SELECT definition FROM pg_views WHERE schemaname=%1 AND viewname=%2") QString viewDefSql = QString("SELECT definition FROM pg_views WHERE schemaname=%1 AND viewname=%2")
.arg( quotedValue( mSchemaName ) ) .arg( quotedValue( mSchemaName ) )
.arg( quotedValue( mTableName ) ); .arg( quotedValue( mTableName ) );
PGresult* viewDefResult = PQexec(connection, viewDefSql.toUtf8()); PGresult* viewDefResult = PQexec(connectionRO, viewDefSql.toUtf8());
if(PQntuples(viewDefResult) < 1) if(PQntuples(viewDefResult) < 1)
{ {
PQclear(viewDefResult); PQclear(viewDefResult);
@ -1523,7 +1541,7 @@ QVariant QgsPostgresProvider::minValue(int index)
.arg(mSchemaTableName) .arg(mSchemaTableName)
.arg(sqlWhereClause); .arg(sqlWhereClause);
} }
PGresult *rmin = PQexec(connection, sql.toUtf8()); PGresult *rmin = PQexec(connectionRO, sql.toUtf8());
QString minValue = QString::fromUtf8(PQgetvalue(rmin,0,0)); QString minValue = QString::fromUtf8(PQgetvalue(rmin,0,0));
PQclear(rmin); PQclear(rmin);
return minValue.toDouble(); return minValue.toDouble();
@ -1558,7 +1576,7 @@ void QgsPostgresProvider::getUniqueValues(int index, QStringList &uniqueValues)
.arg(sqlWhereClause); .arg(sqlWhereClause);
} }
PGresult *res= PQexec(connection, sql.toUtf8()); PGresult *res= PQexec(connectionRO, sql.toUtf8());
if (PQresultStatus(res) == PGRES_TUPLES_OK) if (PQresultStatus(res) == PGRES_TUPLES_OK)
{ {
for(int i=0; i<PQntuples(res); i++) for(int i=0; i<PQntuples(res); i++)
@ -1593,7 +1611,7 @@ QVariant QgsPostgresProvider::maxValue(int index)
.arg(mSchemaTableName) .arg(mSchemaTableName)
.arg(sqlWhereClause); .arg(sqlWhereClause);
} }
PGresult *rmax = PQexec(connection, sql.toUtf8()); PGresult *rmax = PQexec(connectionRO, sql.toUtf8());
QString maxValue = QString::fromUtf8(PQgetvalue(rmax,0,0)); QString maxValue = QString::fromUtf8(PQgetvalue(rmax,0,0));
PQclear(rmax); PQclear(rmax);
return maxValue.toDouble(); return maxValue.toDouble();
@ -1613,7 +1631,7 @@ int QgsPostgresProvider::maxPrimaryKeyValue()
.arg(quotedIdentifier(primaryKey)) .arg(quotedIdentifier(primaryKey))
.arg(mSchemaTableName); .arg(mSchemaTableName);
PGresult *rmax = PQexec(connection, sql.toUtf8()); PGresult *rmax = PQexec(connectionRO, sql.toUtf8());
QString maxValue = QString::fromUtf8(PQgetvalue(rmax,0,0)); QString maxValue = QString::fromUtf8(PQgetvalue(rmax,0,0));
PQclear(rmax); PQclear(rmax);
@ -1645,7 +1663,7 @@ QVariant QgsPostgresProvider::getDefaultValue(int fieldId)
QVariant defaultValue(QString::null); QVariant defaultValue(QString::null);
PGresult* result = PQexec(connection, sql.toUtf8()); PGresult* result = PQexec(connectionRO, sql.toUtf8());
if (PQntuples(result)==1 && !PQgetisnull(result, 0, 0) ) if (PQntuples(result)==1 && !PQgetisnull(result, 0, 0) )
defaultValue = QString::fromUtf8(PQgetvalue(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() ) 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) ) { if( PQgetisnull(result, 0, 0) ) {
PQclear(result); PQclear(result);
return QByteArray(0); // QByteArray(0).isNull() is true return QByteArray(0); // QByteArray(0).isNull() is true
@ -1742,10 +1760,13 @@ bool QgsPostgresProvider::addFeatures(QgsFeatureList & flist)
if( flist.size() == 0 ) if( flist.size() == 0 )
return true; return true;
if( !connectRW() )
return false;
bool returnvalue=true; bool returnvalue=true;
try { try {
PQexecNR(connection,QString("BEGIN").toUtf8()); PQexecNR(connectionRW,QString("BEGIN").toUtf8());
// Prepare the INSERT statement // Prepare the INSERT statement
QString insert = QString("INSERT INTO %1(%2,%3") QString insert = QString("INSERT INTO %1(%2,%3")
@ -1820,7 +1841,7 @@ bool QgsPostgresProvider::addFeatures(QgsFeatureList & flist)
insert += values + ")"; insert += values + ")";
QgsDebugMsg( QString("prepare addfeatures: %1").arg(insert) ); 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) if(stmt==0 || PQresultStatus(stmt)==PGRES_FATAL_ERROR)
throw PGException(stmt); throw PGException(stmt);
@ -1852,7 +1873,7 @@ bool QgsPostgresProvider::addFeatures(QgsFeatureList & flist)
param[i+2] = qparam[i+2]; 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 ) if( result==0 || PQresultStatus(result)==PGRES_FATAL_ERROR )
{ {
delete param; delete param;
@ -1862,14 +1883,13 @@ bool QgsPostgresProvider::addFeatures(QgsFeatureList & flist)
PQclear(result); PQclear(result);
} }
PQexecNR(connection,QString("COMMIT").toUtf8()); PQexecNR(connectionRW,QString("DEALLOCATE addfeatures").toUtf8());
PQexecNR(connection,QString("DEALLOCATE addfeatures").toUtf8()); PQexecNR(connectionRW,QString("COMMIT").toUtf8());
delete param; delete param;
} catch(PGException &e) { } catch(PGException &e) {
e.showErrorMessage( tr("Error while adding features") ); e.showErrorMessage( tr("Error while adding features") );
PQexecNR(connection,QString("ROLLBACK").toUtf8()); PQexecNR(connectionRW,QString("DEALLOCATE addfeatures").toUtf8());
PQexecNR(connectionRW,QString("ROLLBACK").toUtf8());
PQexecNR(connection,QString("DEALLOCATE addfeatures").toUtf8());
returnvalue = false; returnvalue = false;
} }
@ -1881,8 +1901,11 @@ bool QgsPostgresProvider::deleteFeatures(const QgsFeatureIds & id)
{ {
bool returnvalue=true; bool returnvalue=true;
if( !connectRW() )
return false;
try { try {
PQexecNR(connection,QString("BEGIN").toUtf8()); PQexecNR(connectionRW,QString("BEGIN").toUtf8());
for(QgsFeatureIds::const_iterator it=id.begin();it!=id.end();++it) { for(QgsFeatureIds::const_iterator it=id.begin();it!=id.end();++it) {
QString sql = QString("DELETE FROM %1 WHERE %2=%3") QString sql = QString("DELETE FROM %1 WHERE %2=%3")
@ -1892,16 +1915,16 @@ bool QgsPostgresProvider::deleteFeatures(const QgsFeatureIds & id)
QgsDebugMsg("delete sql: "+sql); QgsDebugMsg("delete sql: "+sql);
//send DELETE statement and do error handling //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 ) if( result==0 || PQresultStatus(result)==PGRES_FATAL_ERROR )
throw PGException(result); throw PGException(result);
PQclear(result); PQclear(result);
} }
PQexecNR(connection,QString("COMMIT").toUtf8()); PQexecNR(connectionRW,QString("COMMIT").toUtf8());
} catch(PGException &e) { } catch(PGException &e) {
e.showErrorMessage( tr("Error while deleting features") ); e.showErrorMessage( tr("Error while deleting features") );
PQexecNR(connection,QString("ROLLBACK").toUtf8()); PQexecNR(connectionRW,QString("ROLLBACK").toUtf8());
returnvalue = false; returnvalue = false;
} }
reset(); reset();
@ -1912,8 +1935,11 @@ bool QgsPostgresProvider::addAttributes(const QgsNewAttributesMap & name)
{ {
bool returnvalue=true; bool returnvalue=true;
if( !connectRW() )
return false;
try { try {
PQexecNR(connection,QString("BEGIN").toUtf8()); PQexecNR(connectionRW,QString("BEGIN").toUtf8());
for(QgsNewAttributesMap::const_iterator iter=name.begin();iter!=name.end();++iter) for(QgsNewAttributesMap::const_iterator iter=name.begin();iter!=name.end();++iter)
{ {
@ -1924,16 +1950,16 @@ bool QgsPostgresProvider::addAttributes(const QgsNewAttributesMap & name)
QgsDebugMsg(sql); QgsDebugMsg(sql);
//send sql statement and do error handling //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 ) if( result==0 || PQresultStatus(result)==PGRES_FATAL_ERROR )
throw PGException(result); throw PGException(result);
PQclear(result); PQclear(result);
} }
PQexecNR(connection,QString("COMMIT").toUtf8()); PQexecNR(connectionRW,QString("COMMIT").toUtf8());
} catch(PGException &e) { } catch(PGException &e) {
e.showErrorMessage( tr("Error while adding attributes") ); e.showErrorMessage( tr("Error while adding attributes") );
PQexecNR(connection,QString("ROLLBACK").toUtf8()); PQexecNR(connectionRW,QString("ROLLBACK").toUtf8());
returnvalue = false; returnvalue = false;
} }
@ -1945,8 +1971,11 @@ bool QgsPostgresProvider::deleteAttributes(const QgsAttributeIds& ids)
{ {
bool returnvalue=true; bool returnvalue=true;
if( !connectRW() )
return false;
try { try {
PQexecNR(connection,QString("BEGIN").toUtf8()); PQexecNR(connectionRW,QString("BEGIN").toUtf8());
for(QgsAttributeIds::const_iterator iter=ids.begin();iter != ids.end();++iter) for(QgsAttributeIds::const_iterator iter=ids.begin();iter != ids.end();++iter)
{ {
@ -1960,7 +1989,7 @@ bool QgsPostgresProvider::deleteAttributes(const QgsAttributeIds& ids)
.arg(quotedIdentifier(column)); .arg(quotedIdentifier(column));
//send sql statement and do error handling //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 ) if( result==0 || PQresultStatus(result)==PGRES_FATAL_ERROR )
throw PGException(result); throw PGException(result);
PQclear(result); PQclear(result);
@ -1969,10 +1998,10 @@ bool QgsPostgresProvider::deleteAttributes(const QgsAttributeIds& ids)
attributeFields.remove(*iter); attributeFields.remove(*iter);
} }
PQexecNR(connection,QString("COMMIT").toUtf8()); PQexecNR(connectionRW,QString("COMMIT").toUtf8());
} catch(PGException &e) { } catch(PGException &e) {
e.showErrorMessage( tr("Error while deleting attributes") ); e.showErrorMessage( tr("Error while deleting attributes") );
PQexecNR(connection,QString("ROLLBACK").toUtf8()); PQexecNR(connectionRW,QString("ROLLBACK").toUtf8());
returnvalue = false; returnvalue = false;
} }
@ -1984,8 +2013,11 @@ bool QgsPostgresProvider::changeAttributeValues(const QgsChangedAttributesMap &
{ {
bool returnvalue=true; bool returnvalue=true;
if( !connectRW() )
return false;
try { try {
PQexecNR(connection,QString("BEGIN").toUtf8()); PQexecNR(connectionRW,QString("BEGIN").toUtf8());
// cycle through the features // cycle through the features
for(QgsChangedAttributesMap::const_iterator iter=attr_map.begin();iter!=attr_map.end();++iter) 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( quotedIdentifier(primaryKey) )
.arg( fid ); .arg( fid );
PGresult* result=PQexec(connection, sql.toUtf8()); PGresult* result=PQexec(connectionRW, sql.toUtf8());
if( result==0 || PQresultStatus(result)==PGRES_FATAL_ERROR ) if( result==0 || PQresultStatus(result)==PGRES_FATAL_ERROR )
throw PGException(result); throw PGException(result);
PQclear(result); PQclear(result);
} }
PQexecNR(connection,QString("COMMIT").toUtf8()); PQexecNR(connectionRW,QString("COMMIT").toUtf8());
} catch(PGException &e) { } catch(PGException &e) {
e.showErrorMessage( tr("Error while changing attributes") ); e.showErrorMessage( tr("Error while changing attributes") );
PQexecNR(connection,QString("ROLLBACK").toUtf8()); PQexecNR(connectionRW,QString("ROLLBACK").toUtf8());
returnvalue = false; returnvalue = false;
} }
@ -2061,11 +2093,14 @@ bool QgsPostgresProvider::changeGeometryValues(QgsGeometryMap & geometry_map)
{ {
QgsDebugMsg("entering."); QgsDebugMsg("entering.");
if( !connectRW() )
return false;
bool returnvalue = true; bool returnvalue = true;
try { try {
// Start the PostGIS transaction // 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") QString update = QString("UPDATE %1 SET %2=GeomFromWKB($1%3,%4) WHERE %5=$2")
.arg( mSchemaTableName ) .arg( mSchemaTableName )
@ -2074,7 +2109,7 @@ bool QgsPostgresProvider::changeGeometryValues(QgsGeometryMap & geometry_map)
.arg( srid ) .arg( srid )
.arg( quotedIdentifier(primaryKey) ); .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) if(stmt==0 || PQresultStatus(stmt)==PGRES_FATAL_ERROR)
throw PGException(stmt); throw PGException(stmt);
@ -2102,7 +2137,7 @@ bool QgsPostgresProvider::changeGeometryValues(QgsGeometryMap & geometry_map)
param[0] = qparam[0]; param[0] = qparam[0];
param[1] = qparam[1]; 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 ) if( result==0 || PQresultStatus(result)==PGRES_FATAL_ERROR )
throw PGException(result); throw PGException(result);
@ -2111,12 +2146,12 @@ bool QgsPostgresProvider::changeGeometryValues(QgsGeometryMap & geometry_map)
} // for each feature } // for each feature
PQexecNR(connection,QString("COMMIT").toUtf8()); PQexecNR(connectionRW,QString("DEALLOCATE updatefeatures").toUtf8());
PQexecNR(connection,QString("DEALLOCATE updatefeatures").toUtf8()); PQexecNR(connectionRW,QString("COMMIT").toUtf8());
} catch(PGException &e) { } catch(PGException &e) {
e.showErrorMessage( tr("Error while changing geometry values") ); e.showErrorMessage( tr("Error while changing geometry values") );
PQexecNR(connection,QString("ROLLBACK").toUtf8()); PQexecNR(connectionRW,QString("DEALLOCATE updatefeatures").toUtf8());
PQexecNR(connection,QString("DEALLOCATE updatefeatures").toUtf8()); PQexecNR(connectionRW,QString("ROLLBACK").toUtf8());
returnvalue = false; returnvalue = false;
} }
@ -2176,7 +2211,7 @@ long QgsPostgresProvider::getFeatureCount()
} }
#endif #endif
PGresult *result = PQexec(connection, sql.toUtf8()); PGresult *result = PQexec(connectionRO, sql.toUtf8());
QgsDebugMsg("Approximate Number of features as text: " + QgsDebugMsg("Approximate Number of features as text: " +
QString::fromUtf8(PQgetvalue(result, 0, 0))); QString::fromUtf8(PQgetvalue(result, 0, 0)));
@ -2219,7 +2254,7 @@ void QgsPostgresProvider::calculateExtents()
QgsDebugMsg("Getting approximate extent using: '" + sql + "'"); 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 // TODO: Guard against the result having no rows
@ -2271,7 +2306,7 @@ void QgsPostgresProvider::calculateExtents()
QgsDebugMsg("Getting extents using schema.table: " + sql); QgsDebugMsg("Getting extents using schema.table: " + sql);
PGresult *result = PQexec(connection, sql.toUtf8()); PGresult *result = PQexec(connectionRO, sql.toUtf8());
if(PQntuples(result)>0) if(PQntuples(result)>0)
{ {
std::string box3d = PQgetvalue(result, 0, 0); std::string box3d = PQgetvalue(result, 0, 0);
@ -2390,7 +2425,7 @@ bool QgsPostgresProvider::deduceEndian()
// return data in the endian of the server // return data in the endian of the server
QString firstOid = QString("select regclass(%1)::oid").arg( quotedValue(mSchemaTableName) ); 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 // get the int value from a "normal" select
QString oidValue = QString::fromUtf8(PQgetvalue(oidResult,0,0)); QString oidValue = QString::fromUtf8(PQgetvalue(oidResult,0,0));
PQclear(oidResult); 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) ); QString oidDeclare = QString("declare oidcursor binary cursor with hold for select regclass(%1)::oid").arg( quotedValue(mSchemaTableName) );
// set up the cursor // set up the cursor
PQexecNR(connection, oidDeclare.toUtf8()); PQexecNR(connectionRO, oidDeclare.toUtf8());
QString fetch = "fetch forward 1 from oidcursor"; QString fetch = "fetch forward 1 from oidcursor";
QgsDebugMsg("Fetching a record and attempting to get check endian-ness"); 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; swapEndian = true;
if(PQntuples(fResult) > 0){ if(PQntuples(fResult) > 0){
// get the oid value from the binary cursor // get the oid value from the binary cursor
@ -2420,7 +2455,7 @@ bool QgsPostgresProvider::deduceEndian()
PQclear(fResult); PQclear(fResult);
} }
PQexecNR(connection, QString("close oidcursor").toUtf8()); PQexecNR(connectionRO, QString("close oidcursor").toUtf8());
return swapEndian; return swapEndian;
} }
@ -2439,7 +2474,7 @@ bool QgsPostgresProvider::getGeometryDetails()
QgsDebugMsg("Getting geometry column: " + sql); QgsDebugMsg("Getting geometry column: " + sql);
PGresult *result = executeDbCommand(connection, sql); PGresult *result = executeDbCommand(connectionRO, sql);
QgsDebugMsg("geometry column query returned " + QString::number(PQntuples(result))); QgsDebugMsg("geometry column query returned " + QString::number(PQntuples(result)));
@ -2467,7 +2502,7 @@ bool QgsPostgresProvider::getGeometryDetails()
sql += " limit 1"; sql += " limit 1";
result = executeDbCommand(connection, sql); result = executeDbCommand(connectionRO, sql);
if (PQntuples(result) > 0) if (PQntuples(result) > 0)
{ {
@ -2493,7 +2528,7 @@ bool QgsPostgresProvider::getGeometryDetails()
if(mUri.sql()!="") if(mUri.sql()!="")
sql += " where " + mUri.sql(); sql += " where " + mUri.sql();
result = executeDbCommand(connection, sql); result = executeDbCommand(connectionRO, sql);
if (PQntuples(result)==1) if (PQntuples(result)==1)
{ {
@ -2665,7 +2700,7 @@ QString QgsPostgresProvider::subsetString()
PGconn * QgsPostgresProvider::pgConnection() PGconn * QgsPostgresProvider::pgConnection()
{ {
return connection; return connectionRW;
} }
QString QgsPostgresProvider::getTableName() QString QgsPostgresProvider::getTableName()

View File

@ -47,10 +47,9 @@ class QgsGeometry;
interface defined in the QgsDataProvider class to provide access to spatial interface defined in the QgsDataProvider class to provide access to spatial
data residing in a PostgreSQL/PostGIS enabled database. data residing in a PostgreSQL/PostGIS enabled database.
*/ */
class QgsPostgresProvider:public QgsVectorDataProvider class QgsPostgresProvider : public QgsVectorDataProvider
{ {
Q_OBJECT;
Q_OBJECT
public: public:
/** /**
@ -405,7 +404,18 @@ class QgsPostgresProvider:public QgsVectorDataProvider
/** /**
* Connection pointer * 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 * Spatial reference id of the layer
*/ */
@ -584,7 +594,7 @@ class QgsPostgresProvider:public QgsVectorDataProvider
*/ */
void customEvent ( QEvent *e ); void customEvent ( QEvent *e );
PGconn *connectDb(const QString &conninfo); PGconn *connectDb(const QString &conninfo, bool readonly=true);
void disconnectDb(); void disconnectDb();
bool useWkbHex; bool useWkbHex;
@ -605,7 +615,8 @@ class QgsPostgresProvider:public QgsVectorDataProvider
int ref; int ref;
PGconn *conn; PGconn *conn;
}; };
static QMap<QString, Conn *> connections; static QMap<QString, Conn *> connectionsRW;
static QMap<QString, Conn *> connectionsRO;
static int providerIds; static int providerIds;
}; };

View File

@ -13,27 +13,20 @@
<string>Attribute Table</string> <string>Attribute Table</string>
</property> </property>
<property name="windowIcon" > <property name="windowIcon" >
<iconset/> <iconset>
<normaloff/>
</iconset>
</property> </property>
<layout class="QGridLayout" > <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" > <property name="horizontalSpacing" >
<number>6</number> <number>6</number>
</property> </property>
<property name="verticalSpacing" > <property name="verticalSpacing" >
<number>2</number> <number>2</number>
</property> </property>
<property name="margin" >
<number>0</number>
</property>
<item row="0" column="0" > <item row="0" column="0" >
<widget class="QToolButton" name="mRemoveSelectionButton" > <widget class="QToolButton" name="mRemoveSelectionButton" >
<property name="toolTip" > <property name="toolTip" >
@ -43,7 +36,8 @@
<string/> <string/>
</property> </property>
<property name="icon" > <property name="icon" >
<iconset>../xpm/remove_selection.xpm</iconset> <iconset>
<normaloff>../xpm/remove_selection.xpm</normaloff>../xpm/remove_selection.xpm</iconset>
</property> </property>
<property name="shortcut" > <property name="shortcut" >
<string/> <string/>
@ -59,7 +53,8 @@
<string/> <string/>
</property> </property>
<property name="icon" > <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>
<property name="shortcut" > <property name="shortcut" >
<string>Ctrl+T</string> <string>Ctrl+T</string>
@ -75,7 +70,8 @@
<string/> <string/>
</property> </property>
<property name="icon" > <property name="icon" >
<iconset>../xpm/switch_selection.png</iconset> <iconset>
<normaloff>../xpm/switch_selection.png</normaloff>../xpm/switch_selection.png</iconset>
</property> </property>
<property name="shortcut" > <property name="shortcut" >
<string>Ctrl+S</string> <string>Ctrl+S</string>
@ -94,7 +90,8 @@
<string/> <string/>
</property> </property>
<property name="icon" > <property name="icon" >
<iconset>../xpm/copy_selection.png</iconset> <iconset>
<normaloff>../xpm/copy_selection.png</normaloff>../xpm/copy_selection.png</iconset>
</property> </property>
<property name="shortcut" > <property name="shortcut" >
<string>Ctrl+C</string> <string>Ctrl+C</string>
@ -117,66 +114,12 @@
</property> </property>
</widget> </widget>
</item> </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" > <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> <spacer>
<property name="orientation" > <property name="orientation" >
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
<property name="sizeHint" > <property name="sizeHint" stdset="0" >
<size> <size>
<width>421</width> <width>421</width>
<height>20</height> <height>20</height>
@ -184,17 +127,7 @@
</property> </property>
</spacer> </spacer>
</item> </item>
<item row="1" column="0" colspan="9" > <item row="2" 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="2" column="0" colspan="9" >
<layout class="QHBoxLayout" > <layout class="QHBoxLayout" >
<item> <item>
<widget class="QLabel" name="textLabel1" > <widget class="QLabel" name="textLabel1" >
@ -251,10 +184,36 @@
</item> </item>
</layout> </layout>
</item> </item>
<item row="3" column="0" colspan="9" > <item row="3" column="0" colspan="7" >
<widget class="QDialogButtonBox" name="buttonBox" > <widget class="QDialogButtonBox" name="buttonBox" >
<property name="standardButtons" > <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> </property>
</widget> </widget>
</item> </item>
@ -274,9 +233,6 @@
<tabstop>mInvertSelectionButton</tabstop> <tabstop>mInvertSelectionButton</tabstop>
<tabstop>mCopySelectedRowsButton</tabstop> <tabstop>mCopySelectedRowsButton</tabstop>
<tabstop>mZoomMapToSelectedRowsButton</tabstop> <tabstop>mZoomMapToSelectedRowsButton</tabstop>
<tabstop>mAddAttributeButton</tabstop>
<tabstop>mDeleteAttributeButton</tabstop>
<tabstop>btnEdit</tabstop>
<tabstop>mSearchText</tabstop> <tabstop>mSearchText</tabstop>
<tabstop>mSearchColumns</tabstop> <tabstop>mSearchColumns</tabstop>
<tabstop>mSearchButton</tabstop> <tabstop>mSearchButton</tabstop>

View File

@ -213,6 +213,13 @@
</property> </property>
</widget> </widget>
</item> </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> </layout>
</widget> </widget>
</item> </item>
@ -223,8 +230,8 @@
</property> </property>
<property name="sizeHint" > <property name="sizeHint" >
<size> <size>
<width>547</width> <width>577</width>
<height>51</height> <height>21</height>
</size> </size>
</property> </property>
</spacer> </spacer>

View File

@ -5,8 +5,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>552</width> <width>839</width>
<height>600</height> <height>675</height>
</rect> </rect>
</property> </property>
<property name="minimumSize" > <property name="minimumSize" >
@ -19,21 +19,287 @@
<string>Layer Properties</string> <string>Layer Properties</string>
</property> </property>
<property name="windowIcon" > <property name="windowIcon" >
<iconset/> <iconset>
<normaloff/>
</iconset>
</property> </property>
<property name="modal" > <property name="modal" >
<bool>true</bool> <bool>true</bool>
</property> </property>
<layout class="QGridLayout" > <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" > <item row="0" column="0" >
<widget class="QTabWidget" name="tabWidget" > <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" > <property name="tabShape" >
<enum>QTabWidget::Rounded</enum> <enum>QTabWidget::Rounded</enum>
</property> </property>
<property name="currentIndex" > <property name="currentIndex" >
<number>0</number> <number>5</number>
</property> </property>
<widget class="QWidget" name="tab1" > <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" > <attribute name="title" >
<string>Symbology</string> <string>Symbology</string>
</attribute> </attribute>
@ -134,227 +400,44 @@
<property name="currentIndex" > <property name="currentIndex" >
<number>1</number> <number>1</number>
</property> </property>
<widget class="QWidget" name="page" /> <widget class="QWidget" name="page" >
<widget class="QWidget" name="page_2" /> <property name="geometry" >
</widget> <rect>
</item> <x>0</x>
</layout> <y>0</y>
</widget> <width>100</width>
<widget class="QWidget" name="tab2" > <height>30</height>
<attribute name="title" > </rect>
<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>
</property> </property>
<property name="topMargin" > </widget>
<number>11</number> <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>
<property name="rightMargin" > </widget>
<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> </item>
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="tab3" > <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" > <attribute name="title" >
<string>Metadata</string> <string>Metadata</string>
</attribute> </attribute>
<layout class="QGridLayout" > <layout class="QGridLayout" >
<property name="leftMargin" > <property name="margin" >
<number>11</number>
</property>
<property name="topMargin" >
<number>11</number>
</property>
<property name="rightMargin" >
<number>11</number>
</property>
<property name="bottomMargin" >
<number>11</number> <number>11</number>
</property> </property>
<item row="0" column="0" > <item row="0" column="0" >
@ -370,6 +453,14 @@
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="tab4" > <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" > <attribute name="title" >
<string>Labels</string> <string>Labels</string>
</attribute> </attribute>
@ -406,6 +497,14 @@
</layout> </layout>
</widget> </widget>
<widget class="QWidget" name="tab5" > <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" > <attribute name="title" >
<string>Actions</string> <string>Actions</string>
</attribute> </attribute>
@ -428,63 +527,118 @@
</item> </item>
</layout> </layout>
</widget> </widget>
</widget> <widget class="QWidget" name="tab6" >
</item> <property name="geometry" >
<item row="1" column="0" > <rect>
<layout class="QHBoxLayout" > <x>0</x>
<property name="spacing" > <y>0</y>
<number>3</number> <width>817</width>
</property> <height>557</height>
<property name="leftMargin" > </rect>
<number>1</number> </property>
</property> <attribute name="title" >
<property name="topMargin" > <string>Attributes</string>
<number>1</number> </attribute>
</property> <layout class="QVBoxLayout" name="verticalLayout" >
<property name="rightMargin" > <item>
<number>1</number> <layout class="QHBoxLayout" name="horizontalLayout" >
</property> <property name="sizeConstraint" >
<property name="bottomMargin" > <enum>QLayout::SetNoConstraint</enum>
<number>1</number> </property>
</property> <item>
<item> <widget class="QToolButton" name="mAddAttributeButton" >
<widget class="QPushButton" name="pbnLoadDefaultStyle" > <property name="sizePolicy" >
<property name="text" > <sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
<string>Restore Default Style</string> <horstretch>0</horstretch>
</property> <verstretch>0</verstretch>
</widget> </sizepolicy>
</item> </property>
<item> <property name="toolTip" >
<widget class="QPushButton" name="pbnSaveDefaultStyle" > <string>New column</string>
<property name="text" > </property>
<string>Save As Default</string> <property name="text" >
</property> <string/>
</widget> </property>
</item> <property name="icon" >
<item> <iconset>
<widget class="QPushButton" name="pbnLoadStyle" > <normaloff>../xpm/new_attribute.png</normaloff>../xpm/new_attribute.png</iconset>
<property name="text" > </property>
<string>Load Style ...</string> <property name="shortcut" >
</property> <string>Ctrl+N</string>
</widget> </property>
</item> </widget>
<item> </item>
<widget class="QPushButton" name="pbnSaveStyleAs" > <item>
<property name="text" > <widget class="QToolButton" name="mDeleteAttributeButton" >
<string>Save Style ...</string> <property name="toolTip" >
</property> <string>Delete column</string>
</widget> </property>
</item> <property name="text" >
</layout> <string/>
</item> </property>
<item row="3" column="0" > <property name="icon" >
<widget class="QDialogButtonBox" name="buttonBox" > <iconset>
<property name="orientation" > <normaloff>../xpm/delete_attribute.png</normaloff>../xpm/delete_attribute.png</iconset>
<enum>Qt::Horizontal</enum> </property>
</property> <property name="shortcut" >
<property name="standardButtons" > <string>Ctrl+X</string>
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set> </property>
</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> </widget>
</item> </item>
</layout> </layout>