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
QgsFeature(int id = 0, QString typeName = "" );
/** create a copy of this feature in its uncommitted state.
To do this, you also pass in a reference to the feature's
layer's uncommitted attribute and geometry changes.
The resulting feature will have those changes applied.
This is useful in the cut/copy routine, where you'd
want a copy of the "current" feature, not the on-disk feature.
*/
QgsFeature( const QgsFeature & rhs,
const QMap<int, QMap<int, QVariant> >& changedAttributes,
const QMap<int, QgsGeometry> & changedGeometries );
/** copy ctor needed due to internal pointer */
QgsFeature(const QgsFeature & rhs );

View File

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

View File

@ -1,12 +1,27 @@
class QgsVectorLayer : QgsMapLayer
{
%TypeHeaderCode
#include <qgsvectorlayer.h>
#include "qgsvectorlayer.h"
%End
public:
enum EditType {
LineEdit,
UniqueValues,
UniqueValuesEditable,
ValueMap,
Classification,
Range,
};
struct RangeData {
RangeData();
RangeData(QVariant theMin, QVariant theMax, QVariant theStep);
QVariant mMin;
QVariant mMax;
QVariant mStep;
};
/** Constructor */
QgsVectorLayer(QString baseName = 0, QString path = 0, QString providerLib = 0);
@ -66,10 +81,6 @@ public:
/** Returns the bounding box of the selected features. If there is no selection, QgsRect(0,0,0,0) is returned */
QgsRect boundingBoxOfSelected();
/** Insert a copy of the given features into the layer */
bool addFeatures(QList<QgsFeature> features, bool makeSelected = TRUE);
/** Copies the symbology settings from another layer. Returns true in case of success */
bool copySymbologySettings(const QgsMapLayer& other);
@ -92,12 +103,12 @@ public:
QString providerType() const;
/** reads vector layer specific state from project file DOM node.
* @note Called by QgsMapLayer::readXML().
* @note Called by QgsMapLayer::readXml().
*/
virtual bool readXml( QDomNode & layer_node );
/** write vector layer specific state to project file DOM node.
* @note Called by QgsMapLayer::writeXML().
* @note Called by QgsMapLayer::writeXml().
*/
virtual bool writeXml( QDomNode & layer_node, QDomDocument & doc );
@ -130,17 +141,20 @@ public:
*/
virtual QString subsetString();
/**Returns the features contained in the rectangle. Considers the changed, added, deleted and permanent features
@return 0 in case of success*/
int featuresInRectangle(const QgsRect& searchRect, QList<QgsFeature>& features /Out/, bool fetchGeometries = true, bool fetchAttributes = true);
void select(QList<int> fetchAttributes = QList<int>(),
QgsRect rect = QgsRect(),
bool fetchGeometry = true);
/**Gets the feature at the given feature id. Considers the changed, added, deleted and permanent features
bool getNextFeature(QgsFeature& feature);
/**Gets the feature at the given feature id. Considers the changed, added, deleted and permanent features
@return 0 in case of success*/
int getFeatureAtId(int featureId, QgsFeature& f, bool fetchGeometries = true, bool fetchAttributes = true);
int getFeatureAtId(int featureId, QgsFeature& f, bool fetchGeometries = true, bool fetchAttributes = true);
/** Adds a feature
@param lastFeatureInBatch If True, will also go to the effort of e.g. updating the extents.
@return Irue in case of success and False in case of error
@param alsoUpdateExtent If True, will also go to the effort of e.g. updating the extents.
@return True in case of success and False in case of error
*/
bool addFeature(QgsFeature& f, bool alsoUpdateExtent = TRUE);
@ -168,49 +182,60 @@ public:
bool deleteSelectedFeatures();
/**Adds a ring to polygon/multipolygon features
@return 0 in case of success, 1 problem with feature type, 2 ring not closed, 3 ring not valid, 4 ring crosses \
existing rings, 5 no feature found where ring can be inserted*/
@return
0 in case of success,
1 problem with feature type,
2 ring not closed,
3 ring not valid,
4 ring crosses existing rings,
5 no feature found where ring can be inserted*/
int addRing(const QList<QgsPoint>& ring);
/**Adds a new island polygon to a multipolygon feature
@return 0 in case of success, 1 if selected feature is not multipolygon, 2 if ring is not a valid geometry, \
3 if new polygon ring not disjoint with existing rings, 4 if no feature was selected, 5 if several features are selected, \
6 if selected geometry not found*/
@return
0 in case of success,
1 if selected feature is not multipolygon,
2 if ring is not a valid geometry,
3 if new polygon ring not disjoint with existing rings,
4 if no feature was selected,
5 if several features are selected,
6 if selected geometry not found*/
int addIsland(const QList<QgsPoint>& ring);
/**Translates feature by dx, dy
/**Translates feature by dx, dy
@param featureId id of the feature to translate
@param dx translation of x-coordinate
@param dy translation of y-coordinate
@return 0 in case of success*/
int translateFeature(int featureId, double dx, double dy);
/**Splits features cut by the given line
/**Splits features cut by the given line
@param splitLine line that splits the layer features
@param topologicalEditing true if topological editing is enabled
@return 0 in case of success, 1 if several intersections but only 1 split done, \
2 if intersection too complex to be handled, else other error*/
@return
0 in case of success,
1 if several intersections but only 1 split done,
2 if intersection too complex to be handled, else other error*/
int splitFeatures(const QList<QgsPoint>& splitLine, bool topologicalEditing = false);
/**Changes the specified geometry such that it has no intersections with other \
/**Changes the specified geometry such that it has no intersections with other \
polygon (or multipolygon) geometries in this vector layer
@param geom geometry to modify
@return 0 in case of success*/
@param geom geometry to modify
@return 0 in case of success*/
int removePolygonIntersections(QgsGeometry* geom);
/**Adds topological points for every vertex of the
geometry
@param geom the geometry where each vertex is added to segments of other features
Note: geom is not going to be modified by the function
@return 0 in case of success*/
/**Adds topological points for every vertex of the geometry
@param geom the geometry where each vertex is added to segments of other features
Note: geom is not going to be modified by the function
@return 0 in case of success*/
int addTopologicalPoints(QgsGeometry* geom);
/**Adds a vertex to segments which intersect point p but don't
already have a vertex there. If a feature already has a vertex at position p,
no additional vertex is inserted. This method is usefull for topological
editing.
@param p position of the vertex
@return 0 in case of success*/
/**Adds a vertex to segments which intersect point p but don't
already have a vertex there. If a feature already has a vertex at position p,
no additional vertex is inserted. This method is usefull for topological
editing.
@param p position of the vertex
@return 0 in case of success*/
int addTopologicalPoints(const QgsPoint& p);
/**Inserts vertices to the snapped segments.
@ -246,29 +271,7 @@ existing rings, 5 no feature found where ring can be inserted*/
@return 0 in case of success
*/
int snapWithContext(const QgsPoint& startPoint, double snappingTolerance, QMultiMap<double, QgsSnappingResult>& snappingResults /Out/,
QgsSnapper::SNAP_TO snap_to);
/**
Commits edited attributes. Depending on the feature id,
the changes are written to not commited features or redirected to
the data provider
The commits (in this version) occur in three distinct stages,
(delete attributes, add attributes, change attribute values)
so if a stage fails, it's difficult to roll back cleanly.
\todo Need to indicate at which stage the failed commit occurred,
for better cleanup and recovery from the error.
\param deleted Set of attribute indices (i.e. columns) to delete
\param added Map (name, type) of attribute names (i.e. columns) to add
\param changed Map (feature ID, Map (attribute name, new value) )
of attribute values to change
*/
bool commitAttributeChanges(const QSet<int>& deleted,
const QMap<QString, QString>& added,
const QMap<int, QMap<int, QVariant> >& changed);
QgsSnapper::SNAP_TO snap_to);
/** Draws the layer using coordinate transformation
* @return FALSE if an error occurred during drawing
@ -283,20 +286,36 @@ existing rings, 5 no feature found where ring can be inserted*/
*/
void drawLabels(QPainter * p, const QgsRect& viewExtent, const QgsMapToPixel* cXf, const QgsCoordinateTransform* ct, double scale);
/** returns array of added features */
QList<QgsFeature>& addedFeatures();
/** returns list of attributes */
QList<int> pendingAllAttributesList();
/** returns array of deleted feature IDs */
QSet<int>& deletedFeatureIds();
/** returns array of features with changed attributes */
QMap<int, QMap<int, QVariant> >& changedAttributes();
/** returns fields list which are not commited */
const QMap<int, QgsField> &pendingFields();
/** returns feature count after commit */
int pendingFeatureCount();
/** Sets whether some features are modified or not */
void setModified(bool modified = TRUE, bool onlyGeometryWasModified = FALSE);
/** Make layer editable */
bool startEditing();
/** changed an attribute value (but does not commit it */
bool changeAttributeValue(int fid, int field, QVariant value, bool emitSignal = true);
/** add an attribute field (but does not commit it)
returns the field index or -1 in case of failure */
bool addAttribute(QString name, QString type);
/** delete an attribute field (but does not commit it) */
bool deleteAttribute(int attr);
/** Insert a copy of the given features into the layer (but does not commit it) */
bool addFeatures(QList<QgsFeature> features, bool makeSelected = TRUE);
/** delete a feature from the layer (but does not commit it) */
bool deleteFeature(int fid);
/**
Attempts to commit any changes to disk. Returns the result of the attempt.
@ -314,10 +333,23 @@ existing rings, 5 no feature found where ring can be inserted*/
*/
bool commitChanges();
const QStringList &commitErrors();
/** Stop editing and discard the edits */
bool rollBack();
/**get edit type*/
EditType editType(int idx);
/**set edit type*/
void setEditType(int idx, EditType edit);
/**access value map*/
QMap<QString, QVariant> &valueMap(int idx);
/**access range */
RangeData &range(int idx);
public slots:
/** Select feature by its ID, optionally emit signal selectionChanged() */
@ -341,6 +373,15 @@ signals:
/** This signal is emitted when modifications has been done on layer */
void wasModified(bool onlyGeometry);
void editingStarted();
void editingStopped();
void attributeAdded(int idx);
void attributeDeleted(int idx);
void featureDeleted(int fid);
void layerDeleted();
void attributeValueChanged(int fid, int idx, const QVariant &);
private: // Private methods
/** vector layers are not copyable */

View File

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

View File

@ -43,7 +43,7 @@
QgsLegendLayerFile::QgsLegendLayerFile(QTreeWidgetItem * theLegendItem, QString theString, QgsMapLayer* theLayer)
: QgsLegendItem(theLegendItem, theString), mLyr(theLayer), mTableDisplay(NULL)
: QgsLegendItem(theLegendItem, theString), mLyr(theLayer)
{
// Set the initial visibility flag for layers
// This user option allows the user to turn off inital drawing of
@ -69,23 +69,12 @@ QgsLegendLayerFile::QgsLegendLayerFile(QTreeWidgetItem * theLegendItem, QString
QgsVectorLayer *isVectLyr = dynamic_cast < QgsVectorLayer * >(currentLayer);
if (isVectLyr)
{
// get notifications of changed selection - used to update attribute table
connect(mLyr.layer(), SIGNAL(selectionChanged()), this, SLOT(selectionChanged()));
// get notifications of modified layer - used to close table as it's out of sync
connect(mLyr.layer(), SIGNAL(wasModified(bool)), this, SLOT(closeTable(bool)));
connect(mLyr.layer(), SIGNAL(editingStarted()), this, SLOT(updateLegendItem()));
connect(mLyr.layer(), SIGNAL(editingStopped()), this, SLOT(updateLegendItem()));
}
connect(mLyr.layer(), SIGNAL(layerNameChanged()), this, SLOT(layerNameChanged()));
}
QgsLegendLayerFile::~QgsLegendLayerFile()
{
if (mTableDisplay)
{
mTableDisplay->close();
delete mTableDisplay;
}
}
QgsLegendItem::DRAG_ACTION QgsLegendLayerFile::accept(LEGEND_ITEM_TYPE type)
{
return NO_ACTION;
@ -219,112 +208,16 @@ void QgsLegendLayerFile::showInOverview()
legend()->updateOverview();
}
void QgsLegendLayerFile::table()
{
QgsVectorLayer* vlayer = dynamic_cast<QgsVectorLayer*>(mLyr.layer());
if (!vlayer)
{
QMessageBox::information(0, tr("Not a vector layer"),
tr("To open an attribute table, you must select a vector layer in the legend"));
return;
}
QgsAttributeAction& actions = *vlayer->actions();
if (mTableDisplay)
{
mTableDisplay->raise();
// Give the table the most recent copy of the actions for this layer.
mTableDisplay->table()->setAttributeActions(actions);
}
else
{
// display the attribute table
QApplication::setOverrideCursor(Qt::WaitCursor);
// TODO: pointer to QgisApp should be passed instead of NULL
// but we don't have pointer to it. [MD]
// but be can get it using this ugly hack. [jef]
// TODO: do this cleanly
QgisApp *app = NULL;
QList<QWidget *> list = QApplication::topLevelWidgets();
int i;
for(i=0; i<list.size(); i++)
if( list[i]->windowTitle().startsWith("Quantum GIS") )
{
app=reinterpret_cast<QgisApp*>(list[i]);
break;
}
mTableDisplay = new QgsAttributeTableDisplay(vlayer, app);
try
{
mTableDisplay->table()->fillTable(vlayer);
}
catch(std::bad_alloc& ba)
{
Q_UNUSED(ba);
QMessageBox::critical(0, tr("bad_alloc exception"), tr("Filling the attribute table has been stopped because there was no more virtual memory left"));
}
connect(mTableDisplay, SIGNAL(deleted()), this, SLOT(invalidateTableDisplay()));
mTableDisplay->setTitle(tr("Attribute table - ") + vlayer->name());
mTableDisplay->show();
// Give the table the most recent copy of the actions for this layer.
mTableDisplay->table()->setAttributeActions(actions);
// select rows which should be selected
selectionChanged();
// etablish the necessary connections between the table and the vector layer
connect(mTableDisplay->table(), SIGNAL(selected(int, bool)), mLyr.layer(), SLOT(select(int, bool)));
connect(mTableDisplay->table(), SIGNAL(selectionRemoved(bool)), mLyr.layer(), SLOT(removeSelection(bool)));
connect(mTableDisplay->table(), SIGNAL(repaintRequested()), mLyr.layer(), SLOT(triggerRepaint()));
QApplication::restoreOverrideCursor();
}
}
void QgsLegendLayerFile::invalidateTableDisplay()
{
// from signal deleted() - table doesn't exist anymore, just erase our pointer
mTableDisplay = 0;
}
void QgsLegendLayerFile::selectionChanged()
{
if (!mTableDisplay)
return;
QgsVectorLayer* vlayer = dynamic_cast<QgsVectorLayer*>(mLyr.layer());
const QgsFeatureIds& ids = vlayer->selectedFeaturesIds();
mTableDisplay->table()->selectRowsWithId(ids);
}
void QgsLegendLayerFile::closeTable(bool onlyGeometryWasChanged)
{
if (mTableDisplay)
{
mTableDisplay->close();
delete mTableDisplay;
mTableDisplay = NULL;
}
}
void QgsLegendLayerFile::saveAsShapefile()
{
saveAsShapefileGeneral(FALSE);
}
void QgsLegendLayerFile::table()
{
QgsAttributeTableDisplay::attributeTable( dynamic_cast<QgsVectorLayer*>(mLyr.layer()) );
}
void QgsLegendLayerFile::saveSelectionAsShapefile()
{
saveAsShapefileGeneral(TRUE);
@ -413,69 +306,6 @@ void QgsLegendLayerFile::saveAsShapefileGeneral(bool saveOnlySelection)
}
}
void QgsLegendLayerFile::toggleEditing()
{
QgsVectorLayer* vlayer = dynamic_cast<QgsVectorLayer*>(mLyr.layer());
if (!vlayer)
return;
if (!vlayer->isEditable())
{
vlayer->startEditing();
if(!(vlayer->getDataProvider()->capabilities() & QgsVectorDataProvider::AddFeatures))
{
QMessageBox::information(0,tr("Start editing failed"),
tr("Provider cannot be opened for editing"));
}
else
{
vlayer->triggerRepaint();
}
}
else
{
if(vlayer->isModified())
{
// commit or roll back?
QMessageBox::StandardButton commit = QMessageBox::information(0,tr("Stop editing"), tr("Do you want to save the changes?"), QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
if(commit==QMessageBox::Save)
{
if(!vlayer->commitChanges())
{
QMessageBox::information(0,tr("Error"),tr("Could not commit changes"));
// Leave the in-memory editing state alone,
// to give the user a chance to enter different values
// and try the commit again later
}
}
else if(commit==QMessageBox::Discard)
{
if(!vlayer->rollBack())
{
QMessageBox::information(0,tr("Error"),
tr("Problems during roll back"));
}
}
else //cancel
{
return;
}
}
else //layer not modified
{
vlayer->rollBack();
}
vlayer->triggerRepaint();
}
updateLegendItem();
}
bool QgsLegendLayerFile::isEditing()
{
QgsVectorLayer* vlayer = dynamic_cast<QgsVectorLayer*>(mLyr.layer());
@ -491,7 +321,6 @@ void QgsLegendLayerFile::layerNameChanged()
legend()->setName(this, name);
}
void QgsLegendLayerFile::addToPopupMenu(QMenu& theMenu, QAction* toggleEditingAction)
{
QgsMapLayer* lyr = layer();
@ -526,9 +355,9 @@ void QgsLegendLayerFile::addToPopupMenu(QMenu& theMenu, QAction* toggleEditingAc
||(cap & QgsVectorDataProvider::DeleteFeatures))
{
if(toggleEditingAction)
{
theMenu.addAction(toggleEditingAction);
}
{
theMenu.addAction(toggleEditingAction);
}
}
// save as shapefile

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

@ -31,8 +31,11 @@
#include <QLabel>
#include <QFrame>
#include <QScrollArea>
#include <QCompleter>
#include <QSpinBox>
#include <QDoubleSpinBox>
QgsAttributeDialog::QgsAttributeDialog(QgsVectorLayer *vl, QgsFeature * thepFeature)
QgsAttributeDialog::QgsAttributeDialog(QgsVectorLayer *vl, QgsFeature *thepFeature)
: QDialog(),
mSettingsPath("/Windows/AttributeDialog/"),
mpFeature(thepFeature),
@ -67,7 +70,7 @@ QgsAttributeDialog::QgsAttributeDialog(QgsVectorLayer *vl, QgsFeature * thepFeat
int classificationField = -1;
QStringList values;
QMap<QString,QString> classes;
const QgsUniqueValueRenderer *uvr = dynamic_cast<const QgsUniqueValueRenderer *>( mLayer->renderer() );
if( uvr )
@ -78,7 +81,13 @@ QgsAttributeDialog::QgsAttributeDialog(QgsVectorLayer *vl, QgsFeature * thepFeat
for(int i=0; i<symbols.size(); i++)
{
values.append( symbols[i]->lowerValue() );
QString label = symbols[i]->label();
QString name = symbols[i]->lowerValue();
if(label=="")
label=name;
classes.insert(name, label);
}
}
@ -87,49 +96,135 @@ QgsAttributeDialog::QgsAttributeDialog(QgsVectorLayer *vl, QgsFeature * thepFeat
it != myAttributes.end();
++it)
{
QString myFieldName = theFieldMap[it.key()].name();
int myFieldType = theFieldMap[it.key()].type();
const QgsField &field = theFieldMap[it.key()];
QString myFieldName = field.name();
int myFieldType = field.type();
QLabel * mypLabel = new QLabel();
mypInnerLayout->addWidget(mypLabel,index,0);
QVariant myFieldValue = it.value();
QWidget *myWidget;
if(classificationField!=it.key())
QgsVectorLayer::EditType editType = vl->editType( it.key() );
switch( editType )
{
QLineEdit *le = new QLineEdit();
//the provider may have provided a default value so use it
le->setText(myFieldValue.toString());
if( myFieldType==QVariant::Int )
case QgsVectorLayer::Range:
{
le->setValidator( new QIntValidator(le) );
if( myFieldType==QVariant::Int )
{
int min = vl->range( it.key() ).mMin.toInt();
int max = vl->range( it.key() ).mMax.toInt();
int step = vl->range( it.key() ).mStep.toInt();
QSpinBox *sb = new QSpinBox();
sb->setMinimum(min);
sb->setMaximum(max);
sb->setSingleStep(step);
sb->setValue( it.value().toInt() );
myWidget = sb;
break;
} else if( myFieldType==QVariant::Double ) {
double min = vl->range( it.key() ).mMin.toDouble();
double max = vl->range( it.key() ).mMax.toDouble();
double step = vl->range( it.key() ).mStep.toDouble();
QDoubleSpinBox *dsb = new QDoubleSpinBox();
dsb->setMinimum(min);
dsb->setMaximum(max);
dsb->setSingleStep(step);
dsb->setValue( it.value().toDouble() );
myWidget = dsb;
break;
}
}
else if( myFieldType==QVariant::Double )
// fall-through
case QgsVectorLayer::LineEdit:
case QgsVectorLayer::UniqueValuesEditable:
{
le->setValidator( new QIntValidator(le) );
QLineEdit *le = new QLineEdit( myFieldValue.toString() );
if( editType == QgsVectorLayer::UniqueValuesEditable )
{
QStringList values;
mLayer->getDataProvider()->getUniqueValues(it.key(), values);
QCompleter *c = new QCompleter(values);
c->setCompletionMode(QCompleter::PopupCompletion);
le->setCompleter(c);
}
if( myFieldType==QVariant::Int )
{
le->setValidator( new QIntValidator(le) );
}
else if( myFieldType==QVariant::Double )
{
le->setValidator( new QIntValidator(le) );
}
myWidget = le;
}
break;
myWidget = le;
}
else
{
QComboBox *cb = new QComboBox();
cb->addItems(values);
cb->setEditable(true);
//the provider may have provided a default value so use it
cb->setEditText(myFieldValue.toString());
if( myFieldType==QVariant::Int ) {
cb->setValidator( new QIntValidator(cb) );
}
else if( myFieldType==QVariant::Double )
case QgsVectorLayer::UniqueValues:
{
cb->setValidator( new QIntValidator(cb) );
}
QStringList values;
mLayer->getDataProvider()->getUniqueValues(it.key(), values);
myWidget = cb;
QComboBox *cb = new QComboBox();
cb->setEditable(true);
cb->addItems(values);
int idx = cb->findText( myFieldValue.toString() );
if( idx>= 0 )
cb->setCurrentIndex( idx );
myWidget = cb;
}
break;
case QgsVectorLayer::ValueMap:
{
const QMap<QString,QVariant> &map = vl->valueMap( it.key() );
QComboBox *cb = new QComboBox();
for(QMap<QString,QVariant>::const_iterator it=map.begin(); it!=map.end(); it++)
{
cb->addItem( it.key(), it.value() );
}
int idx = cb->findData( myFieldValue );
if( idx>= 0 )
cb->setCurrentIndex( idx );
myWidget = cb;
}
break;
case QgsVectorLayer::Classification:
{
QComboBox *cb = new QComboBox();
for(QMap<QString,QString>::const_iterator it=classes.begin(); it!=classes.end(); it++)
{
cb->addItem( it.value(), it.key() );
}
int idx = cb->findData( myFieldValue );
if( idx>=0 )
cb->setCurrentIndex( idx );
myWidget = cb;
}
break;
}
if( myFieldType==QVariant::Int )
@ -168,10 +263,9 @@ void QgsAttributeDialog::accept()
it != myAttributes.end();
++it)
{
const QgsFieldMap &theFieldMap = mLayer->getDataProvider()->fields();
//Q_ASSERT(myIndex <= mpWidgets.size());
QString myFieldName = theFieldMap[it.key()].name();
const QgsField &theField = mLayer->pendingFields()[it.key()];
QgsVectorLayer::EditType editType = mLayer->editType( it.key() );
QString myFieldName = theField.name();
bool myFlag=false;
QString myFieldValue;
@ -184,40 +278,62 @@ void QgsAttributeDialog::accept()
QComboBox *cb = dynamic_cast<QComboBox *>(mpWidgets.value(myIndex));
if(cb)
{
myFieldValue = cb->currentText();
if( editType==QgsVectorLayer::UniqueValues ||
editType==QgsVectorLayer::ValueMap ||
editType==QgsVectorLayer::Classification)
{
myFieldValue = cb->itemData( cb->currentIndex() ).toString();
}
else
{
myFieldValue = cb->currentText();
}
}
switch( theFieldMap[it.key()].type() )
QSpinBox *sb = dynamic_cast<QSpinBox *>(mpWidgets.value(myIndex));
if(sb)
{
case QVariant::Int:
myFieldValue = QString::number(sb->value());
}
QDoubleSpinBox *dsb = dynamic_cast<QDoubleSpinBox *>(mpWidgets.value(myIndex));
if(dsb)
{
myFieldValue = QString::number(dsb->value());
}
switch( theField.type() )
{
case QVariant::Int:
{
int myIntValue = myFieldValue.toInt(&myFlag);
if (myFlag && ! myFieldValue.isEmpty())
{
int myIntValue = myFieldValue.toInt(&myFlag);
if (myFlag && ! myFieldValue.isEmpty())
{
mpFeature->changeAttribute( it.key(), QVariant(myIntValue) );
}
else
{
mpFeature->changeAttribute( it.key(), QVariant(QString::null) );
}
mpFeature->changeAttribute( it.key(), QVariant(myIntValue) );
}
break;
case QVariant::Double:
else
{
double myDblValue = myFieldValue.toDouble(&myFlag);
if (myFlag && ! myFieldValue.isEmpty())
{
mpFeature->changeAttribute( it.key(), QVariant(myDblValue) );
}
else
{
mpFeature->changeAttribute( it.key(), QVariant(QString::null) );
}
mpFeature->changeAttribute( it.key(), QVariant(QString::null) );
}
break;
default: //string
mpFeature->changeAttribute(it.key(),QVariant( myFieldValue ) );
break;
}
break;
case QVariant::Double:
{
double myDblValue = myFieldValue.toDouble(&myFlag);
if (myFlag && ! myFieldValue.isEmpty())
{
mpFeature->changeAttribute( it.key(), QVariant(myDblValue) );
}
else
{
mpFeature->changeAttribute( it.key(), QVariant(QString::null) );
}
}
break;
default: //string
mpFeature->changeAttribute(it.key(),QVariant( myFieldValue ) );
break;
}
++myIndex;
}
@ -235,4 +351,3 @@ void QgsAttributeDialog::restoreGeometry()
QSettings settings;
QDialog::restoreGeometry(settings.value(mSettingsPath+"geometry").toByteArray());
}

View File

@ -20,7 +20,6 @@
#include <QValidator>
#include "qgsattributetable.h"
#include "qgsfeature.h"
#include "qgsfield.h"
#include "qgslogger.h"
#include "qgsvectordataprovider.h"
@ -33,31 +32,44 @@
#include <QMenu>
QgsAttributeTableItemDelegate::QgsAttributeTableItemDelegate(const QgsFieldMap & fields, QObject *parent)
: QItemDelegate(parent), mFields(fields)
{}
QgsAttributeTableItemDelegate::QgsAttributeTableItemDelegate(QgsAttributeTable *table, QObject *parent)
: mTable(table), QItemDelegate(parent)
{
}
QWidget * QgsAttributeTableItemDelegate::createEditor( QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index ) const
QWidget *QgsAttributeTableItemDelegate::createEditor(
QWidget *parent,
const QStyleOptionViewItem &option,
const QModelIndex &index ) const
{
QWidget *editor = QItemDelegate::createEditor(parent, option, index);
QLineEdit *le = dynamic_cast<QLineEdit*>(editor);
if (le)
if (!le)
return editor;
int col = index.column();
QTableWidgetItem *twi = mTable->horizontalHeaderItem(col);
if(!twi)
{
int col = index.column();
if( mFields[col-1].type()==QVariant::Int )
{
le->setValidator( new QIntValidator(le) );
}
else if( mFields[col-1].type()==QVariant::Double )
{
le->setValidator( new QDoubleValidator(le) );
}
QgsDebugMsg( QString("horizontalHeaderItem %1 not found").arg(col) );
return editor;
}
int type = twi->data(QgsAttributeTable::AttributeType).toInt();
if( type==QVariant::Int )
{
le->setValidator( new QIntValidator(le) );
}
else if( type==QVariant::Double )
{
le->setValidator( new QDoubleValidator(le) );
}
return editor;
}
QgsAttributeTable::QgsAttributeTable(QWidget * parent):
QgsAttributeTable::QgsAttributeTable(QWidget * parent) :
QTableWidget(parent),
lockKeyPressed(false),
mEditable(false),
@ -69,14 +81,12 @@ QgsAttributeTable::QgsAttributeTable(QWidget * parent):
f.setFamily("Helvetica");
f.setPointSize(9);
setFont(f);
mDelegate = new QgsAttributeTableItemDelegate(mFields, this);
mDelegate = new QgsAttributeTableItemDelegate(this);
setItemDelegate(mDelegate);
setSelectionBehavior(QAbstractItemView::SelectRows);
connect(this, SIGNAL(itemSelectionChanged()), this, SLOT(handleChangedSelections()));
connect(this, SIGNAL(cellChanged(int, int)), this, SLOT(storeChangedValue(int,int)));
connect(horizontalHeader(), SIGNAL(sectionClicked(int)), this, SLOT(columnClicked(int)));
connect(verticalHeader(), SIGNAL(sectionClicked(int)), this, SLOT(rowClicked(int)));
setReadOnly(true);
setFocus();
}
@ -90,14 +100,17 @@ void QgsAttributeTable::setReadOnly(bool b)
{
setEditTriggers(b ? QAbstractItemView::NoEditTriggers :
QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed);
if(!b) {
setColumnReadOnly(0, true);
}
}
void QgsAttributeTable::setColumnReadOnly(int col, bool ro)
{
for (int i = 0; i < rowCount(); ++i)
{
QTableWidgetItem *item = this->item(i, col);
item->setFlags(ro ? item->flags() & ~Qt::ItemIsEditable : item->flags() | Qt::ItemIsEditable);
QTableWidgetItem *twi = item(i, col);
twi->setFlags(ro ? twi->flags() & ~Qt::ItemIsEditable : twi->flags() | Qt::ItemIsEditable);
}
}
@ -173,16 +186,16 @@ void QgsAttributeTable::keyReleaseEvent(QKeyEvent * ev)
void QgsAttributeTable::handleChangedSelections()
{
emit selectionRemoved(false);
emit selectionRemoved(false);
QList<QTableWidgetSelectionRange> selectedItemRanges = selectedRanges();
QList<QTableWidgetSelectionRange>::const_iterator range_it = selectedItemRanges.constBegin();
for (; range_it != selectedItemRanges.constEnd(); ++range_it)
{
for (int index = range_it->topRow(); index <= range_it->bottomRow(); index++)
{
emit selected(item(index, 0)->text().toInt(), false);
}
{
emit selected(item(index, 0)->text().toInt(), false);
}
}
//don't send the signal repaintRequested() from here
@ -203,19 +216,8 @@ void QgsAttributeTable::selectRowWithId(int id)
void QgsAttributeTable::sortColumn(int col, bool ascending)
{
//if the first entry contains a letter, sort alphanumerically, otherwise numerically
QString firstentry = item(0, col)->text();
bool containsletter = false;
for (int i = 0; i < firstentry.length(); i++)
{
if (firstentry[i].isLetter())
{
containsletter = true;
break;
}
}
qsort(0, rowCount() - 1, col, ascending, containsletter);
int type = horizontalHeaderItem(col)->data(QgsAttributeTable::AttributeType).toInt();
qsort(0, rowCount() - 1, col, ascending, type!=QVariant::Int && type==QVariant::Double);
}
@ -302,7 +304,8 @@ void QgsAttributeTable::qsort(int lower, int upper, int col, bool ascending, boo
j = upper;
for (;;)
{
while (compareItems(item(++i, col)->text(), v, ascending, alphanumeric) == -1);
while (compareItems(item(++i, col)->text(), v, ascending, alphanumeric) == -1)
;
while (compareItems(item(--j, col)->text(), v, ascending, alphanumeric) == 1 && j > 0); //make sure that j does not get negative
if (i >= j)
{
@ -381,45 +384,6 @@ void QgsAttributeTable::popupItemSelected(QAction* menuAction)
mActions.doAction(id, mActionValues, mClickedOnValue);
}
bool QgsAttributeTable::addAttribute(const QString& name, const QString& type)
{
//first test if an attribute with the same name is already in the table
for(int i=0;i<columnCount();++i)
{
if(horizontalHeaderItem(i)->text()==name)
{
//name conflict
return false;
}
}
mAddedAttributes.insert(name,type);
QgsDebugMsg("inserting attribute " + name + " of type " + type + ", numCols: " + QString::number(columnCount()) );
//add a new column at the end of the table
insertColumn(columnCount());
setHorizontalHeaderItem(columnCount()-1, new QTableWidgetItem(name));
mEdited=true;
return true;
}
void QgsAttributeTable::deleteAttribute(const QString& name)
{
//check, if there is already an attribute with this name in mAddedAttributes
QgsNewAttributesMap::iterator iter = mAddedAttributes.find(name);
if(iter!=mAddedAttributes.end())
{
mAddedAttributes.erase(iter);
removeAttrColumn(name);
}
else
{
mDeletedAttributes.insert(name);
removeAttrColumn(name);
}
mEdited=true;
}
/* Deprecated: See QgisApp::editCopy() instead */
void QgsAttributeTable::copySelectedRows()
{
@ -463,157 +427,60 @@ void QgsAttributeTable::copySelectedRows()
clipboard->setText(toClipboard, QClipboard::Clipboard);
}
bool QgsAttributeTable::commitChanges(QgsVectorLayer* layer)
void QgsAttributeTable::fillTable(QgsVectorLayer *layer)
{
bool isSuccessful = false;
int row = 0;
if(layer)
const QgsFieldMap &fields = layer->pendingFields();
// set up the column headers
setColumnCount(fields.size()+1);
setHorizontalHeaderItem(0, new QTableWidgetItem("id")); //label for the id-column
int h = 1;
for (QgsFieldMap::const_iterator fldIt = fields.begin(); fldIt!=fields.end(); fldIt++, h++)
{
//convert strings of deleted attributes to ids
QgsDebugMsg( QString("%1: field %2: %3 | %4")
.arg(h).arg(fldIt.key()).arg(fldIt->name()).arg( QVariant::typeToName(fldIt->type()) ) );
QgsVectorDataProvider* provider = layer->getDataProvider();
QTableWidgetItem *twi = new QTableWidgetItem(fldIt->name());
twi->setData( AttributeIndex, fldIt.key() );
twi->setData( AttributeName, fldIt->name() );
twi->setData( AttributeType, fldIt->type() );
setHorizontalHeaderItem(h, twi);
if(provider)
{
QgsAttributeIds deletedIds;
QSet<QString>::const_iterator it = mDeletedAttributes.constBegin();
for(; it != mDeletedAttributes.constEnd(); ++it)
{
deletedIds.insert(provider->indexFromFieldName(*it));
}
isSuccessful = true;
if( !mAddedAttributes.empty() )
{
// add new attributes beforehand, so attribute changes can be applied
isSuccessful = layer->commitAttributeChanges(QgsAttributeIds(), mAddedAttributes, QgsChangedAttributesMap());
if(isSuccessful)
// forget added attributes on successful addition
mAddedAttributes.clear();
}
if(isSuccessful)
{
QgsChangedAttributesMap attributeChanges; //convert mChangedValues to QgsChangedAttributesMap
int fieldIndex;
QMap<int, QMap<QString, QString> >::const_iterator att_it = mChangedValues.constBegin();
for(; att_it != mChangedValues.constEnd(); ++att_it)
{
QgsAttributeMap newAttMap;
QMap<QString, QString>::const_iterator record_it = att_it->constBegin();
for(; record_it != att_it->constEnd(); ++record_it)
{
fieldIndex = provider->indexFromFieldName(record_it.key());
if(fieldIndex != -1)
{
if( record_it.value()=="NULL" ||
( record_it.value().isEmpty() &&
(provider->fields()[fieldIndex].type()==QVariant::Int ||
provider->fields()[fieldIndex].type()==QVariant::Double) ) )
newAttMap.insert(fieldIndex, QVariant(QString::null) );
else
newAttMap.insert(fieldIndex, record_it.value());
}
else
{
QgsDebugMsg("Changed attribute " + record_it.key() + " not found");
}
}
attributeChanges.insert(att_it.key(), newAttMap);
}
isSuccessful = layer->commitAttributeChanges(deletedIds,
QgsNewAttributesMap(),
attributeChanges);
}
}
mAttrIdxMap.insert(fldIt.key(), h);
}
if (isSuccessful)
QgsFeatureList features;
if( layer->selectedFeatureCount()==0 )
{
mEdited=false;
clearEditingStructures();
layer->select(layer->pendingAllAttributesList(), QgsRect(), false);
QgsFeature f;
while( layer->getNextFeature(f) )
features << f;
}
else
{
features = layer->selectedFeatures();
}
return isSuccessful;
}
bool QgsAttributeTable::rollBack(QgsVectorLayer* layer)
{
if(layer)
{
fillTable(layer);
}
mEdited=false;
clearEditingStructures();
return true;
}
void QgsAttributeTable::fillTable(QgsVectorLayer* layer)
{
QgsVectorDataProvider* provider=layer->getDataProvider();
if(provider)
{
QgsFeature fet;
int row = 0;
QgsFeatureList& addedFeatures = layer->addedFeatures();
QgsFeatureIds& deletedFeatures = layer->deletedFeatureIds();
// set up the column headers
mFields = provider->fields();
int fieldcount=provider->fieldCount();
setRowCount( features.size() );
setRowCount(provider->featureCount() + addedFeatures.size() - deletedFeatures.size());
setColumnCount(fieldcount+1);
setHorizontalHeaderItem(0, new QTableWidgetItem("id")); //label for the id-column
for(int i=0; i<features.size(); i++)
putFeatureInTable(i, features[i]);
int h = 1;
QgsFieldMap::const_iterator fldIt;
for (fldIt = mFields.begin(); fldIt != mFields.end(); ++fldIt)
{
QgsDebugMsg("field " + QString::number(fldIt.key()) + ": " + fldIt->name() +
" | " + QString(QVariant::typeToName(fldIt->type())) );
// Default row height is too tall
resizeRowsToContents();
setHorizontalHeaderItem(h++, new QTableWidgetItem(fldIt->name()));
}
//go through the features and fill the values into the table
QgsAttributeList all = provider->allAttributesList();
provider->select(all, QgsRect(), false);
while (provider->getNextFeature(fet))
{
if (!deletedFeatures.contains(fet.featureId()))
{
putFeatureInTable(row, fet);
row++;
}
}
//also consider the not commited features
for(QgsFeatureList::iterator it = addedFeatures.begin(); it != addedFeatures.end(); it++)
{
putFeatureInTable(row, *it);
row++;
}
// Default row height is too tall
resizeRowsToContents();
// Make each column wide enough to show all the contents
for (int i = 0; i < columnCount(); ++i)
{
resizeColumnToContents(i);
}
}
// Make each column wide enough to show all the contents
for (int i=0; i<columnCount(); i++)
resizeColumnToContents(i);
}
void QgsAttributeTable::putFeatureInTable(int row, QgsFeature& fet)
void QgsAttributeTable::putFeatureInTable(int row, const QgsFeature& fet)
{
// Prevent a crash if a provider doesn't update the feature count properly
if(row >= rowCount())
@ -623,21 +490,35 @@ void QgsAttributeTable::putFeatureInTable(int row, QgsFeature& fet)
//id-field
int id = fet.featureId();
QTableWidgetItem *item = new QTableWidgetItem(QString::number(id));
item->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
setItem(row, 0, item);
QTableWidgetItem *twi = new QTableWidgetItem(QString::number(id));
twi->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
setItem(row, 0, twi);
insertFeatureId(id, row); //insert the id into the search tree of qgsattributetable
const QgsAttributeMap& attr = fet.attributeMap();
QgsAttributeMap::const_iterator it;
int h = 1;
for (it = attr.begin(); it != attr.end(); ++it)
{
QString value;
const QgsAttributeMap& attr = fet.attributeMap();
for (QgsAttributeMap::const_iterator it = attr.begin(); it != attr.end(); ++it)
{
if( !mAttrIdxMap.contains( it.key() ) )
continue;
int h = mAttrIdxMap[ it.key() ];
twi = horizontalHeaderItem(h);
if(!twi)
{
QgsDebugMsg("header item not found.");
continue;
}
int type = twi->data(AttributeType).toInt();
bool isNum = (type == QVariant::Double || type == QVariant::Int);
QString value;
// get the field values
if( it->isNull() )
{
if( mFields[h-1].type()==QVariant::Int || mFields[h-1].type()==QVariant::Double )
if( isNum )
value="";
else
value="NULL";
@ -645,58 +526,10 @@ void QgsAttributeTable::putFeatureInTable(int row, QgsFeature& fet)
value = it->toString();
}
bool isNum;
value.toFloat(&isNum);
item = new QTableWidgetItem(value);
if (isNum) item->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
setItem(row, h++, item);
}
}
void QgsAttributeTable::storeChangedValue(int row, int column)
{
//id column is not editable
if(column>0)
{
//find feature id
int id=item(row,0)->text().toInt();
QString field = horizontalHeaderItem(column)->text();
if(id>=0)
{
// add empty map for feature if doesn't exist
if (!mChangedValues.contains(id))
{
mChangedValues.insert(id, QMap<QString, QString>());
}
mChangedValues[id].insert(field, item(row,column)->text());
mEdited=true;
}
else
{
// added feature attribute changed
emit featureAttributeChanged(row,column);
}
}
}
void QgsAttributeTable::clearEditingStructures()
{
mDeletedAttributes.clear();
mAddedAttributes.clear();
mChangedValues.clear();
}
void QgsAttributeTable::removeAttrColumn(const QString& name)
{
for(int i=0;i<columnCount();++i)
{
if(horizontalHeaderItem(i)->text()==name)
{
removeColumn(i);
break;
}
twi = new QTableWidgetItem(value);
if (isNum)
twi->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter);
setItem(row, h, twi);
}
}
@ -852,3 +685,54 @@ bool QgsAttributeTable::checkSelectionChanges()
return true;
}
}
void QgsAttributeTable::attributeValueChanged(int fid, int idx, const QVariant &value)
{
if( !rowIdMap.contains(fid) )
return;
if( !mAttrIdxMap.contains(idx) )
return;
item( rowIdMap[fid], mAttrIdxMap[idx] )->setText( value.toString() );
}
void QgsAttributeTable::featureDeleted(int fid)
{
if( !rowIdMap.contains(fid) )
return;
int row = rowIdMap[fid];
removeRow(row);
for(QMap<int,int>::iterator it=rowIdMap.begin(); it!=rowIdMap.end(); it++)
if( it.value() > row )
rowIdMap[ it.key() ]--;
}
void QgsAttributeTable::addAttribute(int attr, const QgsField &fld)
{
QTableWidgetItem *twi = new QTableWidgetItem( fld.name() );
twi->setData( AttributeIndex, attr );
twi->setData( AttributeName, fld.name() );
twi->setData( AttributeType, fld.type() );
insertColumn( columnCount() );
setHorizontalHeaderItem(columnCount()-1, twi);
mAttrIdxMap.insert(attr, columnCount()-1);
}
void QgsAttributeTable::deleteAttribute(int attr)
{
int column = mAttrIdxMap[attr];
removeColumn( column );
mAttrIdxMap.remove(attr);
for(QMap<int, int>::iterator it=mAttrIdxMap.begin(); it!=mAttrIdxMap.end(); it++)
{
if( it.value()>column )
mAttrIdxMap[ it.key() ]--;
}
}

View File

@ -21,6 +21,7 @@
#include "qgsattributeaction.h"
#include "qgsvectorlayer.h"
#include "qgsfield.h"
#include <QItemDelegate>
#include <QTableWidget>
@ -31,18 +32,21 @@
*@author Gary E.Sherman
*/
class QgsAttributeTable;
class QgsAttributeTableItemDelegate: public QItemDelegate
{
Q_OBJECT
public:
QgsAttributeTableItemDelegate(const QgsFieldMap & fields, QObject * parent = 0);
QgsAttributeTableItemDelegate(QgsAttributeTable *table, QObject * parent = 0);
QWidget * createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index ) const;
private:
const QgsFieldMap & mFields;
QgsAttributeTable *mTable;
};
class QgsAttributeTable:public QTableWidget
class QgsAttributeTable : public QTableWidget
{
Q_OBJECT
@ -50,9 +54,17 @@ class QgsAttributeTable:public QTableWidget
QgsAttributeTable(QWidget * parent = 0);
~QgsAttributeTable();
enum {
AttributeIndex = Qt::UserRole,
AttributeName = Qt::UserRole+1,
AttributeType = Qt::UserRole+2,
};
void setReadOnly(bool b);
void setColumnReadOnly(int col, bool ro);
/**Inserts the feature with the specified id into rowIdMap. This function has to be called (e.g. from QgsShapeFileLayer) when a row is inserted into the table*/
/* Inserts the feature with the specified id into rowIdMap. This function has to be called
(e.g. from QgsShapeFileLayer) when a row is inserted into the table */
void insertFeatureId(int id, int row);
/**Selects the row which belongs to the feature with the specified id*/
void selectRowWithId(int id);
@ -66,38 +78,11 @@ class QgsAttributeTable:public QTableWidget
bool edited() const {return mEdited;}
/**Switches editing mode on and off*/
void setEditable(bool enabled){mEditable=enabled;}
/**Adds an attribute to the table (but does not commit it yet)
@param name attribute name
@param type attribute type
@return false in case of a name conflict, true in case of success*/
bool addAttribute(const QString& name, const QString& type);
/**Deletes an attribute (but does not commit it)
@param name attribute name*/
void deleteAttribute(const QString& name);
/** Copies the selected rows to the clipboard
Deprecated: See QgisApp::editCopy() instead */
void copySelectedRows();
/**
Attempts to commit any changes to disk. Returns the result of the attempt.
If a commit fails, the in-memory changes are left alone.
This allows editing to continue if the commit failed on e.g. a
disallowed value in a Postgres database - the user can re-edit and try
again.
Delegates to QgsVectorLayer to decide, which changes
belong to not commited features or to commited ones.
*/
bool commitChanges(QgsVectorLayer* layer);
/**Discard all changes and restore
the state before editing was started*/
bool rollBack(QgsVectorLayer* layer);
/**Fills the contents of a provider into this table*/
void fillTable(QgsVectorLayer* layer);
/**Swaps the selected rows such that the selected ones are on the top of the table*/
void bringSelectedToTop();
/** Selects rows with chosen feature IDs */
@ -107,38 +92,42 @@ class QgsAttributeTable:public QTableWidget
/** Shows all rows */
void showAllRows();
/**Fills the contents of a provider into this table*/
void fillTable(QgsVectorLayer *layer);
void addAttribute(int idx, const QgsField &fld);
void deleteAttribute(int idx);
public slots:
void columnClicked(int col);
void rowClicked(int row);
// Called when the user chooses an item on the popup menu
void popupItemSelected(QAction * menuAction);
void attributeValueChanged(int fid, int idx, const QVariant &value);
void featureDeleted(int fid);
protected slots:
void handleChangedSelections();
/**Writes changed values to 'mChangedValues'*/
void storeChangedValue(int row, int column);
protected:
/**Flag telling if the ctrl-button or the shift-button is pressed*/
bool lockKeyPressed;
/**Search tree to find a row corresponding to a feature id*/
QMap<int,int> rowIdMap;
/**Map attribute index to columns*/
QMap<int,int> mAttrIdxMap;
bool mEditable;
/**True if table has been edited and contains uncommited changes*/
bool mEdited;
/**Map containing the added attributes. The key is the attribute name
and the value the attribute type*/
QgsNewAttributesMap mAddedAttributes;
/**Set containing the attribute names of deleted attributes*/
QSet<QString> mDeletedAttributes;
/**Nested map containing the changed attribute values. The int is the feature id,
the first QString the attribute name and the second QString the new value*/
QMap<int, QMap<QString, QString> > mChangedValues;
/**Stors the numbers of the last selected rows. This is used to check for selection changes before emit repaintRequested()*/
std::set<int> mLastSelectedRows;
/**Compares the content of two cells either alphanumeric or numeric. If 'ascending' is true, -1 means s1 is less, 0 equal, 1 greater. If 'ascending' is false, -1 means s1 is more, 0 equal, 1 greater. This method is used mainly to sort a column*/
/* Compares the content of two cells either alphanumeric or numeric.
If 'ascending' is true, -1 means s1 is less, 0 equal, 1 greater.
If 'ascending' is false, -1 means s1 is more, 0 equal, 1 greater.
This method is used mainly to sort a column*/
int compareItems(QString s1, QString s2, bool ascending, bool alphanumeric);
void keyPressEvent(QKeyEvent* ev);
void keyReleaseEvent(QKeyEvent* ev);
@ -146,16 +135,15 @@ class QgsAttributeTable:public QTableWidget
void qsort(int lower, int upper, int col, bool ascending, bool alphanumeric);
/**Called when the user requests a popup menu*/
void contextMenuEvent(QContextMenuEvent* event);
/**Clears mAddedAttributes, mDeletedAttributes and mChangedValues*/
void clearEditingStructures();
/**Removes the column belonging to an attribute from the table
@name attribut name*/
void removeAttrColumn(const QString& name);
/** puts attributes of feature to the chosen table row */
void putFeatureInTable(int row, QgsFeature& fet);
void putFeatureInTable(int row, const QgsFeature& fet);
void mouseReleaseEvent(QMouseEvent* e);
/**This function compares the current selection and the selection of the last repaint. Returns true if there are differences in the selection.
Also, mLastSelectedRows is updated*/
/**This function compares the current selection and the selection of the last repaint.
Returns true if there are differences in the selection.
Also, mLastSelectedRows is updated*/
bool checkSelectionChanges();
signals:
@ -165,8 +153,6 @@ class QgsAttributeTable:public QTableWidget
void selectionRemoved(bool);
/**Is emitted when a set of related selection and deselection signals have been emitted*/
void repaintRequested();
/**Is emitted when a attribute of a added feature is changed*/
void featureAttributeChanged(int row, int column);
private:
void swapRows(int row1, int row2);
@ -179,10 +165,10 @@ class QgsAttributeTable:public QTableWidget
QgsAttributeTableItemDelegate *mDelegate;
QgsFieldMap mFields;
// Track previous columm for QTableView sortIndicator wrong direction workaround
int mPreviousSortIndicatorColumn;
QgsVectorLayer *mLayer;
};
#endif

View File

@ -21,8 +21,6 @@
#include "qgisapp.h"
#include "qgsapplication.h"
#include "qgsaddattrdialog.h"
#include "qgsdelattrdialog.h"
#include "qgsfeature.h"
#include "qgsfield.h"
#include "qgslogger.h"
@ -39,249 +37,174 @@
#include <QPixmap>
#include <QSettings>
#include <QToolButton>
#include <QDockWidget>
QgsAttributeTableDisplay::QgsAttributeTableDisplay(QgsVectorLayer* layer, QgisApp * qgisApp)
QgsAttributeTableDisplay::QgsAttributeTableDisplay(QgsVectorLayer* layer)
: QDialog(0, Qt::Window),
mLayer(layer),
mQgisApp(qgisApp)
mDock(NULL)
{
setupUi(this);
restorePosition();
setTheme();
mToggleEditingButton->setEnabled( layer->getDataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues );
mToggleEditingButton->setChecked( layer->isEditable() );
connect(mRemoveSelectionButton, SIGNAL(clicked()), this, SLOT(removeSelection()));
connect(mSelectedToTopButton, SIGNAL(clicked()), this, SLOT(selectedToTop()));
connect(mInvertSelectionButton, SIGNAL(clicked()), this, SLOT(invertSelection()));
connect(mCopySelectedRowsButton, SIGNAL(clicked()), this, SLOT(copySelectedRowsToClipboard()));
connect(mZoomMapToSelectedRowsButton, SIGNAL(clicked()), this, SLOT(zoomMapToSelectedRows()));
connect(mAddAttributeButton, SIGNAL(clicked()), this, SLOT(addAttribute()));
connect(mDeleteAttributeButton, SIGNAL(clicked()), this, SLOT(deleteAttributes()));
connect(mSearchButton, SIGNAL(clicked()), this, SLOT(search()));
connect(mSearchShowResults, SIGNAL(activated(int)), this, SLOT(searchShowResultsChanged(int)));
connect(btnAdvancedSearch, SIGNAL(clicked()), this, SLOT(advancedSearch()));
connect(buttonBox, SIGNAL(helpRequested()), this, SLOT(showHelp()));
connect(buttonBox->button(QDialogButtonBox::Close), SIGNAL(clicked()),
this, SLOT(close()));
connect(tblAttributes, SIGNAL(featureAttributeChanged(int,int)), this, SLOT(changeFeatureAttribute(int,int)));
//disable those buttons until start editing has been pressed and provider supports it
mAddAttributeButton->setEnabled(false);
mDeleteAttributeButton->setEnabled(false);
connect(buttonBox->button(QDialogButtonBox::Close), SIGNAL(clicked()), this, SLOT(close()));
int cap=layer->getDataProvider()->capabilities();
if((cap&QgsVectorDataProvider::ChangeAttributeValues)
||(cap&QgsVectorDataProvider::AddAttributes)
||(cap&QgsVectorDataProvider::DeleteAttributes))
{
btnEdit->setEnabled(true);
}
else
{
btnEdit->setEnabled(false);
}
connect(mToggleEditingButton, SIGNAL(clicked()), this, SLOT(toggleEditing()));
connect(this, SIGNAL(editingToggled(QgsMapLayer *)), QgisApp::instance(), SLOT(toggleEditing(QgsMapLayer *)));
// etablish connection to table
connect(tblAttributes, SIGNAL(cellChanged(int, int)), this, SLOT(changeFeatureAttribute(int,int)));
// etablish connections to layer
connect(mLayer, SIGNAL(layerDeleted()), this, SLOT(close()));
connect(mLayer, SIGNAL(selectionChanged()), this, SLOT(selectionChanged()));
connect(mLayer, SIGNAL(editingStarted()), this, SLOT(editingToggled()));
connect(mLayer, SIGNAL(editingStopped()), this, SLOT(editingToggled()));
connect(mLayer, SIGNAL(attributeAdded(int)), this, SLOT(attributeAdded(int)));
connect(mLayer, SIGNAL(attributeDeleted(int)), this, SLOT(attributeDeleted(int)));
connect(mLayer, SIGNAL(attributeValueChanged(int,int,const QVariant &)),
tblAttributes, SLOT(attributeValueChanged(int,int,const QVariant &)) );
connect(mLayer, SIGNAL(featureDeleted(int)),
tblAttributes, SLOT(featureDeleted(int)));
// etablish connections between table and vector layer
connect(tblAttributes, SIGNAL(selected(int, bool)), mLayer, SLOT(select(int, bool)));
connect(tblAttributes, SIGNAL(selectionRemoved(bool)), mLayer, SLOT(removeSelection(bool)));
connect(tblAttributes, SIGNAL(repaintRequested()), mLayer, SLOT(triggerRepaint()));
// fill in mSearchColumns with available columns
QgsVectorDataProvider* provider = mLayer->getDataProvider();
if (provider)
const QgsFieldMap& xfields = mLayer->pendingFields();
QgsFieldMap::const_iterator fldIt;
for (fldIt = xfields.constBegin(); fldIt != xfields.constEnd(); ++fldIt)
{
const QgsFieldMap& xfields = provider->fields();
QgsFieldMap::const_iterator fldIt;
for (fldIt = xfields.constBegin(); fldIt != xfields.constEnd(); ++fldIt)
{
mSearchColumns->addItem(fldIt->name());
}
mSearchColumns->addItem(fldIt->name());
}
// TODO: create better labels
mSearchShowResults->addItem(tr("select"));
mSearchShowResults->addItem(tr("select and bring to top"));
mSearchShowResults->addItem(tr("show only matching"));
QSettings mySettings;
bool myDockFlag = mySettings.value("/qgis/dockAttributeTable",false).toBool();
if (myDockFlag )
{
mDock = new QDockWidget(tr("Attribute table - ") + layer->name(), QgisApp::instance());
mDock->setAllowedAreas(Qt::BottomDockWidgetArea | Qt::TopDockWidgetArea);
mDock->setWidget(this);
QgisApp::instance()->addDockWidget(Qt::BottomDockWidgetArea, mDock);
buttonBox->setVisible(false);
}
setWindowTitle(tr("Attribute table - ") + layer->name());
}
QgsAttributeTableDisplay::~QgsAttributeTableDisplay()
{
smTables.remove(mLayer);
}
QgsAttributeTable *QgsAttributeTableDisplay::table()
void QgsAttributeTableDisplay::closeEvent(QCloseEvent *ev)
{
return tblAttributes;
saveWindowLocation();
ev->ignore();
delete this;
}
void QgsAttributeTableDisplay::fillTable()
{
tblAttributes->fillTable( mLayer );
tblAttributes->setReadOnly( !mLayer->isEditable() );
selectionChanged();
// Give the table the most recent copy of the actions for this layer.
setAttributeActions(*mLayer->actions());
}
void QgsAttributeTableDisplay::toggleEditing()
{
emit editingToggled(mLayer);
}
void QgsAttributeTableDisplay::setAttributeActions(const QgsAttributeAction &action)
{
tblAttributes->setAttributeActions(action);
}
void QgsAttributeTableDisplay::selectRowsWithId(const QgsFeatureIds &ids)
{
tblAttributes->selectRowsWithId(ids);
}
void QgsAttributeTableDisplay::setTheme()
{
mAddAttributeButton->setIcon(QgisApp::getThemeIcon("/mActionNewAttribute.png"));
mRemoveSelectionButton->setIcon(QgisApp::getThemeIcon("/mActionUnselectAttributes.png"));
mSelectedToTopButton->setIcon(QgisApp::getThemeIcon("/mActionSelectedToTop.png"));
mInvertSelectionButton->setIcon(QgisApp::getThemeIcon("/mActionInvertSelection.png"));
mCopySelectedRowsButton->setIcon(QgisApp::getThemeIcon("/mActionCopySelected.png"));
mZoomMapToSelectedRowsButton->setIcon(QgisApp::getThemeIcon("/mActionZoomToSelected.png"));
mAddAttributeButton->setIcon(QgisApp::getThemeIcon("/mActionNewAttribute.png"));
mDeleteAttributeButton->setIcon(QgisApp::getThemeIcon("/mActionDeleteAttribute.png"));
btnEdit->setIcon(QgisApp::getThemeIcon("/mActionToggleEditing.png"));
mToggleEditingButton->setIcon(QgisApp::getThemeIcon("/mActionToggleEditing.png"));
}
void QgsAttributeTableDisplay::setTitle(QString title)
void QgsAttributeTableDisplay::editingToggled()
{
setWindowTitle(title);
}
void QgsAttributeTableDisplay::deleteAttributes()
{
QgsDelAttrDialog dialog(table()->horizontalHeader());
if(dialog.exec()==QDialog::Accepted)
{
const std::list<QString>* attlist=dialog.selectedAttributes();
for(std::list<QString>::const_iterator iter=attlist->begin();iter!=attlist->end();++iter)
{
table()->deleteAttribute(*iter);
}
}
}
void QgsAttributeTableDisplay::addAttribute()
{
QgsAddAttrDialog dialog(mLayer->getDataProvider(), this);
if(dialog.exec()==QDialog::Accepted)
{
if(!table()->addAttribute(dialog.name(),dialog.type()))
{
QMessageBox::information(this,tr("Name conflict"),tr("The attribute could not be inserted. The name already exists in the table."));
}
}
}
void QgsAttributeTableDisplay::startEditing()
{
QgsVectorDataProvider* provider=mLayer->getDataProvider();
bool editing=false;
if(provider)
{
if(provider->capabilities()&QgsVectorDataProvider::AddAttributes)
{
mAddAttributeButton->setEnabled(true);
editing=true;
}
if(provider->capabilities()&QgsVectorDataProvider::DeleteAttributes)
{
mDeleteAttributeButton->setEnabled(true);
editing=true;
}
if(provider->capabilities()&QgsVectorDataProvider::ChangeAttributeValues)
{
table()->setReadOnly(false);
table()->setColumnReadOnly(0,true);//id column is not editable
editing=true;
}
if(editing)
{
btnEdit->setText(tr("Stop editing"));
buttonBox->button(QDialogButtonBox::Close)->setEnabled(false);
//make the dialog modal when in editable
//otherwise map editing and table editing
//may disturb each other
//hide();
//setModal(true);
//show();
}
else
{
//revert button
QMessageBox::information(this,tr("Editing not permitted"),tr("The data provider is read only, editing is not allowed."));
btnEdit->setChecked(false);
}
}
}
void QgsAttributeTableDisplay::on_btnEdit_toggled(bool theFlag)
{
if (theFlag)
{
startEditing();
}
else
{
stopEditing();
}
}
void QgsAttributeTableDisplay::stopEditing()
{
if(table()->edited())
{
//commit or roll back?
QMessageBox::StandardButton commit=QMessageBox::information(this,tr("Stop editing"),
tr("Do you want to save the changes?"),
QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
if(commit==QMessageBox::Save)
{
if(!table()->commitChanges(mLayer))
{
QMessageBox::information(this,tr("Error"),tr("Could not commit changes - changes are still pending"));
return;
}
}
else if(commit == QMessageBox::Discard)
{
table()->rollBack(mLayer);
}
else //cancel
{
return;
}
}
btnEdit->setText(tr("Start editing"));
buttonBox->button(QDialogButtonBox::Close)->setEnabled(true);
mAddAttributeButton->setEnabled(false);
mDeleteAttributeButton->setEnabled(false);
table()->setReadOnly(true);
//make this dialog modeless again
hide();
setModal(false);
show();
mToggleEditingButton->setChecked( mLayer->isEditable() );
tblAttributes->setReadOnly( !mLayer->isEditable() );
}
void QgsAttributeTableDisplay::selectedToTop()
{
table()->bringSelectedToTop();
tblAttributes->bringSelectedToTop();
}
void QgsAttributeTableDisplay::invertSelection()
{
if(mLayer)
{
QApplication::setOverrideCursor(Qt::WaitCursor);
mLayer->invertSelection();
QApplication::restoreOverrideCursor();
}
if(!mLayer)
return;
QApplication::setOverrideCursor(Qt::WaitCursor);
mLayer->invertSelection();
QApplication::restoreOverrideCursor();
}
void QgsAttributeTableDisplay::removeSelection()
{
table()->clearSelection();
mLayer->triggerRepaint();
tblAttributes->clearSelection();
mLayer->triggerRepaint();
}
void QgsAttributeTableDisplay::copySelectedRowsToClipboard()
{
// Deprecated
// table()->copySelectedRows();
// Use the Application's copy method instead
mQgisApp->editCopy(mLayer);
QgisApp::instance()->editCopy(mLayer);
}
void QgsAttributeTableDisplay::zoomMapToSelectedRows()
{
mQgisApp->zoomToSelected();
QgisApp::instance()->zoomToSelected();
}
void QgsAttributeTableDisplay::search()
{
// if selected field is numeric, numeric comparison will be used
// else attributes containing entered text will be matched
QgsVectorDataProvider* provider = mLayer->getDataProvider();
int item = mSearchColumns->currentIndex();
QVariant::Type type = provider->fields()[item].type();
int type = tblAttributes->item(0, mSearchColumns->currentIndex())->data(QgsAttributeTable::AttributeType).toInt();
bool numeric = (type == QVariant::Int || type == QVariant::Double);
QString str;
@ -314,25 +237,25 @@ void QgsAttributeTableDisplay::searchShowResultsChanged(int item)
if (item == 2) // show only matching
{
table()->showRowsWithId(mSearchIds);
tblAttributes->showRowsWithId(mSearchIds);
}
else
{
// make sure that all rows are shown
table()->showAllRows();
tblAttributes->showAllRows();
// select matching
mLayer->setSelectedFeatures(mSearchIds);
if (item == 1) // select matching and bring to top
table()->bringSelectedToTop();
tblAttributes->bringSelectedToTop();
}
QApplication::restoreOverrideCursor();
}
void QgsAttributeTableDisplay::doSearch(const QString& searchString)
void QgsAttributeTableDisplay::doSearch(QString searchString)
{
mSearchString = searchString;
@ -343,6 +266,7 @@ void QgsAttributeTableDisplay::doSearch(const QString& searchString)
QMessageBox::critical(this, tr("Search string parsing error"), search.parserErrorMsg());
return;
}
QgsSearchTreeNode* searchTree = search.tree();
if (searchTree == NULL)
{
@ -354,24 +278,19 @@ void QgsAttributeTableDisplay::doSearch(const QString& searchString)
QApplication::setOverrideCursor(Qt::WaitCursor);
// TODO: need optimized getNextFeature which won't extract geometry
// or search by traversing table ... which one is quicker?
QgsFeature fet;
QgsVectorDataProvider* provider = mLayer->getDataProvider();
mSearchIds.clear();
const QgsFieldMap& fields = provider->fields();
QgsAttributeList all = provider->allAttributesList();
provider->select(all, QgsRect(), false);
while (provider->getNextFeature(fet))
mLayer->select(mLayer->pendingAllAttributesList(), true, false);
QgsFeature f;
while( mLayer->getNextFeature(f) )
{
if (searchTree->checkAgainst(fields, fet.attributeMap()))
if (searchTree->checkAgainst(mLayer->pendingFields(), f.attributeMap()))
{
mSearchIds.insert(fet.featureId());
mSearchIds << f.featureId();
}
// check if there were errors during evaulating
// check if there were errors during evaluating
if (searchTree->hasError())
break;
}
@ -386,22 +305,13 @@ void QgsAttributeTableDisplay::doSearch(const QString& searchString)
// update table
searchShowResultsChanged(mSearchShowResults->currentIndex());
QString str;
if (mSearchIds.size())
str.sprintf(tr("Found %d matching features.","", mSearchIds.size()).toUtf8(), mSearchIds.size());
else
str = tr("No matching features found.");
QMessageBox::information(this, tr("Search results"), str);
}
void QgsAttributeTableDisplay::closeEvent(QCloseEvent* ev)
{
saveWindowLocation();
ev->ignore();
emit deleted();
delete this;
}
void QgsAttributeTableDisplay::restorePosition()
@ -423,16 +333,77 @@ void QgsAttributeTableDisplay::showHelp()
void QgsAttributeTableDisplay::changeFeatureAttribute(int row, int column)
{
QgsFeatureList &flist = mLayer->addedFeatures();
int id = table()->item(row,0)->text().toInt();
int i;
for(i=0; i<flist.size() && flist[i].featureId()!=id; i++)
;
if(i==flist.size())
if(column==0)
return;
flist[i].changeAttribute(column-1, table()->item(row,column)->text());
if( !mLayer->isEditable() )
return;
mLayer->changeAttributeValue(
tblAttributes->item(row,0)->text().toInt(),
tblAttributes->horizontalHeaderItem(column)->data(QgsAttributeTable::AttributeIndex).toInt(),
tblAttributes->item(row, column)->text(),
false
);
}
QMap<QgsVectorLayer *, QgsAttributeTableDisplay *> QgsAttributeTableDisplay::smTables;
QgsAttributeTableDisplay *QgsAttributeTableDisplay::attributeTable(QgsVectorLayer *layer)
{
if(!layer)
return NULL;
if( smTables.contains(layer) ) {
QgsAttributeTableDisplay *td = smTables[layer];
td->setAttributeActions(*layer->actions());
td->raise();
return td;
}
QgsAttributeTableDisplay *td = new QgsAttributeTableDisplay(layer);
if(!td)
return NULL;
// display the attribute table
QApplication::setOverrideCursor(Qt::WaitCursor);
try
{
td->fillTable();
}
catch(std::bad_alloc& ba)
{
Q_UNUSED(ba);
QMessageBox::critical(0, tr("bad_alloc exception"), tr("Filling the attribute table has been stopped because there was no more virtual memory left"));
delete td;
td=NULL;
}
QApplication::restoreOverrideCursor();
if(!td)
return NULL;
smTables[layer] = td;
td->show();
return td;
}
void QgsAttributeTableDisplay::selectionChanged()
{
// select rows which should be selected
selectRowsWithId( mLayer->selectedFeaturesIds() );
}
void QgsAttributeTableDisplay::attributeAdded(int attr)
{
tblAttributes->addAttribute(attr, mLayer->pendingFields()[attr]);
}
void QgsAttributeTableDisplay::attributeDeleted(int attr)
{
tblAttributes->deleteAttribute(attr);
}

View File

@ -22,47 +22,41 @@
#include "ui_qgsattributetablebase.h"
class QDockWidget;
class QgsAttributeTable;
class QgsVectorLayer;
class QgisApp;
class QgsAttributeActions;
/**
*@author Gary E.Sherman
*/
class QgsAttributeTableDisplay:public QDialog, private Ui::QgsAttributeTableBase
class QgsAttributeTableDisplay : public QDialog, private Ui::QgsAttributeTableBase
{
Q_OBJECT
public:
/**
\param qgisApp This should be the QgisApp that spawned this table.
Otherwise the Copy button on this QgsAttributeTableDisplay
will not work.
*/
QgsAttributeTableDisplay(QgsVectorLayer* layer, QgisApp * qgisApp);
static QgsAttributeTableDisplay *attributeTable(QgsVectorLayer *layer);
~QgsAttributeTableDisplay();
QgsAttributeTable *table();
void setTitle(QString title);
void fillTable();
protected:
QgsAttributeTableDisplay(QgsVectorLayer* layer);
QgsVectorLayer* mLayer;
QgisApp * mQgisApp;
void doSearch(QString searchString);
void setAttributeActions(const QgsAttributeAction &actions);
void selectRowsWithId(const QgsFeatureIds &ids);
void doSearch(const QString& searchString);
virtual void closeEvent(QCloseEvent* ev);
virtual void closeEvent(QCloseEvent *ev);
/** array of feature IDs that match last searched condition */
QgsFeatureIds mSearchIds;
protected slots:
void deleteAttributes();
void addAttribute();
void on_btnEdit_toggled(bool theFlag);
void startEditing();
void stopEditing();
void selectedToTop();
void invertSelection();
void removeSelection();
@ -72,12 +66,18 @@ class QgsAttributeTableDisplay:public QDialog, private Ui::QgsAttributeTableBase
void advancedSearch();
void searchShowResultsChanged(int item);
void showHelp();
void toggleEditing();
void attributeAdded(int idx);
void attributeDeleted(int idx);
public slots:
void changeFeatureAttribute(int row, int column);
void editingToggled();
void selectionChanged();
signals:
void deleted();
void editingToggled(QgsMapLayer *);
private:
/** Set the icon theme for this dialog */
@ -88,7 +88,11 @@ class QgsAttributeTableDisplay:public QDialog, private Ui::QgsAttributeTableBase
QString mSearchString;
QDockWidget *mDock;
static const int context_id = 831088384;
static QMap<QgsVectorLayer *, QgsAttributeTableDisplay *> smTables;
};
#endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -42,419 +42,420 @@ QgsMapToolAddFeature::~QgsMapToolAddFeature()
void QgsMapToolAddFeature::canvasReleaseEvent(QMouseEvent * e)
{
QgsVectorLayer *vlayer = dynamic_cast <QgsVectorLayer*>(mCanvas->currentLayer());
if (!vlayer)
{
QMessageBox::information(0, QObject::tr("Not a vector layer"),
QObject::tr("The current layer is not a vector layer"));
return;
}
{
QMessageBox::information(0, QObject::tr("Not a vector layer"),
QObject::tr("The current layer is not a vector layer"));
return;
}
QGis::WKBTYPE layerWKBType = vlayer->geometryType();
//no support for adding features to 2.5D types yet
if(layerWKBType == QGis::WKBLineString25D || layerWKBType == QGis::WKBPolygon25D || \
layerWKBType == QGis::WKBMultiLineString25D || layerWKBType == QGis::WKBPoint25D || layerWKBType == QGis::WKBMultiPoint25D)
{
QMessageBox::critical(0, QObject::tr("2.5D shape type not supported"), QObject::tr("Adding features to 2.5D shapetypes is not supported yet"));
delete mRubberBand;
mRubberBand = NULL;
mCapturing = FALSE;
mCaptureList.clear();
mCanvas->refresh();
return;
}
layerWKBType == QGis::WKBMultiLineString25D || layerWKBType == QGis::WKBPoint25D || layerWKBType == QGis::WKBMultiPoint25D)
{
QMessageBox::critical(0, QObject::tr("2.5D shape type not supported"), QObject::tr("Adding features to 2.5D shapetypes is not supported yet"));
delete mRubberBand;
mRubberBand = NULL;
mCapturing = FALSE;
mCaptureList.clear();
mCanvas->refresh();
return;
}
QgsVectorDataProvider* provider = vlayer->getDataProvider();
if(!(provider->capabilities() & QgsVectorDataProvider::AddFeatures))
{
QMessageBox::information(0, QObject::tr("Layer cannot be added to"),
QObject::tr("The data provider for this layer does not support the addition of features."));
return;
}
{
QMessageBox::information(0, QObject::tr("Layer cannot be added to"),
QObject::tr("The data provider for this layer does not support the addition of features."));
return;
}
if (!vlayer->isEditable())
{
QMessageBox::information(0, QObject::tr("Layer not editable"),
QObject::tr("Cannot edit the vector layer. To make it editable, go to the file item "
"of the layer, right click and check 'Allow Editing'."));
return;
}
{
QMessageBox::information(0, QObject::tr("Layer not editable"),
QObject::tr("Cannot edit the vector layer. To make it editable, go to the file item "
"of the layer, right click and check 'Allow Editing'."));
return;
}
// POINT CAPTURING
if (mTool == CapturePoint)
{
//check we only use this tool for point/multipoint layers
if(vlayer->vectorType() != QGis::Point)
{
//check we only use this tool for point/multipoint layers
if(vlayer->vectorType() != QGis::Point)
{
QMessageBox::information(0, QObject::tr("Wrong editing tool"),
QObject::tr("Cannot apply the 'capture point' tool on this vector layer"));
return;
}
QMessageBox::information(0, QObject::tr("Wrong editing tool"),
QObject::tr("Cannot apply the 'capture point' tool on this vector layer"));
return;
}
QgsPoint idPoint; //point in map coordinates
QList<QgsSnappingResult> snapResults;
QgsPoint savePoint; //point in layer coordinates
if(mSnapper.snapToBackgroundLayers(e->pos(), snapResults) == 0)
QgsPoint idPoint; //point in map coordinates
QList<QgsSnappingResult> snapResults;
QgsPoint savePoint; //point in layer coordinates
if(mSnapper.snapToBackgroundLayers(e->pos(), snapResults) == 0)
{
idPoint = snapPointFromResults(snapResults, e->pos());
try
{
idPoint = snapPointFromResults(snapResults, e->pos());
try
{
savePoint = toLayerCoords(vlayer, idPoint);
QgsDebugMsg("savePoint = " + savePoint.stringRep());
}
catch(QgsCsException &cse)
{
Q_UNUSED(cse);
QMessageBox::information(0, QObject::tr("Coordinate transform error"), \
QObject::tr("Cannot transform the point to the layers coordinate system"));
return;
}
savePoint = toLayerCoords(vlayer, idPoint);
QgsDebugMsg("savePoint = " + savePoint.stringRep());
}
catch(QgsCsException &cse)
{
Q_UNUSED(cse);
QMessageBox::information(0, QObject::tr("Coordinate transform error"), \
QObject::tr("Cannot transform the point to the layers coordinate system"));
return;
}
// emit signal - QgisApp can catch it and save point position to clipboard
// FIXME: is this still actual or something old that's not used anymore?
//emit xyClickCoordinates(idPoint);
//only do the rest for provider with feature addition support
//note that for the grass provider, this will return false since
//grass provider has its own mechanism of feature addition
if(provider->capabilities() & QgsVectorDataProvider::AddFeatures)
{
QgsFeature* f = new QgsFeature(0,"WKBPoint");
int size = 0;
char end=QgsApplication::endian();
unsigned char *wkb = NULL;
int wkbtype = 0;
double x = savePoint.x();
double y = savePoint.y();
if(layerWKBType == QGis::WKBPoint)
{
size=1+sizeof(int)+2*sizeof(double);
wkb = new unsigned char[size];
wkbtype=QGis::WKBPoint;
memcpy(&wkb[0],&end,1);
memcpy(&wkb[1],&wkbtype, sizeof(int));
memcpy(&wkb[5], &x, sizeof(double));
memcpy(&wkb[5]+sizeof(double), &y, sizeof(double));
}
else if(layerWKBType == QGis::WKBMultiPoint)
{
size = 2+3*sizeof(int)+2*sizeof(double);
wkb = new unsigned char[size];
wkbtype=QGis::WKBMultiPoint;
int position = 0;
memcpy(&wkb[position], &end, 1);
position += 1;
memcpy(&wkb[position], &wkbtype, sizeof(int));
position += sizeof(int);
int npoint = 1;
memcpy(&wkb[position], &npoint, sizeof(int));
position += sizeof(int);
memcpy(&wkb[position], &end, 1);
position += 1;
int pointtype = QGis::WKBPoint;
memcpy(&wkb[position],&pointtype, sizeof(int));
position += sizeof(int);
memcpy(&wkb[position], &x, sizeof(double));
position += sizeof(double);
memcpy(&wkb[position], &y, sizeof(double));
}
f->setGeometryAndOwnership(&wkb[0],size);
// add the fields to the QgsFeature
const QgsFieldMap fields=provider->fields();
for(QgsFieldMap::const_iterator it = fields.constBegin(); it != fields.constEnd(); ++it)
{
f->addAttribute(it.key(), provider->getDefaultValue(it.key()) );
}
// show the dialog to enter attribute values
QgsAttributeDialog * mypDialog = new QgsAttributeDialog( vlayer, f );
if (mypDialog->exec())
// emit signal - QgisApp can catch it and save point position to clipboard
// FIXME: is this still actual or something old that's not used anymore?
//emit xyClickCoordinates(idPoint);
//only do the rest for provider with feature addition support
//note that for the grass provider, this will return false since
//grass provider has its own mechanism of feature addition
if(provider->capabilities() & QgsVectorDataProvider::AddFeatures)
{
qDebug("Adding feature to layer");
vlayer->addFeature(*f);
QgsFeature* f = new QgsFeature(0,"WKBPoint");
int size = 0;
char end=QgsApplication::endian();
unsigned char *wkb = NULL;
int wkbtype = 0;
double x = savePoint.x();
double y = savePoint.y();
if(layerWKBType == QGis::WKBPoint)
{
size=1+sizeof(int)+2*sizeof(double);
wkb = new unsigned char[size];
wkbtype=QGis::WKBPoint;
memcpy(&wkb[0],&end,1);
memcpy(&wkb[1],&wkbtype, sizeof(int));
memcpy(&wkb[5], &x, sizeof(double));
memcpy(&wkb[5]+sizeof(double), &y, sizeof(double));
}
else if(layerWKBType == QGis::WKBMultiPoint)
{
size = 2+3*sizeof(int)+2*sizeof(double);
wkb = new unsigned char[size];
wkbtype=QGis::WKBMultiPoint;
int position = 0;
memcpy(&wkb[position], &end, 1);
position += 1;
memcpy(&wkb[position], &wkbtype, sizeof(int));
position += sizeof(int);
int npoint = 1;
memcpy(&wkb[position], &npoint, sizeof(int));
position += sizeof(int);
memcpy(&wkb[position], &end, 1);
position += 1;
int pointtype = QGis::WKBPoint;
memcpy(&wkb[position],&pointtype, sizeof(int));
position += sizeof(int);
memcpy(&wkb[position], &x, sizeof(double));
position += sizeof(double);
memcpy(&wkb[position], &y, sizeof(double));
}
f->setGeometryAndOwnership(&wkb[0],size);
// add the fields to the QgsFeature
const QgsFieldMap fields=vlayer->pendingFields();
for(QgsFieldMap::const_iterator it = fields.constBegin(); it != fields.constEnd(); ++it)
{
f->addAttribute(it.key(), provider->getDefaultValue(it.key()) );
}
// show the dialog to enter attribute values
QgsAttributeDialog * mypDialog = new QgsAttributeDialog( vlayer, f );
if (mypDialog->exec())
{
qDebug("Adding feature to layer");
vlayer->addFeature(*f);
}
else
{
qDebug("Adding feature to layer failed");
delete f;
}
delete mypDialog;
mCanvas->refresh();
}
else
{
qDebug("Adding feature to layer failed");
delete f;
}
delete mypDialog;
mCanvas->refresh();
}
}
}
else if (mTool == CaptureLine || mTool == CapturePolygon)
{
//check we only use the line tool for line/multiline layers
if(mTool == CaptureLine && vlayer->vectorType() != QGis::Line)
{
//check we only use the line tool for line/multiline layers
if(mTool == CaptureLine && vlayer->vectorType() != QGis::Line)
{
QMessageBox::information(0, QObject::tr("Wrong editing tool"),
QObject::tr("Cannot apply the 'capture line' tool on this vector layer"));
return;
}
//check we only use the polygon tool for polygon/multipolygon layers
if(mTool == CapturePolygon && vlayer->vectorType() != QGis::Polygon)
{
QMessageBox::information(0, QObject::tr("Wrong editing tool"),
QObject::tr("Cannot apply the 'capture polygon' tool on this vector layer"));
return;
}
QMessageBox::information(0, QObject::tr("Wrong editing tool"),
QObject::tr("Cannot apply the 'capture line' tool on this vector layer"));
return;
}
//add point to list and to rubber band
int error = addVertex(e->pos());
if(error == 1)
{
//current layer is not a vector layer
return;
}
else if (error == 2)
{
//problem with coordinate transformation
QMessageBox::information(0, QObject::tr("Coordinate transform error"), \
QObject::tr("Cannot transform the point to the layers coordinate system"));
return;
}
if (e->button() == Qt::LeftButton)
{
mCapturing = TRUE;
}
else if (e->button() == Qt::RightButton)
{
// End of string
mCapturing = FALSE;
delete mRubberBand;
mRubberBand = NULL;
//lines: bail out if there are not at least two vertices
if(mTool == CaptureLine && mCaptureList.size() < 2)
{
mCaptureList.clear();
return;
}
//polygons: bail out if there are not at least two vertices
if(mTool == CapturePolygon && mCaptureList.size() < 3)
{
mCaptureList.clear();
return;
}
//create QgsFeature with wkb representation
QgsFeature* f = new QgsFeature(0,"WKBLineString");
unsigned char* wkb;
int size;
char end=QgsApplication::endian();
if(mTool == CaptureLine)
{
if(layerWKBType == QGis::WKBLineString)
{
size=1+2*sizeof(int)+2*mCaptureList.size()*sizeof(double);
wkb= new unsigned char[size];
int wkbtype=QGis::WKBLineString;
int length=mCaptureList.size();
memcpy(&wkb[0],&end,1);
memcpy(&wkb[1],&wkbtype, sizeof(int));
memcpy(&wkb[1+sizeof(int)],&length, sizeof(int));
int position=1+2*sizeof(int);
double x,y;
for(QList<QgsPoint>::iterator it=mCaptureList.begin();it!=mCaptureList.end();++it)
{
QgsPoint savePoint = *it;
x = savePoint.x();
y = savePoint.y();
memcpy(&wkb[position],&x,sizeof(double));
position+=sizeof(double);
memcpy(&wkb[position],&y,sizeof(double));
position+=sizeof(double);
}
}
else if(layerWKBType == QGis::WKBMultiLineString)
{
size = 1+2*sizeof(int)+1+2*sizeof(int)+2*mCaptureList.size()*sizeof(double);
wkb= new unsigned char[size];
int position = 0;
int wkbtype=QGis::WKBMultiLineString;
memcpy(&wkb[position], &end, 1);
position += 1;
memcpy(&wkb[position], &wkbtype, sizeof(int));
position += sizeof(int);
int nlines = 1;
memcpy(&wkb[position], &nlines, sizeof(int));
position += sizeof(int);
memcpy(&wkb[position], &end, 1);
position += 1;
int linewkbtype = QGis::WKBLineString;
memcpy(&wkb[position], &linewkbtype, sizeof(int));
position += sizeof(int);
int length=mCaptureList.size();
memcpy(&wkb[position], &length, sizeof(int));
position += sizeof(int);
double x,y;
for(QList<QgsPoint>::iterator it=mCaptureList.begin();it!=mCaptureList.end();++it)
{
QgsPoint savePoint = *it;
x = savePoint.x();
y = savePoint.y();
memcpy(&wkb[position],&x,sizeof(double));
position+=sizeof(double);
memcpy(&wkb[position],&y,sizeof(double));
position+=sizeof(double);
}
}
else
{
QMessageBox::critical(0, QObject::tr("Error"), QObject::tr("Cannot add feature. Unknown WKB type"));
return; //unknown wkbtype
}
f->setGeometryAndOwnership(&wkb[0],size);
}
else // polygon
{
if(layerWKBType == QGis::WKBPolygon)
{
size=1+3*sizeof(int)+2*(mCaptureList.size()+1)*sizeof(double);
wkb= new unsigned char[size];
int wkbtype=QGis::WKBPolygon;
int length=mCaptureList.size()+1;//+1 because the first point is needed twice
int numrings=1;
memcpy(&wkb[0],&end,1);
memcpy(&wkb[1],&wkbtype, sizeof(int));
memcpy(&wkb[1+sizeof(int)],&numrings,sizeof(int));
memcpy(&wkb[1+2*sizeof(int)],&length, sizeof(int));
int position=1+3*sizeof(int);
double x,y;
QList<QgsPoint>::iterator it;
for(it=mCaptureList.begin();it!=mCaptureList.end();++it)
{
QgsPoint savePoint = *it;
x = savePoint.x();
y = savePoint.y();
memcpy(&wkb[position],&x,sizeof(double));
position+=sizeof(double);
memcpy(&wkb[position],&y,sizeof(double));
position+=sizeof(double);
}
// close the polygon
it=mCaptureList.begin();
QgsPoint savePoint = *it;
x = savePoint.x();
y = savePoint.y();
memcpy(&wkb[position],&x,sizeof(double));
position+=sizeof(double);
memcpy(&wkb[position],&y,sizeof(double));
}
else if(layerWKBType == QGis::WKBMultiPolygon)
{
size = 2+5*sizeof(int)+2*(mCaptureList.size()+1)*sizeof(double);
wkb = new unsigned char[size];
int wkbtype = QGis::WKBMultiPolygon;
int polygontype = QGis::WKBPolygon;
int length = mCaptureList.size()+1;//+1 because the first point is needed twice
int numrings = 1;
int numpolygons = 1;
int position = 0; //pointer position relative to &wkb[0]
memcpy(&wkb[position],&end,1);
position += 1;
memcpy(&wkb[position],&wkbtype, sizeof(int));
position += sizeof(int);
memcpy(&wkb[position], &numpolygons, sizeof(int));
position += sizeof(int);
memcpy(&wkb[position], &end, 1);
position += 1;
memcpy(&wkb[position], &polygontype, sizeof(int));
position += sizeof(int);
memcpy(&wkb[position], &numrings, sizeof(int));
position += sizeof(int);
memcpy(&wkb[position], &length, sizeof(int));
position += sizeof(int);
double x,y;
QList<QgsPoint>::iterator it;
for(it=mCaptureList.begin();it!=mCaptureList.end();++it)//add the captured points to the polygon
{
QgsPoint savePoint = *it;
x = savePoint.x();
y = savePoint.y();
memcpy(&wkb[position],&x,sizeof(double));
position+=sizeof(double);
memcpy(&wkb[position],&y,sizeof(double));
position+=sizeof(double);
}
// close the polygon
it=mCaptureList.begin();
QgsPoint savePoint = *it;
x = savePoint.x();
y = savePoint.y();
memcpy(&wkb[position],&x,sizeof(double));
position+=sizeof(double);
memcpy(&wkb[position],&y,sizeof(double));
}
else
{
QMessageBox::critical(0, QObject::tr("Error"), QObject::tr("Cannot add feature. Unknown WKB type"));
return; //unknown wkbtype
}
f->setGeometryAndOwnership(&wkb[0],size);
//is automatic polygon intersection removal activated?
int avoidPolygonIntersections = QgsProject::instance()->readNumEntry("Digitizing", "/AvoidPolygonIntersections", 0);
if(avoidPolygonIntersections != 0)
{
if(vlayer->removePolygonIntersections(f->geometry()) != 0)
{
QMessageBox::critical(0, QObject::tr("Error"), QObject::tr("Could not remove polygon intersection"));
}
}
}
// add the fields to the QgsFeature
const QgsFieldMap fields = provider->fields();
for(QgsFieldMap::const_iterator it = fields.begin(); it != fields.end(); ++it)
{
f->addAttribute(it.key(), provider->getDefaultValue(it.key()));
}
QgsAttributeDialog * mypDialog = new QgsAttributeDialog( vlayer, f );
if (mypDialog->exec())
//check we only use the polygon tool for polygon/multipolygon layers
if(mTool == CapturePolygon && vlayer->vectorType() != QGis::Polygon)
{
if(vlayer->addFeature(*f))
QMessageBox::information(0, QObject::tr("Wrong editing tool"),
QObject::tr("Cannot apply the 'capture polygon' tool on this vector layer"));
return;
}
//add point to list and to rubber band
int error = addVertex(e->pos());
if(error == 1)
{
//current layer is not a vector layer
return;
}
else if (error == 2)
{
//problem with coordinate transformation
QMessageBox::information(0, QObject::tr("Coordinate transform error"), \
QObject::tr("Cannot transform the point to the layers coordinate system"));
return;
}
if (e->button() == Qt::LeftButton)
{
mCapturing = TRUE;
}
else if (e->button() == Qt::RightButton)
{
// End of string
mCapturing = FALSE;
delete mRubberBand;
mRubberBand = NULL;
//lines: bail out if there are not at least two vertices
if(mTool == CaptureLine && mCaptureList.size() < 2)
{
//add points to other features to keep topology up-to-date
int topologicalEditing = QgsProject::instance()->readNumEntry("Digitizing", "/TopologicalEditing", 0);
if(topologicalEditing)
mCaptureList.clear();
return;
}
//polygons: bail out if there are not at least two vertices
if(mTool == CapturePolygon && mCaptureList.size() < 3)
{
mCaptureList.clear();
return;
}
//create QgsFeature with wkb representation
QgsFeature* f = new QgsFeature(0,"WKBLineString");
unsigned char* wkb;
int size;
char end=QgsApplication::endian();
if(mTool == CaptureLine)
{
if(layerWKBType == QGis::WKBLineString)
{
vlayer->addTopologicalPoints(f->geometry());
size=1+2*sizeof(int)+2*mCaptureList.size()*sizeof(double);
wkb= new unsigned char[size];
int wkbtype=QGis::WKBLineString;
int length=mCaptureList.size();
memcpy(&wkb[0],&end,1);
memcpy(&wkb[1],&wkbtype, sizeof(int));
memcpy(&wkb[1+sizeof(int)],&length, sizeof(int));
int position=1+2*sizeof(int);
double x,y;
for(QList<QgsPoint>::iterator it=mCaptureList.begin();it!=mCaptureList.end();++it)
{
QgsPoint savePoint = *it;
x = savePoint.x();
y = savePoint.y();
memcpy(&wkb[position],&x,sizeof(double));
position+=sizeof(double);
memcpy(&wkb[position],&y,sizeof(double));
position+=sizeof(double);
}
}
else if(layerWKBType == QGis::WKBMultiLineString)
{
size = 1+2*sizeof(int)+1+2*sizeof(int)+2*mCaptureList.size()*sizeof(double);
wkb= new unsigned char[size];
int position = 0;
int wkbtype=QGis::WKBMultiLineString;
memcpy(&wkb[position], &end, 1);
position += 1;
memcpy(&wkb[position], &wkbtype, sizeof(int));
position += sizeof(int);
int nlines = 1;
memcpy(&wkb[position], &nlines, sizeof(int));
position += sizeof(int);
memcpy(&wkb[position], &end, 1);
position += 1;
int linewkbtype = QGis::WKBLineString;
memcpy(&wkb[position], &linewkbtype, sizeof(int));
position += sizeof(int);
int length=mCaptureList.size();
memcpy(&wkb[position], &length, sizeof(int));
position += sizeof(int);
double x,y;
for(QList<QgsPoint>::iterator it=mCaptureList.begin();it!=mCaptureList.end();++it)
{
QgsPoint savePoint = *it;
x = savePoint.x();
y = savePoint.y();
memcpy(&wkb[position],&x,sizeof(double));
position+=sizeof(double);
memcpy(&wkb[position],&y,sizeof(double));
position+=sizeof(double);
}
}
else
{
QMessageBox::critical(0, QObject::tr("Error"), QObject::tr("Cannot add feature. Unknown WKB type"));
return; //unknown wkbtype
}
f->setGeometryAndOwnership(&wkb[0],size);
}
else // polygon
{
if(layerWKBType == QGis::WKBPolygon)
{
size=1+3*sizeof(int)+2*(mCaptureList.size()+1)*sizeof(double);
wkb= new unsigned char[size];
int wkbtype=QGis::WKBPolygon;
int length=mCaptureList.size()+1;//+1 because the first point is needed twice
int numrings=1;
memcpy(&wkb[0],&end,1);
memcpy(&wkb[1],&wkbtype, sizeof(int));
memcpy(&wkb[1+sizeof(int)],&numrings,sizeof(int));
memcpy(&wkb[1+2*sizeof(int)],&length, sizeof(int));
int position=1+3*sizeof(int);
double x,y;
QList<QgsPoint>::iterator it;
for(it=mCaptureList.begin();it!=mCaptureList.end();++it)
{
QgsPoint savePoint = *it;
x = savePoint.x();
y = savePoint.y();
memcpy(&wkb[position],&x,sizeof(double));
position+=sizeof(double);
memcpy(&wkb[position],&y,sizeof(double));
position+=sizeof(double);
}
// close the polygon
it=mCaptureList.begin();
QgsPoint savePoint = *it;
x = savePoint.x();
y = savePoint.y();
memcpy(&wkb[position],&x,sizeof(double));
position+=sizeof(double);
memcpy(&wkb[position],&y,sizeof(double));
}
else if(layerWKBType == QGis::WKBMultiPolygon)
{
size = 2+5*sizeof(int)+2*(mCaptureList.size()+1)*sizeof(double);
wkb = new unsigned char[size];
int wkbtype = QGis::WKBMultiPolygon;
int polygontype = QGis::WKBPolygon;
int length = mCaptureList.size()+1;//+1 because the first point is needed twice
int numrings = 1;
int numpolygons = 1;
int position = 0; //pointer position relative to &wkb[0]
memcpy(&wkb[position],&end,1);
position += 1;
memcpy(&wkb[position],&wkbtype, sizeof(int));
position += sizeof(int);
memcpy(&wkb[position], &numpolygons, sizeof(int));
position += sizeof(int);
memcpy(&wkb[position], &end, 1);
position += 1;
memcpy(&wkb[position], &polygontype, sizeof(int));
position += sizeof(int);
memcpy(&wkb[position], &numrings, sizeof(int));
position += sizeof(int);
memcpy(&wkb[position], &length, sizeof(int));
position += sizeof(int);
double x,y;
QList<QgsPoint>::iterator it;
for(it=mCaptureList.begin();it!=mCaptureList.end();++it)//add the captured points to the polygon
{
QgsPoint savePoint = *it;
x = savePoint.x();
y = savePoint.y();
memcpy(&wkb[position],&x,sizeof(double));
position+=sizeof(double);
memcpy(&wkb[position],&y,sizeof(double));
position+=sizeof(double);
}
// close the polygon
it=mCaptureList.begin();
QgsPoint savePoint = *it;
x = savePoint.x();
y = savePoint.y();
memcpy(&wkb[position],&x,sizeof(double));
position+=sizeof(double);
memcpy(&wkb[position],&y,sizeof(double));
}
else
{
QMessageBox::critical(0, QObject::tr("Error"), QObject::tr("Cannot add feature. Unknown WKB type"));
return; //unknown wkbtype
}
f->setGeometryAndOwnership(&wkb[0],size);
//is automatic polygon intersection removal activated?
int avoidPolygonIntersections = QgsProject::instance()->readNumEntry("Digitizing", "/AvoidPolygonIntersections", 0);
if(avoidPolygonIntersections != 0)
{
if(vlayer->removePolygonIntersections(f->geometry()) != 0)
{
QMessageBox::critical(0, QObject::tr("Error"), QObject::tr("Could not remove polygon intersection"));
}
}
}
}
delete f;
delete mypDialog;
// delete the elements of mCaptureList
mCaptureList.clear();
mCanvas->refresh();
}
}
// add the fields to the QgsFeature
const QgsFieldMap fields = vlayer->pendingFields();
for(QgsFieldMap::const_iterator it = fields.begin(); it != fields.end(); ++it)
{
f->addAttribute(it.key(), provider->getDefaultValue(it.key()));
}
QgsAttributeDialog * mypDialog = new QgsAttributeDialog( vlayer, f );
if (mypDialog->exec())
{
if(vlayer->addFeature(*f))
{
//add points to other features to keep topology up-to-date
int topologicalEditing = QgsProject::instance()->readNumEntry("Digitizing", "/TopologicalEditing", 0);
if(topologicalEditing)
{
vlayer->addTopologicalPoints(f->geometry());
}
}
}
delete f;
delete mypDialog;
// delete the elements of mCaptureList
mCaptureList.clear();
mCanvas->refresh();
}
}
}

View File

@ -31,6 +31,7 @@
#include "qgsspatialrefsys.h"
#include "qgsvectordataprovider.h"
#include "qgsvectorlayer.h"
#include "qgsattributedialog.h"
#include <QSettings>
#include <QMessageBox>
@ -73,7 +74,7 @@ void QgsMapToolIdentify::canvasReleaseEvent(QMouseEvent * e)
return;
}
QgsMapLayer* layer = mCanvas->currentLayer();
mLayer = mCanvas->currentLayer();
// delete rubber band if there was any
delete mRubberBand;
@ -81,31 +82,31 @@ void QgsMapToolIdentify::canvasReleaseEvent(QMouseEvent * e)
// call identify method for selected layer
if (layer)
if (mLayer)
{
// In the special case of the WMS provider,
// coordinates are sent back to the server as pixel coordinates
// not the layer's native CRS. So identify on screen coordinates!
if (
(layer->type() == QgsMapLayer::RASTER)
(mLayer->type() == QgsMapLayer::RASTER)
&&
(dynamic_cast<QgsRasterLayer*>(layer)->providerKey() == "wms")
(dynamic_cast<QgsRasterLayer*>(mLayer)->providerKey() == "wms")
)
{
identifyRasterWmsLayer(dynamic_cast<QgsRasterLayer*>(layer), QgsPoint(e->x(), e->y()) );
identifyRasterWmsLayer( QgsPoint(e->x(), e->y()) );
}
else
{
// convert screen coordinates to map coordinates
QgsPoint idPoint = mCanvas->getCoordinateTransform()->toMapCoordinates(e->x(), e->y());
if (layer->type() == QgsMapLayer::VECTOR)
if (mLayer->type() == QgsMapLayer::VECTOR)
{
identifyVectorLayer(dynamic_cast<QgsVectorLayer*>(layer), idPoint);
identifyVectorLayer(idPoint);
}
else if (layer->type() == QgsMapLayer::RASTER)
else if (mLayer->type() == QgsMapLayer::RASTER)
{
identifyRasterLayer(dynamic_cast<QgsRasterLayer*>(layer), idPoint);
identifyRasterLayer(idPoint);
}
else
{
@ -127,8 +128,9 @@ void QgsMapToolIdentify::canvasReleaseEvent(QMouseEvent * e)
}
void QgsMapToolIdentify::identifyRasterLayer(QgsRasterLayer* layer, const QgsPoint& point)
void QgsMapToolIdentify::identifyRasterLayer(const QgsPoint& point)
{
QgsRasterLayer *layer = dynamic_cast<QgsRasterLayer*>(mLayer);
if (!layer)
return;
@ -140,7 +142,7 @@ void QgsMapToolIdentify::identifyRasterLayer(QgsRasterLayer* layer, const QgsPoi
QgsAttributeAction aa;
mResults = new QgsIdentifyResults(aa, mCanvas->window());
mResults->setAttribute(Qt::WA_DeleteOnClose);
// Be informed when the dialog box is closed so that we can stop using it.
// Be informed when the dialog box is closed so that we can stop using it.
connect(mResults, SIGNAL(accepted()), this, SLOT(resultsDialogGone()));
connect(mResults, SIGNAL(rejected()), this, SLOT(resultsDialogGone()));
mResults->restorePosition();
@ -166,8 +168,9 @@ void QgsMapToolIdentify::identifyRasterLayer(QgsRasterLayer* layer, const QgsPoi
}
void QgsMapToolIdentify::identifyRasterWmsLayer(QgsRasterLayer* layer, const QgsPoint& point)
void QgsMapToolIdentify::identifyRasterWmsLayer(const QgsPoint& point)
{
QgsRasterLayer *layer = dynamic_cast<QgsRasterLayer*>(mLayer);
if (!layer)
{
return;
@ -193,7 +196,7 @@ void QgsMapToolIdentify::identifyRasterWmsLayer(QgsRasterLayer* layer, const Qgs
if(xMinView < xMinLayer)
{
i = (int)(point.x() - (xMinLayer - xMinView) / mupp);
i = (int)(point.x() - (xMinLayer - xMinView) / mupp);
}
else
{
@ -214,7 +217,7 @@ void QgsMapToolIdentify::identifyRasterWmsLayer(QgsRasterLayer* layer, const Qgs
if (text.isEmpty())
{
showError(layer);
showError();
return;
}
@ -225,8 +228,9 @@ void QgsMapToolIdentify::identifyRasterWmsLayer(QgsRasterLayer* layer, const Qgs
viewer->showMessage(); // deletes itself on close
}
void QgsMapToolIdentify::identifyVectorLayer(QgsVectorLayer* layer, const QgsPoint& point)
void QgsMapToolIdentify::identifyVectorLayer(const QgsPoint& point)
{
QgsVectorLayer *layer = dynamic_cast<QgsVectorLayer*>(mLayer);
if (!layer)
return;
@ -250,8 +254,7 @@ void QgsMapToolIdentify::identifyVectorLayer(QgsVectorLayer* layer, const QgsPoi
//QgsFeature feat;
QgsAttributeAction& actions = *layer->actions();
QString fieldIndex = layer->displayField();
QgsVectorDataProvider* dataProvider = layer->getDataProvider();
const QgsFieldMap& fields = dataProvider->fields();
const QgsFieldMap& fields = layer->pendingFields();
// init distance/area calculator
QgsDistanceArea calc;
@ -259,6 +262,22 @@ void QgsMapToolIdentify::identifyVectorLayer(QgsVectorLayer* layer, const QgsPoi
calc.setEllipsoid(ellipsoid);
calc.setSourceSRS(layer->srs().srsid());
mFeatureList.clear();
QApplication::setOverrideCursor(Qt::WaitCursor);
layer->select(layer->pendingAllAttributesList(), r, true);
QgsFeature f;
while( layer->getNextFeature(f) )
mFeatureList << f;
QApplication::restoreOverrideCursor();
if( layer->isEditable() && mFeatureList.size()==1 )
{
editFeature(mFeatureList[0]);
return;
}
// display features falling within the search radius
if(!mResults)
{
@ -268,6 +287,8 @@ void QgsMapToolIdentify::identifyVectorLayer(QgsVectorLayer* layer, const QgsPoi
connect(mResults, SIGNAL(accepted()), this, SLOT(resultsDialogGone()));
connect(mResults, SIGNAL(rejected()), this, SLOT(resultsDialogGone()));
connect(mResults, SIGNAL(selectedFeatureChanged(int)), this, SLOT(highlightFeature(int)));
connect(mResults, SIGNAL(editFeature(int)), this, SLOT(editFeature(int)));
// restore the identify window position and show it
mResults->restorePosition();
}
@ -281,12 +302,9 @@ void QgsMapToolIdentify::identifyVectorLayer(QgsVectorLayer* layer, const QgsPoi
QApplication::setOverrideCursor(Qt::WaitCursor);
int lastFeatureId = 0;
QgsFeatureList::iterator f_it = mFeatureList.begin();
QList<QgsFeature> featureList;
layer->featuresInRectangle(r, featureList, true, true);
QList<QgsFeature>::iterator f_it = featureList.begin();
for(; f_it != featureList.end(); ++f_it)
for(; f_it != mFeatureList.end(); ++f_it)
{
featureCount++;
@ -294,6 +312,10 @@ void QgsMapToolIdentify::identifyVectorLayer(QgsVectorLayer* layer, const QgsPoi
featureNode->setData(0, Qt::UserRole, QVariant(f_it->featureId())); // save feature id
lastFeatureId = f_it->featureId();
featureNode->setText(0, fieldIndex);
if( layer->isEditable() )
mResults->addEdit( featureNode, f_it->featureId() );
const QgsAttributeMap& attr = f_it->attributeMap();
for (QgsAttributeMap::const_iterator it = attr.begin(); it != attr.end(); ++it)
@ -340,13 +362,12 @@ void QgsMapToolIdentify::identifyVectorLayer(QgsVectorLayer* layer, const QgsPoi
mResults->addDerivedAttribute(featureNode, "Y", str);
}
// Add actions
// Add actions
QgsAttributeAction::aIter iter = actions.begin();
for (register int i = 0; iter != actions.end(); ++iter, ++i)
{
mResults->addAction( featureNode, i, QObject::tr("action"), iter->name() );
}
}
QgsDebugMsg("Feature count on identify: " + QString::number(featureCount));
@ -354,7 +375,7 @@ void QgsMapToolIdentify::identifyVectorLayer(QgsVectorLayer* layer, const QgsPoi
//also test the not commited features //todo: eliminate copy past code
mResults->setTitle(layer->name() + " - " + QString::number(featureCount) + QObject::tr(" features found"));
if (featureCount == 1)
if (featureCount == 1)
{
mResults->showAllAttributes();
mResults->setTitle(layer->name() + " - " + QObject::tr(" 1 feature found") );
@ -369,228 +390,14 @@ void QgsMapToolIdentify::identifyVectorLayer(QgsVectorLayer* layer, const QgsPoi
{
QString title = layer->name();
title += QString( tr("- %1 features found","Identify results window title",featureCount) ).arg(featureCount);
mResults->setTitle(title);
mResults->setTitle(title);
}
QApplication::restoreOverrideCursor();
mResults->show();
}
#if 0 //MH: old state of the function
void QgsMapToolIdentify::identifyVectorLayer(QgsVectorLayer* layer, const QgsPoint& point)
{
if (!layer)
return;
// load identify radius from settings
QSettings settings;
double identifyValue = settings.value("/Map/identifyRadius", QGis::DEFAULT_IDENTIFY_RADIUS).toDouble();
QString ellipsoid = settings.readEntry("/qgis/measure/ellipsoid", "WGS84");
// create the search rectangle
double searchRadius = mCanvas->extent().width() * (identifyValue/100.0);
QgsRect r;
r.setXmin(point.x() - searchRadius);
r.setXmax(point.x() + searchRadius);
r.setYmin(point.y() - searchRadius);
r.setYmax(point.y() + searchRadius);
r = toLayerCoords(layer, r);
int featureCount = 0;
QgsFeature feat;
QgsAttributeAction& actions = *layer->actions();
QString fieldIndex = layer->displayField();
QgsVectorDataProvider* dataProvider = layer->getDataProvider();
QgsAttributeList allAttributes = dataProvider->allAttributesList();
const QgsFieldMap& fields = dataProvider->fields();
dataProvider->select(allAttributes, r, true, true);
// init distance/area calculator
QgsDistanceArea calc;
calc.setProjectionsEnabled(mCanvas->projectionsEnabled()); // project?
calc.setEllipsoid(ellipsoid);
calc.setSourceSRS(layer->srs().srsid());
if ( !layer->isEditable() )
{
// display features falling within the search radius
if(!mResults)
{
mResults = new QgsIdentifyResults(actions, mCanvas->window());
mResults->setAttribute(Qt::WA_DeleteOnClose);
// Be informed when the dialog box is closed so that we can stop using it.
connect(mResults, SIGNAL(accepted()), this, SLOT(resultsDialogGone()));
connect(mResults, SIGNAL(rejected()), this, SLOT(resultsDialogGone()));
connect(mResults, SIGNAL(selectedFeatureChanged(int)), this, SLOT(highlightFeature(int)));
// restore the identify window position and show it
mResults->restorePosition();
}
else
{
mResults->raise();
mResults->clear();
mResults->setActions(actions);
}
QApplication::setOverrideCursor(Qt::WaitCursor);
int lastFeatureId = 0;
QTreeWidgetItem *click = mResults->addNode(tr("(clicked coordinate)"));
click->setText(1, point.stringRep());
while (dataProvider->getNextFeature(feat))
{
featureCount++;
QTreeWidgetItem* featureNode = mResults->addNode("foo");
featureNode->setData(0, Qt::UserRole, QVariant(feat.featureId())); // save feature id
lastFeatureId = feat.featureId();
featureNode->setText(0, fieldIndex);
const QgsAttributeMap& attr = feat.attributeMap();
for (QgsAttributeMap::const_iterator it = attr.begin(); it != attr.end(); ++it)
{
//QgsDebugMsg(it->fieldName() + " == " + fieldIndex);
if (fields[it.key()].name() == fieldIndex)
{
featureNode->setText(1, it->toString());
}
mResults->addAttribute(featureNode, fields[it.key()].name(), it->toString());
}
// Calculate derived attributes and insert:
// measure distance or area depending on geometry type
if (layer->vectorType() == QGis::Line)
{
double dist = calc.measure(feat.geometry());
QString str = calc.textUnit(dist, 3, mCanvas->mapUnits(), false);
mResults->addDerivedAttribute(featureNode, QObject::tr("Length"), str);
}
else if (layer->vectorType() == QGis::Polygon)
{
double area = calc.measure(feat.geometry());
QString str = calc.textUnit(area, 3, mCanvas->mapUnits(), true);
mResults->addDerivedAttribute(featureNode, QObject::tr("Area"), str);
}
// Add actions
QgsAttributeAction::aIter iter = actions.begin();
for (register int i = 0; iter != actions.end(); ++iter, ++i)
{
mResults->addAction( featureNode, i, QObject::tr("action"), iter->name() );
}
}
QgsDebugMsg("Feature count on identify: " + QString::number(featureCount));
//also test the not commited features //todo: eliminate copy past code
mResults->setTitle(layer->name() + " - " + QString::number(featureCount) + QObject::tr(" features found"));
if (featureCount == 1)
{
mResults->showAllAttributes();
mResults->setTitle(layer->name() + " - " + QObject::tr(" 1 feature found") );
highlightFeature(lastFeatureId);
}
else if (featureCount == 0)
{
mResults->setTitle(layer->name() + " - " + QObject::tr("No features found") );
mResults->setMessage ( QObject::tr("No features found"), QObject::tr("No features were found in the active layer at the point you clicked") );
}
else
{
QString title = layer->name();
title += QString( tr("- %1 features found","Identify results window title",featureCount) ).arg(featureCount);
mResults->setTitle(title);
}
QApplication::restoreOverrideCursor();
mResults->show();
}
else // ( layer->isEditable() )
{
// Edit attributes
// TODO: what to do if more features were selected? - nearest?
QgsChangedAttributesMap& changedAttributes = layer->changedAttributes();
QApplication::setOverrideCursor(Qt::WaitCursor);
if (dataProvider->getNextFeature(feat))
{
// these are the values to populate the dialog with
// start off with list of committed attribute values
QgsAttributeMap old = feat.attributeMap();
// Test if this feature already changed since the last commit
QgsChangedAttributesMap::iterator it = changedAttributes.find(feat.featureId());
if ( it != changedAttributes.end() )
{
// Yes, this feature already has in-memory attribute changes
// go through and apply the modified-but-not-committed values
QgsAttributeMap oldattr = *it;
int index=0;
for (QgsAttributeMap::const_iterator oldit = old.begin(); oldit != old.end(); ++oldit)
{
QgsAttributeMap::iterator ait = oldattr.find( oldit.key() );
if ( ait != oldattr.end() )
{
// replace the committed value with the
// modified-but-not-committed value
old[index] = *ait;
}
++index;
}
}
QApplication::restoreOverrideCursor();
// Show the attribute value editing dialog
QgsAttributeDialog ad( dataProvider->fields(), old );
if (ad.exec() == QDialog::Accepted)
{
int i = 0;
for (QgsAttributeMap::const_iterator oldit = old.begin(); oldit != old.end(); ++oldit, ++i)
{
// only apply changed values if they were edited by the user
if (ad.isDirty(i))
{
QgsDebugMsg("found a changed attribute: " + QString::number(i) + " = " + ad.value(i));
QgsAttributeMap& chattr = changedAttributes[ feat.featureId() ];
chattr[i] = ad.value(i);
// propagate "dirtyness" to the layer
layer->setModified();
}
}
}
}
else
{
QApplication::restoreOverrideCursor();
QMessageBox::information(0, tr("No features found"),
tr("<p>No features were found within the search radius. "
"Note that it is currently not possible to use the "
"identify tool on unsaved features.</p>"));
}
}
}
#endif
void QgsMapToolIdentify::showError(QgsMapLayer * mapLayer)
void QgsMapToolIdentify::showError()
{
// QMessageBox::warning(
// this,
@ -600,10 +407,10 @@ void QgsMapToolIdentify::showError(QgsMapLayer * mapLayer)
// );
QgsMessageViewer * mv = new QgsMessageViewer();
mv->setWindowTitle( mapLayer->errorCaptionString() );
mv->setWindowTitle( mLayer->errorCaptionString() );
mv->setMessageAsPlainText(
QObject::tr("Could not identify objects on") + " " + mapLayer->name() + " " + QObject::tr("because") + ":\n" +
mapLayer->errorString()
QObject::tr("Could not identify objects on") + " " + mLayer->name() + " " + QObject::tr("because") + ":\n" +
mLayer->errorString()
);
mv->exec(); // deletes itself on close
}
@ -625,7 +432,7 @@ void QgsMapToolIdentify::deactivate()
void QgsMapToolIdentify::highlightFeature(int featureId)
{
QgsVectorLayer* layer = dynamic_cast<QgsVectorLayer*>(mCanvas->currentLayer());
QgsVectorLayer* layer = dynamic_cast<QgsVectorLayer*>(mLayer);
if (!layer)
return;
@ -653,3 +460,41 @@ void QgsMapToolIdentify::highlightFeature(int featureId)
mRubberBand->show();
}
}
void QgsMapToolIdentify::editFeature(int featureId)
{
for(QgsFeatureList::iterator it=mFeatureList.begin(); it!=mFeatureList.end(); it++)
{
if( it->featureId() == featureId )
{
editFeature( *it );
break;
}
}
}
void QgsMapToolIdentify::editFeature(QgsFeature &f)
{
QgsVectorLayer* layer = dynamic_cast<QgsVectorLayer*>(mLayer);
if (!layer)
return;
if (!layer->isEditable() )
return;
QgsAttributeMap src = f.attributeMap();
QgsAttributeDialog *ad = new QgsAttributeDialog(layer, &f);
if (ad->exec())
{
const QgsAttributeMap &dst = f.attributeMap();
for(QgsAttributeMap::const_iterator it=dst.begin(); it!=dst.end(); it++)
{
if( !src.contains( it.key() ) || it.value()!=src[it.key()] )
layer->changeAttributeValue( f.featureId(), it.key(), it.value().toString() );
}
}
delete ad;
mCanvas->refresh();
}

View File

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

View File

@ -56,65 +56,65 @@ void QgsMapToolMoveFeature::canvasPressEvent(QMouseEvent * e)
QgsVectorLayer* vlayer = currentVectorLayer();
if(!vlayer)
{
return;
}
{
return;
}
if(!vlayer->isEditable())
{
QMessageBox::information(0, QObject::tr("Layer not editable"), \
QObject::tr("Cannot edit the vector layer. To make it editable, go to the file item " \
"of the layer, right click and check 'Allow Editing'."));
return;
}
{
QMessageBox::information(0, QObject::tr("Layer not editable"),
QObject::tr("Cannot edit the vector layer. To make it editable, go to the file item "
"of the layer, right click and check 'Allow Editing'."));
return;
}
//find first geometry under mouse cursor and store iterator to it
QgsPoint layerCoords = toLayerCoords((QgsMapLayer*)vlayer, e->pos());
QSettings settings;
double searchRadius = settings.value("/qgis/digitizing/search_radius_vertex_edit", 10).toDouble();
QgsRect selectRect(layerCoords.x()-searchRadius, layerCoords.y()-searchRadius, \
layerCoords.x()+searchRadius, layerCoords.y()+searchRadius);
QgsRect selectRect(layerCoords.x()-searchRadius, layerCoords.y()-searchRadius,
layerCoords.x()+searchRadius, layerCoords.y()+searchRadius);
QList<QgsFeature> featureList;
vlayer->featuresInRectangle(selectRect, featureList, true, false);
if(featureList.size() > 0)
vlayer->select(QgsAttributeList(), selectRect, true);
//find the closest feature
QgsGeometry* pointGeometry = QgsGeometry::fromPoint(layerCoords);
if(!pointGeometry)
{
return;
}
double minDistance = std::numeric_limits<double>::max();
QgsFeature cf;
QgsFeature f;
while( vlayer->getNextFeature(f) )
{
if(f.geometry())
{
//find the closest feature
QgsGeometry* pointGeometry = QgsGeometry::fromPoint(layerCoords);
if(!pointGeometry)
{
return;
}
QList<QgsFeature>::iterator closestFeatureIt;
double minDistance = std::numeric_limits<double>::max();
double currentDistance;
QList<QgsFeature>::iterator it = featureList.begin();
for(; it != featureList.end(); ++it)
{
if(it->geometry())
{
currentDistance = pointGeometry->distance(*(it->geometry()));
if(currentDistance < minDistance)
{
minDistance = currentDistance;
closestFeatureIt = it;
}
}
}
mStartPointMapCoords = toMapCoords(e->pos());
mMovedFeature = closestFeatureIt->featureId(); //todo: take the closest feature, not the first one...
mRubberBand = createRubberBand();
mRubberBand->setToGeometry(closestFeatureIt->geometry(), *vlayer);
mRubberBand->setColor(Qt::red);
mRubberBand->setWidth(2);
mRubberBand->show();
delete pointGeometry;
double currentDistance = pointGeometry->distance(*f.geometry());
if(currentDistance < minDistance)
{
minDistance = currentDistance;
cf = f;
}
}
}
if( minDistance==std::numeric_limits<double>::max() )
{
return;
}
mStartPointMapCoords = toMapCoords(e->pos());
mMovedFeature = cf.featureId(); //todo: take the closest feature, not the first one...
mRubberBand = createRubberBand();
mRubberBand->setToGeometry( cf.geometry(), *vlayer);
mRubberBand->setColor(Qt::red);
mRubberBand->setWidth(2);
mRubberBand->show();
delete pointGeometry;
}
void QgsMapToolMoveFeature::canvasReleaseEvent(QMouseEvent * e)

View File

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

View File

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

View File

@ -43,10 +43,9 @@
static long DEFAULT_WMS_EPSG = 4326; // WGS 84
QgsServerSourceSelect::QgsServerSourceSelect(QgisApp * app, QWidget * parent, Qt::WFlags fl)
QgsServerSourceSelect::QgsServerSourceSelect(QWidget * parent, Qt::WFlags fl)
: QDialog(parent, fl),
m_Epsg(DEFAULT_WMS_EPSG),
qgisApp(app),
mWmsProvider(0)
{
setupUi(this);

View File

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

View File

@ -19,6 +19,7 @@
#include <memory>
#include "qgisapp.h"
#include "qgsapplication.h"
#include "qgsattributeactiondialog.h"
#include "qgscontexthelp.h"
@ -32,7 +33,6 @@
#include "qgsproject.h"
#include "qgssinglesymboldialog.h"
#include "qgsuniquevaluedialog.h"
#include "qgsvectordataprovider.h"
#include "qgsvectorlayer.h"
#include "qgsvectorlayerproperties.h"
#include "qgsconfig.h"
@ -48,15 +48,18 @@
#include <QFileDialog>
#include <QFileInfo>
#include <QSettings>
#include <QComboBox>
#include <QCheckBox>
#if QT_VERSION < 0x040300
#define toPlainText() text()
#endif
QgsVectorLayerProperties::QgsVectorLayerProperties(QgsVectorLayer * lyr,
QWidget * parent,
Qt::WFlags fl)
QgsVectorLayerProperties::QgsVectorLayerProperties(
QgsVectorLayer *lyr,
QWidget * parent,
Qt::WFlags fl)
: QDialog(parent, fl),
layer(lyr),
mRendererDialog(0)
@ -66,6 +69,21 @@ QgsVectorLayerProperties::QgsVectorLayerProperties(QgsVectorLayer * lyr,
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
connect(buttonBox->button(QDialogButtonBox::Apply), SIGNAL(clicked()), this, SLOT(apply()));
connect(this, SIGNAL(accepted()), this, SLOT(apply()));
connect(mAddAttributeButton, SIGNAL(clicked()), this, SLOT(addAttribute()));
connect(mDeleteAttributeButton, SIGNAL(clicked()), this, SLOT(deleteAttribute()));
connect(mToggleEditingButton, SIGNAL(clicked()), this, SLOT(toggleEditing()));
connect(this, SIGNAL(toggleEditing(QgsMapLayer*)),
QgisApp::instance(), SLOT(toggleEditing(QgsMapLayer*)));
connect(layer, SIGNAL(editingStarted()), this, SLOT(editingToggled()));
connect(layer, SIGNAL(editingStopped()), this, SLOT(editingToggled()));
connect(layer, SIGNAL(attributeAdded(int)), this, SLOT(attributeAdded(int)));
connect(layer, SIGNAL(attributeDeleted(int)), this, SLOT(attributeDeleted(int)));
mAddAttributeButton->setIcon(QgisApp::getThemeIcon("/mActionNewAttribute.png"));
mDeleteAttributeButton->setIcon(QgisApp::getThemeIcon("/mActionDeleteAttribute.png"));
mToggleEditingButton->setIcon(QgisApp::getThemeIcon("/mActionToggleEditing.png"));
// Create the Label dialog tab
QVBoxLayout *layout = new QVBoxLayout( labelOptionsFrame );
@ -73,18 +91,31 @@ QgsVectorLayerProperties::QgsVectorLayerProperties(QgsVectorLayer * lyr,
labelDialog = new QgsLabelDialog ( layer->label(), labelOptionsFrame);
layout->addWidget( labelDialog );
labelOptionsFrame->setLayout(layout);
connect(labelDialog, SIGNAL(labelSourceSet()),
this, SLOT(setLabelCheckBox()));
connect(labelDialog, SIGNAL(labelSourceSet()), this, SLOT(setLabelCheckBox()));
// Create the Actions dialog tab
QgsVectorDataProvider *dp = dynamic_cast<QgsVectorDataProvider *>(layer->getDataProvider());
QVBoxLayout *actionLayout = new QVBoxLayout( actionOptionsFrame );
actionLayout->setMargin(0);
QgsFieldMap fields = dp->fields();
actionDialog = new QgsAttributeActionDialog ( layer->actions(), fields,
actionOptionsFrame );
const QgsFieldMap &fields = layer->pendingFields();
actionDialog = new QgsAttributeActionDialog ( layer->actions(), fields, actionOptionsFrame );
actionLayout->addWidget( actionDialog );
tblAttributes->setColumnCount(8);
tblAttributes->setRowCount( fields.size() );
tblAttributes->setHorizontalHeaderItem( 0, new QTableWidgetItem( tr("id") ) );
tblAttributes->setHorizontalHeaderItem( 1, new QTableWidgetItem( tr("name") ) );
tblAttributes->setHorizontalHeaderItem( 2, new QTableWidgetItem( tr("type") ) );
tblAttributes->setHorizontalHeaderItem( 3, new QTableWidgetItem( tr("length") ) );
tblAttributes->setHorizontalHeaderItem( 4, new QTableWidgetItem( tr("precision") ) );
tblAttributes->setHorizontalHeaderItem( 5, new QTableWidgetItem( tr("comment") ) );
tblAttributes->setHorizontalHeaderItem( 6, new QTableWidgetItem( tr("edit widget") ) );
tblAttributes->setHorizontalHeaderItem( 7, new QTableWidgetItem( tr("values") ) );
tblAttributes->setSelectionBehavior( QAbstractItemView::SelectRows );
tblAttributes->setSelectionMode( QAbstractItemView::MultiSelection );
loadRows();
reset();
if(layer->getDataProvider())//enable spatial index button group if supported by provider
{
@ -95,18 +126,169 @@ QgsVectorLayerProperties::QgsVectorLayerProperties(QgsVectorLayer * lyr,
}
}
updateButtons();
leSpatialRefSys->setText(layer->srs().proj4String());
leSpatialRefSys->setCursorPosition(0);
connect(sliderTransparency, SIGNAL(valueChanged(int)), this, SLOT(sliderTransparency_valueChanged(int)));
tabWidget->setCurrentIndex(0);
} // QgsVectorLayerProperties ctor
void QgsVectorLayerProperties::loadRows()
{
const QgsFieldMap &fields = layer->pendingFields();
int row=0;
for(QgsFieldMap::const_iterator it=fields.begin(); it!=fields.end(); it++, row++)
setRow( row, it.key(), it.value() );
tblAttributes->resizeColumnsToContents();
}
void QgsVectorLayerProperties::setRow(int row, int idx, const QgsField &field)
{
tblAttributes->setItem(row, 0, new QTableWidgetItem( QString::number(idx) ) );
tblAttributes->setItem(row, 1, new QTableWidgetItem( field.name() ) );
tblAttributes->setItem(row, 2, new QTableWidgetItem( field.typeName() ) );
tblAttributes->setItem(row, 3, new QTableWidgetItem( QString::number( field.length() ) ) );
tblAttributes->setItem(row, 4, new QTableWidgetItem( QString::number( field.precision() ) ) );
tblAttributes->setItem(row, 5, new QTableWidgetItem( field.comment() ) );
for(int i=0; i<6; i++)
tblAttributes->item(row, i)->setFlags( tblAttributes->item(row, i)->flags() & ~Qt::ItemIsEditable );
QComboBox *cb = new QComboBox();
cb->addItem( tr("line edit"), QgsVectorLayer::LineEdit);
cb->addItem( tr("unique values"), QgsVectorLayer::UniqueValues);
cb->addItem( tr("unique values (editable)"), QgsVectorLayer::UniqueValuesEditable);
cb->addItem( tr("value map"), QgsVectorLayer::ValueMap);
cb->addItem( tr("classification"), QgsVectorLayer::Classification);
cb->addItem( tr("range"), QgsVectorLayer::Range);
cb->setSizeAdjustPolicy(QComboBox::AdjustToContentsOnFirstShow);
cb->setCurrentIndex( layer->editType( idx ) );
tblAttributes->setCellWidget(row, 6, cb );
if( layer->editType(idx)==QgsVectorLayer::ValueMap )
{
// TODO: create a gui for value maps
QStringList mapList;
QMap<QString, QVariant> &map = layer->valueMap( idx );
for(QMap<QString, QVariant>::iterator mit=map.begin(); mit!=map.end(); mit++)
{
QgsDebugMsg( QString("idx:%1 key:%2 value:%3").arg( idx ).arg( mit.key() ).arg( mit.value().toString() ) );
if( mit.value().isNull() )
mapList << mit.key();
else
mapList << QString( "%1=%2" ).arg( mit.key() ).arg( mit.value().toString() );
}
tblAttributes->setItem(row, 7, new QTableWidgetItem( mapList.join(";") ) );
} else if( layer->editType(idx)==QgsVectorLayer::Range ) {
tblAttributes->setItem(
row, 7,
new QTableWidgetItem( QString("%1;%2;%3")
.arg( layer->range(idx).mMin.toString() )
.arg( layer->range(idx).mMax.toString() )
.arg( layer->range(idx).mStep.toString() )
)
);
}
}
QgsVectorLayerProperties::~QgsVectorLayerProperties()
{
disconnect(labelDialog, SIGNAL(labelSourceSet()),
this, SLOT(setLabelCheckBox()));
disconnect(labelDialog, SIGNAL(labelSourceSet()), this, SLOT(setLabelCheckBox()));
}
void QgsVectorLayerProperties::toggleEditing()
{
emit toggleEditing(layer);
}
void QgsVectorLayerProperties::attributeAdded(int idx)
{
const QgsFieldMap &fields = layer->pendingFields();
int row = tblAttributes->rowCount();
tblAttributes->insertRow(row);
setRow(row, idx, fields[idx]);
tblAttributes->setCurrentCell(row, idx, QItemSelectionModel::NoUpdate);
}
void QgsVectorLayerProperties::attributeDeleted(int idx)
{
for(int i=0; i<tblAttributes->rowCount(); i++)
{
if( tblAttributes->item(i, 0)->text().toInt()==idx )
{
tblAttributes->removeRow(i);
break;
}
}
}
void QgsVectorLayerProperties::addAttribute()
{
QgsAddAttrDialog dialog(layer->getDataProvider(), this);
if(dialog.exec()==QDialog::Accepted)
{
if(!addAttribute(dialog.name(),dialog.type()))
{
QMessageBox::information(this,tr("Name conflict"),tr("The attribute could not be inserted. The name already exists in the table."));
}
}
}
bool QgsVectorLayerProperties::addAttribute(QString name, QString type)
{
QgsDebugMsg("inserting attribute " + name + " of type " + type );
return layer->addAttribute( name, type );
}
void QgsVectorLayerProperties::deleteAttribute()
{
QList<QTableWidgetItem*> items = tblAttributes->selectedItems();
QList<int> idxs;
for(QList<QTableWidgetItem*>::const_iterator it=items.begin(); it!=items.end(); it++)
{
if( (*it)->column()==0 )
idxs << (*it)->text().toInt();
}
for(QList<int>::const_iterator it=idxs.begin(); it!=idxs.end(); it++)
layer->deleteAttribute(*it);
}
void QgsVectorLayerProperties::editingToggled()
{
if( layer->isEditable() )
loadRows();
updateButtons();
}
void QgsVectorLayerProperties::updateButtons()
{
if ( layer->isEditable() )
{
int cap = layer->getDataProvider()->capabilities();
mAddAttributeButton->setEnabled( cap & QgsVectorDataProvider::AddAttributes );
mDeleteAttributeButton->setEnabled( cap & QgsVectorDataProvider::DeleteAttributes );
mToggleEditingButton->setChecked( true );
}
else
{
mAddAttributeButton->setEnabled( false );
mDeleteAttributeButton->setEnabled( false );
mToggleEditingButton->setChecked( false );
}
}
void QgsVectorLayerProperties::sliderTransparency_valueChanged(int theValue)
{
//set the transparency percentage label to a suitable value
@ -167,8 +349,6 @@ void QgsVectorLayerProperties::reset( void )
"layer is shown here. This is currently only supported for PostgreSQL "
"layers. To enter or modify the query, click on the Query Builder button"));
//we are dealing with a pg layer here so that we can enable the sql box
QgsVectorDataProvider *dp = dynamic_cast<QgsVectorDataProvider *>(layer->getDataProvider());
//see if we are dealing with a pg layer here
if(layer->providerType() == "postgres")
{
@ -188,7 +368,7 @@ void QgsVectorLayerProperties::reset( void )
}
//get field list for display field combo
const QgsFieldMap& myFields = dp->fields();
const QgsFieldMap& myFields = layer->pendingFields();
for (QgsFieldMap::const_iterator it = myFields.begin(); it != myFields.end(); ++it)
{
displayFieldComboBox->addItem( it->name() );
@ -249,7 +429,7 @@ void QgsVectorLayerProperties::reset( void )
SLOT(alterLayerDialog(const QString &)));
// reset fields in label dialog
layer->label()->setFields ( layer->getDataProvider()->fields() );
layer->label()->setFields ( layer->pendingFields() );
//set the metadata contents
QString myStyle = QgsApplication::reportStyleSheet();
@ -311,6 +491,69 @@ void QgsVectorLayerProperties::apply()
layer->setLabelOn(labelCheckBox->isChecked());
layer->setLayerName(displayName());
for(int i=0; i<tblAttributes->rowCount(); i++)
{
int idx = tblAttributes->item(i, 0)->text().toInt();
const QgsField &field = layer->pendingFields()[idx];
QgsVectorLayer::EditType editType = layer->editType(idx);
QComboBox *cb = dynamic_cast<QComboBox*>( tblAttributes->cellWidget(i, 6) );
if(!cb)
continue;
layer->setEditType( idx, (QgsVectorLayer::EditType) cb->itemData( cb->currentIndex() ).toInt() );
if( editType==QgsVectorLayer::ValueMap )
{
QMap<QString, QVariant> &map = layer->valueMap(idx);
map.clear();
QString value = tblAttributes->item(i, 7)->text();
if( !value.isEmpty() )
{
QStringList values = tblAttributes->item(i, 7)->text().split(";");
for(int j=0; j<values.size(); j++)
{
QStringList args = values[j].split("=");
QVariant value;
if(args.size()==1 || (args.size()==2 && args[0]==args[1]))
{
QgsDebugMsg( QString("idx:%1 key:%2 value:%2").arg(idx).arg(args[0]) );
value = args[0];
}
else if(args.size()==2)
{
QgsDebugMsg( QString("idx:%1 key:%2 value:%3").arg( idx ).arg( args[0] ).arg( args[1] ) );
value = args[1];
}
if( value.canConvert( field.type() ) )
{
map.insert( args[0], value );
}
}
}
} else if( editType==QgsVectorLayer::Range ) {
QStringList values = tblAttributes->item(i, 7)->text().split(";");
if( values.size()==3 ) {
QVariant min = values[0];
QVariant max = values[1];
QVariant step = values[2];
if( min.canConvert(field.type()) &&
max.canConvert(field.type()) &&
step.canConvert(field.type()) )
{
min.convert( field.type() );
max.convert( field.type() );
step.convert( field.type() );
layer->range(idx) = QgsVectorLayer::RangeData(min,max,step);
}
}
}
}
QgsSingleSymbolDialog *sdialog =
dynamic_cast < QgsSingleSymbolDialog * >(widgetStackRenderers->currentWidget());
@ -354,11 +597,8 @@ void QgsVectorLayerProperties::on_pbnQueryBuilder_clicked()
// launch the query builder using the PostgreSQL connection
// from the provider
// get the data provider
QgsVectorDataProvider *dp =
dynamic_cast<QgsVectorDataProvider *>(layer->getDataProvider());
// cast to postgres provider type
QgsPostgresProvider * myPGProvider = (QgsPostgresProvider *) dp;
// cast to postgres provider type
QgsPostgresProvider * myPGProvider = (QgsPostgresProvider *) layer->getDataProvider() ; // FIXME use dynamic cast
// create the query builder object using the table name
// and postgres connection from the provider
QgsDataSourceURI uri(myPGProvider->dataSourceUri());
@ -541,7 +781,7 @@ QString QgsVectorLayerProperties::getMetadata()
}
#if 0
//
// Add the info about each field in the attribute table
//
@ -569,8 +809,7 @@ QString QgsVectorLayerProperties::getMetadata()
myMetadata += "</th>";
//get info for each field by looping through them
QgsVectorDataProvider *myDataProvider = dynamic_cast<QgsVectorDataProvider *>(layer->getDataProvider());
const QgsFieldMap& myFields = myDataProvider->fields();
const QgsFieldMap& myFields = layer->pendingFields();
for (QgsFieldMap::const_iterator it = myFields.begin(); it != myFields.end(); ++it)
{
const QgsField& myField = *it;
@ -594,15 +833,17 @@ QString QgsVectorLayerProperties::getMetadata()
//close field list
myMetadata += "</table>"; //end of nested table
#endif
myMetadata += "</td></tr>"; //end of stats container table row
//
// Close the table
//
myMetadata += "</table>";
myMetadata += "</body></html>";
return myMetadata;
}

View File

@ -23,15 +23,20 @@
#include "ui_qgsvectorlayerpropertiesbase.h"
#include "qgisgui.h"
#include "qgsrenderer.h"
#include "qgsaddattrdialog.h"
#include "qgsdelattrdialog.h"
#include "qgsfield.h"
class QgsMapLayer;
class QgsAttributeActionDialog;
class QgsLabelDialog;
class QgsVectorLayer;
class QgsVectorLayerProperties : public QDialog, private Ui::QgsVectorLayerPropertiesBase{
Q_OBJECT
public:
class QgsVectorLayerProperties : public QDialog, private Ui::QgsVectorLayerPropertiesBase
{
Q_OBJECT;
public:
QgsVectorLayerProperties(QgsVectorLayer *lyr = 0,QWidget *parent = 0, Qt::WFlags fl = QgisGui::ModalDialogFlags);
~QgsVectorLayerProperties();
/**Sets the legend type to "single symbol", "graduated symbol" or "continuous color"*/
@ -42,19 +47,42 @@ class QgsVectorLayerProperties : public QDialog, private Ui::QgsVectorLayerPrope
/**Sets the attribute that is used in the Identify Results dialog box*/
void setDisplayField(QString name);
public slots:
/**Adds an attribute to the table (but does not commit it yet)
@param name attribute name
@param type attribute type
@return false in case of a name conflict, true in case of success*/
bool addAttribute(QString name, QString type);
/**Deletes an attribute (but does not commit it)
@param name attribute name
@return false in case of a non-existing attribute.*/
bool deleteAttribute(int attr);
public slots:
void alterLayerDialog(const QString& string);
/** Reset to original (vector layer) values */
void reset();
/** Get metadata about the layer in nice formatted html */
QString getMetadata();
/** Set transparency based on slider position */
void sliderTransparency_valueChanged(int theValue);
/** Toggles on the label check box */
void setLabelCheckBox();
/** Called when apply button is pressed or dialog is accepted */
void apply();
/** toggle editing of layer */
void toggleEditing();
/** editing of layer was toggled */
void editingToggled();
//
//methods reimplemented from qt designer base class
//
@ -67,13 +95,21 @@ class QgsVectorLayerProperties : public QDialog, private Ui::QgsVectorLayerPrope
void on_pbnSaveDefaultStyle_clicked();
void on_pbnLoadStyle_clicked();
void on_pbnSaveStyleAs_clicked();
signals:
/** emitted when changes to layer were saved to update legend */
void refreshLegend(QString layerID, bool expandItem);
protected:
void addAttribute();
void deleteAttribute();
void attributeAdded(int idx);
void attributeDeleted(int idx);
signals:
/** emitted when changes to layer were saved to update legend */
void refreshLegend(QString layerID, bool expandItem);
void toggleEditing(QgsMapLayer *);
protected:
QgsVectorLayer *layer;
/**Renderer dialog which is shown*/
QDialog* mRendererDialog;
@ -83,14 +119,19 @@ class QgsVectorLayerProperties : public QDialog, private Ui::QgsVectorLayerPrope
QgsLabelDialog* labelDialog;
/**Actions dialog. If apply is pressed, the actions are stored for later use */
QgsAttributeActionDialog* actionDialog;
void updateButtons();
void loadRows();
void setRow(int row, int idx, const QgsField &field);
/**Buffer pixmap which takes the picture of renderers before they are assigned to the vector layer*/
//QPixmap bufferPixmap;
static const int context_id = 94000531;
};
inline QString QgsVectorLayerProperties::displayName()
{
return txtDisplayName->text();
}
#endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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);
/**Prints out a variable/value pair for types with overloaded operator<<*/
template <typename T> static void debug(const QString& var, T val, const char* file = 0, const char* function = 0, \
template <typename T> static void debug(const QString& var, T val, const char* file = 0, const char* function = 0,
int line = -1, int debuglevel = 1)
{
const char* dfile = debugFile();
if(dfile) //exit if QGIS_DEBUG_FILE is set and the message comes from the wrong file
{
const char* dfile = debugFile();
if(dfile) //exit if QGIS_DEBUG_FILE is set and the message comes from the wrong file
{
if(!file || strcmp(dfile, file) != 0)
{
return;
}
}
std::ostringstream os;
os << var.toLocal8Bit().data() << " = " << val;
if(line == -1)
{
qDebug("%s: (%s) %s", file, function, os.str().c_str());
}
else
{
#if defined(_MSC_VER)
qDebug("%s(%d): (%s) %s", file, line, function, os.str().c_str());
#else
qDebug("%s: %d: (%s) %s", file, line, function, os.str().c_str());
#endif
}
if(!file || strcmp(dfile, file) != 0)
{
return;
}
}
std::ostringstream os;
os << var.toLocal8Bit().data() << " = " << val;
if(line == -1)
{
qDebug("%s: (%s) %s", file, function, os.str().c_str());
}
else
{
#if defined(_MSC_VER)
qDebug("%s(%d): (%s) %s", file, line, function, os.str().c_str());
#else
qDebug("%s: %d: (%s) %s", file, line, function, os.str().c_str());
#endif
}
}
/**Goes to qWarning*/
static void warning(const QString& msg);

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

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
const QgsAttributeMap& attrs = f->attributeMap();

View File

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

View File

@ -103,13 +103,13 @@ void QgsSingleSymbolRenderer::renderFeature(QPainter * p, QgsFeature & f, QImage
//first find out the value for the scale classification attribute
const QgsAttributeMap& attrs = f.attributeMap();
fieldScale = sqrt(fabs(attrs[mSymbol->scaleClassificationField()].toDouble()));
QgsDebugMsg(QString("Feature has field scale factor %1").arg(fieldScale));
QgsDebugMsgLevel(QString("Feature has field scale factor %1").arg(fieldScale), 3);
}
if ( mSymbol->rotationClassificationField() >= 0 )
{
const QgsAttributeMap& attrs = f.attributeMap();
rotation = attrs[mSymbol->rotationClassificationField()].toDouble();
QgsDebugMsg(QString("Feature has rotation factor %1").arg(rotation));
QgsDebugMsgLevel(QString("Feature has rotation factor %1").arg(rotation), 3);
}
*img = mSymbol->getPointSymbolAsImage( widthScale, selected, mSelectionColor, fieldScale, rotation, rasterScaleFactor);

View File

@ -34,7 +34,7 @@ class CORE_EXPORT QgsSingleSymbolRenderer: public QgsRenderer
void addSymbol(QgsSymbol* sy);
/*Returns a pointer to mSymbol*/
const QgsSymbol* symbol() const;
/**Renders an OGRFeature*/
/**Renders a feature*/
void renderFeature(QPainter* p, QgsFeature& f, QImage* img, bool selected, double widthScale = 1.0, double rasterScaleFactor = 1.0);
/**Reads the renderer configuration from an XML file
@param rnode the DOM node to read

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
const QgsAttributeMap& attrs = f->attributeMap();

View File

@ -30,7 +30,7 @@ class CORE_EXPORT QgsUniqueValueRenderer: public QgsRenderer
virtual ~QgsUniqueValueRenderer();
/** Determines if a feature will be rendered or not
@param f a pointer to the feature to determine if rendering will happen*/
bool willRenderFeature(QgsFeature *f);
virtual bool willRenderFeature(QgsFeature *f);
void renderFeature(QPainter* p, QgsFeature& f,QImage* img, bool selected, double widthScale = 1.0, double rasterScaleFactor = 1.0);
/**Reads the renderer configuration from an XML file
@param rnode the DOM node to read
@ -64,7 +64,7 @@ class CORE_EXPORT QgsUniqueValueRenderer: public QgsRenderer
/**Symbols for the unique values*/
QMap<QString, QgsSymbol*> mSymbols;
/**Returns the symbol for a feature or 0 if there isn't any*/
QgsSymbol* symbolForFeature(const QgsFeature* f);
QgsSymbol *symbolForFeature(const QgsFeature* f);
/**Cached copy of all underlying symbols required attribute fields*/
QgsAttributeList mSymbolAttributes;
bool mSymbolAttributesDirty; // insertValue was called

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)
{
//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
#include "qgsvectorlayer.h"
#include "qgsfield.h"
class QgisInterface;
class QgsMapCanvas;
@ -490,9 +492,9 @@ public:
* \param qdesc option element in QGIS module description XML file
* \param gdesc GRASS module XML description file
*/
QgsGrassModuleInput ( QgsGrassModule *module,
QgsGrassModuleStandardOptions *options, QString key,
QDomElement &qdesc, QDomElement &gdesc, QDomNode &gnode,
QgsGrassModuleInput ( QgsGrassModule *module,
QgsGrassModuleStandardOptions *options, QString key,
QDomElement &qdesc, QDomElement &gdesc, QDomNode &gnode,
QWidget * parent = 0 );
//! Destructor

View File

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

View File

@ -36,16 +36,6 @@ email : sherman at mrcc.com
#include <QString>
#include <QTextCodec>
//TODO Following ifndef can be removed once WIN32 GEOS support
// is fixed
#ifndef NOWIN32GEOSXXX
//XXX GEOS support on windows is broken until we can get VC++ to
// tolerate geos.h without throwing a bunch of type errors. It
// appears that the windows version of GEOS may be compiled with
// MINGW rather than VC++.
#endif
#include "qgsapplication.h"
#include "qgsdataprovider.h"
#include "qgsfeature.h"
@ -134,13 +124,9 @@ QgsOgrProvider::QgsOgrProvider(QString const & uri)
valid = false;
}
// create the geos objects
geometryFactory = new GEOS_GEOM::GeometryFactory();
assert(geometryFactory!=0);
mSupportedNativeTypes.insert("Integer");
mSupportedNativeTypes.insert("Real");
mSupportedNativeTypes.insert("String");
mSupportedNativeTypes.insert("Integer", QVariant::Int);
mSupportedNativeTypes.insert("Real", QVariant::Double);
mSupportedNativeTypes.insert("String", QVariant::String);
}
QgsOgrProvider::~QgsOgrProvider()
@ -149,7 +135,6 @@ QgsOgrProvider::~QgsOgrProvider()
ogrDataSource = 0;
free(extent_);
extent_ = 0;
delete geometryFactory;
if( mSelectionRectangle )
{
OGR_G_DestroyGeometry( mSelectionRectangle );

View File

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

View File

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

View File

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

View File

@ -13,27 +13,20 @@
<string>Attribute Table</string>
</property>
<property name="windowIcon" >
<iconset/>
<iconset>
<normaloff/>
</iconset>
</property>
<layout class="QGridLayout" >
<property name="leftMargin" >
<number>0</number>
</property>
<property name="topMargin" >
<number>0</number>
</property>
<property name="rightMargin" >
<number>0</number>
</property>
<property name="bottomMargin" >
<number>0</number>
</property>
<property name="horizontalSpacing" >
<number>6</number>
</property>
<property name="verticalSpacing" >
<number>2</number>
</property>
<property name="margin" >
<number>0</number>
</property>
<item row="0" column="0" >
<widget class="QToolButton" name="mRemoveSelectionButton" >
<property name="toolTip" >
@ -43,7 +36,8 @@
<string/>
</property>
<property name="icon" >
<iconset>../xpm/remove_selection.xpm</iconset>
<iconset>
<normaloff>../xpm/remove_selection.xpm</normaloff>../xpm/remove_selection.xpm</iconset>
</property>
<property name="shortcut" >
<string/>
@ -59,7 +53,8 @@
<string/>
</property>
<property name="icon" >
<iconset>../xpm/selected_to_top.png</iconset>
<iconset>
<normaloff>../xpm/selected_to_top.png</normaloff>../xpm/selected_to_top.png</iconset>
</property>
<property name="shortcut" >
<string>Ctrl+T</string>
@ -75,7 +70,8 @@
<string/>
</property>
<property name="icon" >
<iconset>../xpm/switch_selection.png</iconset>
<iconset>
<normaloff>../xpm/switch_selection.png</normaloff>../xpm/switch_selection.png</iconset>
</property>
<property name="shortcut" >
<string>Ctrl+S</string>
@ -94,7 +90,8 @@
<string/>
</property>
<property name="icon" >
<iconset>../xpm/copy_selection.png</iconset>
<iconset>
<normaloff>../xpm/copy_selection.png</normaloff>../xpm/copy_selection.png</iconset>
</property>
<property name="shortcut" >
<string>Ctrl+C</string>
@ -117,66 +114,12 @@
</property>
</widget>
</item>
<item row="0" column="5" >
<widget class="QToolButton" name="mAddAttributeButton" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip" >
<string>New column</string>
</property>
<property name="text" >
<string/>
</property>
<property name="icon" >
<iconset>../xpm/new_attribute.png</iconset>
</property>
<property name="shortcut" >
<string>Ctrl+N</string>
</property>
</widget>
</item>
<item row="0" column="6" >
<widget class="QToolButton" name="mDeleteAttributeButton" >
<property name="toolTip" >
<string>Delete column</string>
</property>
<property name="text" >
<string/>
</property>
<property name="icon" >
<iconset>../xpm/delete_attribute.png</iconset>
</property>
<property name="shortcut" >
<string>Ctrl+X</string>
</property>
</widget>
</item>
<item row="0" column="7" >
<widget class="QToolButton" name="btnEdit" >
<property name="toolTip" >
<string>Toggle editing mode</string>
</property>
<property name="whatsThis" >
<string>Click to toggle table editing</string>
</property>
<property name="text" >
<string/>
</property>
<property name="checkable" >
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="8" >
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<property name="sizeHint" stdset="0" >
<size>
<width>421</width>
<height>20</height>
@ -184,17 +127,7 @@
</property>
</spacer>
</item>
<item row="1" column="0" colspan="9" >
<widget class="QgsAttributeTable" native="1" name="tblAttributes" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="2" column="0" colspan="9" >
<item row="2" column="0" colspan="7" >
<layout class="QHBoxLayout" >
<item>
<widget class="QLabel" name="textLabel1" >
@ -251,10 +184,36 @@
</item>
</layout>
</item>
<item row="3" column="0" colspan="9" >
<item row="3" column="0" colspan="7" >
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="standardButtons" >
<set>QDialogButtonBox::Close|QDialogButtonBox::Help|QDialogButtonBox::NoButton</set>
<set>QDialogButtonBox::Close|QDialogButtonBox::Help</set>
</property>
</widget>
</item>
<item row="1" column="0" colspan="7" >
<widget class="QgsAttributeTable" native="1" name="tblAttributes" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item row="0" column="5" >
<widget class="QToolButton" name="mToggleEditingButton" >
<property name="toolTip" >
<string>Toggle editing mode</string>
</property>
<property name="whatsThis" >
<string>Click to toggle table editing</string>
</property>
<property name="text" >
<string/>
</property>
<property name="checkable" >
<bool>true</bool>
</property>
</widget>
</item>
@ -274,9 +233,6 @@
<tabstop>mInvertSelectionButton</tabstop>
<tabstop>mCopySelectedRowsButton</tabstop>
<tabstop>mZoomMapToSelectedRowsButton</tabstop>
<tabstop>mAddAttributeButton</tabstop>
<tabstop>mDeleteAttributeButton</tabstop>
<tabstop>btnEdit</tabstop>
<tabstop>mSearchText</tabstop>
<tabstop>mSearchColumns</tabstop>
<tabstop>mSearchButton</tabstop>

View File

@ -213,6 +213,13 @@
</property>
</widget>
</item>
<item row="5" column="0" colspan="2" >
<widget class="QCheckBox" name="cbxAttributeTableDocked" >
<property name="text" >
<string>Open attribute table in a dock window</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
@ -223,8 +230,8 @@
</property>
<property name="sizeHint" >
<size>
<width>547</width>
<height>51</height>
<width>577</width>
<height>21</height>
</size>
</property>
</spacer>

View File

@ -5,8 +5,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>552</width>
<height>600</height>
<width>839</width>
<height>675</height>
</rect>
</property>
<property name="minimumSize" >
@ -19,21 +19,287 @@
<string>Layer Properties</string>
</property>
<property name="windowIcon" >
<iconset/>
<iconset>
<normaloff/>
</iconset>
</property>
<property name="modal" >
<bool>true</bool>
</property>
<layout class="QGridLayout" >
<item row="1" column="0" >
<layout class="QHBoxLayout" >
<property name="spacing" >
<number>3</number>
</property>
<property name="margin" >
<number>1</number>
</property>
<item>
<widget class="QPushButton" name="pbnLoadDefaultStyle" >
<property name="text" >
<string>Restore Default Style</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbnSaveDefaultStyle" >
<property name="text" >
<string>Save As Default</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbnLoadStyle" >
<property name="text" >
<string>Load Style ...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbnSaveStyleAs" >
<property name="text" >
<string>Save Style ...</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="0" >
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="0" column="0" >
<widget class="QTabWidget" name="tabWidget" >
<property name="enabled" >
<bool>true</bool>
</property>
<property name="sizePolicy" >
<sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="autoFillBackground" >
<bool>false</bool>
</property>
<property name="tabShape" >
<enum>QTabWidget::Rounded</enum>
</property>
<property name="currentIndex" >
<number>0</number>
<number>5</number>
</property>
<widget class="QWidget" name="tab1" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>817</width>
<height>557</height>
</rect>
</property>
<attribute name="title" >
<string>General</string>
</attribute>
<layout class="QGridLayout" >
<item row="0" column="0" >
<widget class="QGroupBox" name="indexGroupBox" >
<property name="title" >
<string>Options</string>
</property>
<layout class="QGridLayout" >
<item row="0" column="0" >
<widget class="QLabel" name="textLabel3" >
<property name="text" >
<string>Display name</string>
</property>
<property name="buddy" >
<cstring>txtDisplayName</cstring>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2" >
<widget class="QLineEdit" name="txtDisplayName" />
</item>
<item row="1" column="0" >
<widget class="QLabel" name="textLabel2" >
<property name="toolTip" >
<string>Display field for the Identify Results dialog box</string>
</property>
<property name="whatsThis" >
<string>This sets the display field for the Identify Results dialog box</string>
</property>
<property name="text" >
<string>Display field</string>
</property>
<property name="buddy" >
<cstring>displayFieldComboBox</cstring>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2" >
<widget class="QComboBox" name="displayFieldComboBox" >
<property name="whatsThis" >
<string>Use this control to set which field is placed at the top level of the Identify Results dialog box.</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="3" >
<widget class="QLineEdit" name="leSpatialRefSys" >
<property name="readOnly" >
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="1" >
<widget class="QPushButton" name="pbnIndex" >
<property name="text" >
<string>Create Spatial Index</string>
</property>
</widget>
</item>
<item row="3" column="2" >
<widget class="QPushButton" name="pbnChangeSpatialRefSys" >
<property name="text" >
<string>Change CRS</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0" >
<widget class="QGroupBox" name="chkUseScaleDependentRendering" >
<property name="title" >
<string>Use scale dependent rendering</string>
</property>
<property name="checkable" >
<bool>true</bool>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>11</number>
</property>
<item row="0" column="2" >
<widget class="QLabel" name="textLabel1_2_2" >
<property name="text" >
<string>Maximum</string>
</property>
<property name="buddy" >
<cstring>spinMaximumScale</cstring>
</property>
</widget>
</item>
<item row="0" column="0" >
<widget class="QLabel" name="textLabel1" >
<property name="text" >
<string>Minimum</string>
</property>
<property name="buddy" >
<cstring>spinMinimumScale</cstring>
</property>
</widget>
</item>
<item row="0" column="1" >
<widget class="QSpinBox" name="spinMinimumScale" >
<property name="toolTip" >
<string>Minimum scale at which this layer will be displayed. </string>
</property>
<property name="minimum" >
<number>1</number>
</property>
<property name="maximum" >
<number>100000000</number>
</property>
</widget>
</item>
<item row="0" column="3" >
<widget class="QSpinBox" name="spinMaximumScale" >
<property name="toolTip" >
<string>Maximum scale at which this layer will be displayed. </string>
</property>
<property name="minimum" >
<number>1</number>
</property>
<property name="maximum" >
<number>100000000</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0" >
<widget class="QGroupBox" name="grpSubset" >
<property name="title" >
<string>Subset</string>
</property>
<layout class="QGridLayout" >
<property name="margin" >
<number>11</number>
</property>
<item row="0" column="0" colspan="2" >
<widget class="QTextEdit" name="txtSubsetSQL" >
<property name="enabled" >
<bool>false</bool>
</property>
<property name="acceptDrops" >
<bool>false</bool>
</property>
<property name="acceptRichText" >
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="0" >
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" stdset="0" >
<size>
<width>480</width>
<height>21</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="1" >
<widget class="QPushButton" name="pbnQueryBuilder" >
<property name="text" >
<string>Query Builder</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab2" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>817</width>
<height>552</height>
</rect>
</property>
<property name="sizePolicy" >
<sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<attribute name="title" >
<string>Symbology</string>
</attribute>
@ -134,227 +400,44 @@
<property name="currentIndex" >
<number>1</number>
</property>
<widget class="QWidget" name="page" />
<widget class="QWidget" name="page_2" />
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab2" >
<attribute name="title" >
<string>General</string>
</attribute>
<layout class="QGridLayout" >
<item row="0" column="0" >
<widget class="QGroupBox" name="indexGroupBox" >
<property name="title" >
<string>Options</string>
</property>
<layout class="QGridLayout" >
<item row="0" column="0" >
<widget class="QLabel" name="textLabel3" >
<property name="text" >
<string>Display name</string>
</property>
<property name="buddy" >
<cstring>txtDisplayName</cstring>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2" >
<widget class="QLineEdit" name="txtDisplayName" />
</item>
<item row="1" column="0" >
<widget class="QLabel" name="textLabel2" >
<property name="toolTip" >
<string>Display field for the Identify Results dialog box</string>
</property>
<property name="whatsThis" >
<string>This sets the display field for the Identify Results dialog box</string>
</property>
<property name="text" >
<string>Display field</string>
</property>
<property name="buddy" >
<cstring>displayFieldComboBox</cstring>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2" >
<widget class="QComboBox" name="displayFieldComboBox" >
<property name="whatsThis" >
<string>Use this control to set which field is placed at the top level of the Identify Results dialog box.</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="3" >
<widget class="QLineEdit" name="leSpatialRefSys" >
<property name="readOnly" >
<bool>true</bool>
</property>
</widget>
</item>
<item row="3" column="1" >
<widget class="QPushButton" name="pbnIndex" >
<property name="text" >
<string>Create Spatial Index</string>
</property>
</widget>
</item>
<item row="3" column="2" >
<widget class="QPushButton" name="pbnChangeSpatialRefSys" >
<property name="text" >
<string>Change CRS</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0" >
<widget class="QGroupBox" name="chkUseScaleDependentRendering" >
<property name="title" >
<string>Use scale dependent rendering</string>
</property>
<property name="checkable" >
<bool>true</bool>
</property>
<layout class="QGridLayout" >
<property name="leftMargin" >
<number>11</number>
<widget class="QWidget" name="page" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>100</width>
<height>30</height>
</rect>
</property>
<property name="topMargin" >
<number>11</number>
</widget>
<widget class="QWidget" name="page_2" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>799</width>
<height>502</height>
</rect>
</property>
<property name="rightMargin" >
<number>11</number>
</property>
<property name="bottomMargin" >
<number>11</number>
</property>
<item row="0" column="2" >
<widget class="QLabel" name="textLabel1_2_2" >
<property name="text" >
<string>Maximum</string>
</property>
<property name="buddy" >
<cstring>spinMaximumScale</cstring>
</property>
</widget>
</item>
<item row="0" column="0" >
<widget class="QLabel" name="textLabel1" >
<property name="text" >
<string>Minimum</string>
</property>
<property name="buddy" >
<cstring>spinMinimumScale</cstring>
</property>
</widget>
</item>
<item row="0" column="1" >
<widget class="QSpinBox" name="spinMinimumScale" >
<property name="toolTip" >
<string>Minimum scale at which this layer will be displayed. </string>
</property>
<property name="minimum" >
<number>1</number>
</property>
<property name="maximum" >
<number>100000000</number>
</property>
</widget>
</item>
<item row="0" column="3" >
<widget class="QSpinBox" name="spinMaximumScale" >
<property name="toolTip" >
<string>Maximum scale at which this layer will be displayed. </string>
</property>
<property name="minimum" >
<number>1</number>
</property>
<property name="maximum" >
<number>100000000</number>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0" >
<widget class="QGroupBox" name="grpSubset" >
<property name="title" >
<string>Subset</string>
</property>
<layout class="QGridLayout" >
<property name="leftMargin" >
<number>11</number>
</property>
<property name="topMargin" >
<number>11</number>
</property>
<property name="rightMargin" >
<number>11</number>
</property>
<property name="bottomMargin" >
<number>11</number>
</property>
<item row="0" column="0" colspan="2" >
<widget class="QTextEdit" name="txtSubsetSQL" >
<property name="enabled" >
<bool>false</bool>
</property>
<property name="acceptDrops" >
<bool>false</bool>
</property>
<property name="acceptRichText" >
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="0" >
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType" >
<enum>QSizePolicy::Expanding</enum>
</property>
<property name="sizeHint" >
<size>
<width>480</width>
<height>21</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="1" >
<widget class="QPushButton" name="pbnQueryBuilder" >
<property name="text" >
<string>Query Builder</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab3" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>817</width>
<height>552</height>
</rect>
</property>
<attribute name="title" >
<string>Metadata</string>
</attribute>
<layout class="QGridLayout" >
<property name="leftMargin" >
<number>11</number>
</property>
<property name="topMargin" >
<number>11</number>
</property>
<property name="rightMargin" >
<number>11</number>
</property>
<property name="bottomMargin" >
<property name="margin" >
<number>11</number>
</property>
<item row="0" column="0" >
@ -370,6 +453,14 @@
</layout>
</widget>
<widget class="QWidget" name="tab4" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>817</width>
<height>552</height>
</rect>
</property>
<attribute name="title" >
<string>Labels</string>
</attribute>
@ -406,6 +497,14 @@
</layout>
</widget>
<widget class="QWidget" name="tab5" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>817</width>
<height>552</height>
</rect>
</property>
<attribute name="title" >
<string>Actions</string>
</attribute>
@ -428,63 +527,118 @@
</item>
</layout>
</widget>
</widget>
</item>
<item row="1" column="0" >
<layout class="QHBoxLayout" >
<property name="spacing" >
<number>3</number>
</property>
<property name="leftMargin" >
<number>1</number>
</property>
<property name="topMargin" >
<number>1</number>
</property>
<property name="rightMargin" >
<number>1</number>
</property>
<property name="bottomMargin" >
<number>1</number>
</property>
<item>
<widget class="QPushButton" name="pbnLoadDefaultStyle" >
<property name="text" >
<string>Restore Default Style</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbnSaveDefaultStyle" >
<property name="text" >
<string>Save As Default</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbnLoadStyle" >
<property name="text" >
<string>Load Style ...</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pbnSaveStyleAs" >
<property name="text" >
<string>Save Style ...</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="0" >
<widget class="QDialogButtonBox" name="buttonBox" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons" >
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::NoButton|QDialogButtonBox::Ok</set>
</property>
<widget class="QWidget" name="tab6" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>817</width>
<height>557</height>
</rect>
</property>
<attribute name="title" >
<string>Attributes</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout" >
<item>
<layout class="QHBoxLayout" name="horizontalLayout" >
<property name="sizeConstraint" >
<enum>QLayout::SetNoConstraint</enum>
</property>
<item>
<widget class="QToolButton" name="mAddAttributeButton" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="toolTip" >
<string>New column</string>
</property>
<property name="text" >
<string/>
</property>
<property name="icon" >
<iconset>
<normaloff>../xpm/new_attribute.png</normaloff>../xpm/new_attribute.png</iconset>
</property>
<property name="shortcut" >
<string>Ctrl+N</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="mDeleteAttributeButton" >
<property name="toolTip" >
<string>Delete column</string>
</property>
<property name="text" >
<string/>
</property>
<property name="icon" >
<iconset>
<normaloff>../xpm/delete_attribute.png</normaloff>../xpm/delete_attribute.png</iconset>
</property>
<property name="shortcut" >
<string>Ctrl+X</string>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="mToggleEditingButton" >
<property name="toolTip" >
<string>Toggle editing mode</string>
</property>
<property name="whatsThis" >
<string>Click to toggle table editing</string>
</property>
<property name="text" >
<string/>
</property>
<property name="checkable" >
<bool>true</bool>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer" >
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QTableWidget" name="tblAttributes" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize" >
<size>
<width>256</width>
<height>0</height>
</size>
</property>
<property name="sortingEnabled" >
<bool>false</bool>
</property>
</widget>
</item>
</layout>
<zorder>tblAttributes</zorder>
<zorder></zorder>
</widget>
</widget>
</item>
</layout>