[QGIS Commit] r10337 - in trunk/qgis/src/app: . attributetable
legend
svn_qgis at osgeo.org
svn_qgis at osgeo.org
Fri Mar 20 14:24:19 EDT 2009
Author: wonder
Date: 2009-03-20 14:24:19 -0400 (Fri, 20 Mar 2009)
New Revision: 10337
Added:
trunk/qgis/src/app/attributetable/
trunk/qgis/src/app/attributetable/BeataDialog.cpp
trunk/qgis/src/app/attributetable/BeataDialog.h
trunk/qgis/src/app/attributetable/BeataModel.cpp
trunk/qgis/src/app/attributetable/BeataModel.h
trunk/qgis/src/app/attributetable/BeataView.cpp
trunk/qgis/src/app/attributetable/BeataView.h
Modified:
trunk/qgis/src/app/CMakeLists.txt
trunk/qgis/src/app/legend/qgslegend.cpp
trunk/qgis/src/app/legend/qgslegendlayerfile.cpp
trunk/qgis/src/app/qgisapp.cpp
Log:
Greetings from hackfest from one-handed guy :-)
Imported new attribute table. enjoy!
Modified: trunk/qgis/src/app/CMakeLists.txt
===================================================================
--- trunk/qgis/src/app/CMakeLists.txt 2009-03-20 17:35:32 UTC (rev 10336)
+++ trunk/qgis/src/app/CMakeLists.txt 2009-03-20 18:24:19 UTC (rev 10337)
@@ -82,6 +82,10 @@
ogr/qgsogrhelperfunctions.cpp
ogr/qgsopenvectorlayerdialog.cpp
ogr/qgsnewogrconnection.cpp
+
+ attributetable/BeataDialog.cpp
+ attributetable/BeataModel.cpp
+ attributetable/BeataView.cpp
)
@@ -149,6 +153,9 @@
ogr/qgsopenvectorlayerdialog.h
ogr/qgsnewogrconnection.h
+
+ attributetable/BeataDialog.h
+ attributetable/BeataModel.h
)
IF (POSTGRES_FOUND)
@@ -202,7 +209,7 @@
INCLUDE_DIRECTORIES(
- ${CMAKE_CURRENT_SOURCE_DIR} composer legend
+ ${CMAKE_CURRENT_SOURCE_DIR} composer legend attributetable
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_BINARY_DIR}/../ui
../core
Added: trunk/qgis/src/app/attributetable/BeataDialog.cpp
===================================================================
--- trunk/qgis/src/app/attributetable/BeataDialog.cpp (rev 0)
+++ trunk/qgis/src/app/attributetable/BeataDialog.cpp 2009-03-20 18:24:19 UTC (rev 10337)
@@ -0,0 +1,508 @@
+/***************************************************************************
+ BeataDialog.cpp
+ BEtter Attribute TAble
+ -------------------
+ date : Feb 2009
+ copyright : Vita Cizek
+ email : weetya (at) gmail.com
+
+ ***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <QtGui>
+
+#include "BeataDialog.h"
+#include "BeataModel.h"
+#include "BeataView.h"
+
+#include <qgsapplication.h>
+#include <qgsvectordataprovider.h>
+#include <qgsvectorlayer.h>
+#include <qgssearchstring.h>
+#include <qgssearchtreenode.h>
+
+#include "qgisapp.h"
+#include "qgssearchquerybuilder.h"
+
+BeataDialog::BeataDialog(QgsVectorLayer *theLayer, QWidget *parent, Qt::WindowFlags flags)
+ : QDialog(parent, flags)
+{
+ mLayer = theLayer;
+
+ setupUi(this);
+
+ setAttribute(Qt::WA_DeleteOnClose);
+
+ QSettings settings;
+ restoreGeometry( settings.value( "/Windows/BetterAttributeTable/geometry" ).toByteArray() );
+
+ mView->setLayer(mLayer);
+ mFilterModel = (BeataFilterModel *) mView->model();
+ mModel = (BeataModel *)((BeataFilterModel *)mView->model())->sourceModel();
+
+ mQuery = query;
+ mColumnBox = columnBox;
+ columnBoxInit();
+
+ mShowBox = showBox;
+ mShowBox->addItem("Show unselected rows");
+ mShowBox->addItem("Hide unselected rows");
+
+ mMenuActions = new QMenu();
+ mMenuActions->addAction(tr("Advanced search"), this, SLOT(advancedSearch()));
+ mMenuActions->addSeparator();
+ mMenuActions->addAction(getThemeIcon( "/mActionCopySelected.png" ), tr("Copy selected rows"), this, SLOT(copySelectedRowsToClipboard()));
+ mMenuActions->addAction(getThemeIcon( "/mActionZoomToSelected.png" ), tr("Zoom to selected"), this, SLOT(zoomMapToSelectedRows()));
+ mMenuActions->addAction(getThemeIcon( "/mActionSelectedToTop.png" ), tr("Move selected to top"), this, SLOT(selectedToTop()));
+ mMenuActions->addAction(getThemeIcon( "/mActionUnselectAttributes.png" ), tr("Clear selection"), this, SLOT(removeSelection()));
+ mMenuActions->addAction(getThemeIcon( "/mActionInvertSelection.png" ), tr("Invert selection"), this, SLOT(invertSelection()));
+ mMenuActions->addSeparator();
+
+ // toggle editing
+ mActionToggleEditing = mMenuActions->addAction(getThemeIcon( "/mActionToggleEditing.png" ), tr("Toggle editing"), this, SLOT(toggleEditing()));
+ mActionToggleEditing->setCheckable( true );
+ mActionToggleEditing->setEnabled( mLayer->dataProvider()->capabilities() & QgsVectorDataProvider::ChangeAttributeValues );
+ // info from table to application
+ connect( this, SIGNAL( editingToggled( QgsMapLayer * ) ), parentWidget(), SLOT( toggleEditing( QgsMapLayer * ) ) );
+ // info from layer to table
+ connect( mLayer, SIGNAL( editingStarted() ), this, SLOT( editingToggled() ) );
+ connect( mLayer, SIGNAL( editingStopped() ), this, SLOT( editingToggled() ) );
+
+ connect(mShowBox, SIGNAL(currentIndexChanged(const QString &)), this, SLOT(toggleShowDeselected(const QString &)));
+ connect(searchButton, SIGNAL(clicked()), this, SLOT(search()));
+ connect(actionsButton, SIGNAL(clicked()), this, SLOT(showAdvanced()));
+
+ connect(mLayer, SIGNAL(selectionChanged()), this, SLOT(updateSelectionFromLayer()));
+ connect(mLayer, SIGNAL(layerDeleted()), this, SLOT( close()));
+ connect(mView->verticalHeader(), SIGNAL(sectionClicked(int)), this, SLOT(updateRowSelection(int)));
+ connect(mModel, SIGNAL(modelChanged()), this, SLOT(updateSelection()));
+
+ mLastClickedHeaderIndex = 0;
+ mSelectionModel = new QItemSelectionModel(mFilterModel);
+ updateSelectionFromLayer();
+}
+
+BeataDialog::~BeataDialog()
+{
+}
+
+void BeataDialog::closeEvent( QCloseEvent* event )
+{
+ QDialog::closeEvent( event );
+
+ QSettings settings;
+ settings.setValue( "/Windows/BetterAttributeTable/geometry", saveGeometry() );
+}
+
+
+QIcon BeataDialog::getThemeIcon( const QString theName )
+{
+ // copied from QgisApp::getThemeIcon. To be removed when merged to SVN
+
+ QString myPreferredPath = QgsApplication::activeThemePath() + QDir::separator() + theName;
+ QString myDefaultPath = QgsApplication::defaultThemePath() + QDir::separator() + theName;
+ if ( QFile::exists( myPreferredPath ) )
+ {
+ return QIcon( myPreferredPath );
+ }
+ else if ( QFile::exists( myDefaultPath ) )
+ {
+ //could still return an empty icon if it
+ //doesnt exist in the default theme either!
+ return QIcon( myDefaultPath );
+ }
+ else
+ {
+ return QIcon();
+ }
+}
+
+void BeataDialog::showAdvanced()
+{
+ mMenuActions->exec(QCursor::pos());
+}
+
+void BeataDialog::selectedToTop()
+{
+ int freeIndex = 0;
+
+ //QgsFeatureIds fids = mSelectedFeatures;
+ //QgsFeatureIds::Iterator it = fids.begin();
+
+ mModel->incomingChangeLayout();
+
+ QgsFeatureIds::Iterator it = mSelectedFeatures.begin();
+ for (; it != mSelectedFeatures.end(); ++it, ++freeIndex)
+ {
+ QModelIndex sourceIndex = mFilterModel->mapToSource(mFilterModel->index(freeIndex, 0));
+ mModel->swapRows(mModel->rowToId(sourceIndex.row()), *it);
+ }
+
+/*
+ while (it != fids.end())
+ { //map!!!!
+ //mModel->swapRows(mModel->rowToId(freeIndex), *it);
+ //QModelIndex index = mFilterModel->mapFromSource(mModel->index(mModel->idToRow(*it), 0));
+ QModelIndex sourceIndex = mFilterModel->mapToSource(mFilterModel->index(freeIndex, 0));
+ mModel->swapRows(mModel->rowToId(sourceIndex.row()), *it);
+ //mModel->swapRows(freeIndex, *it);
+
+ if (fids.empty())
+ break;
+ else
+ ++it;
+
+ ++freeIndex;
+ }
+*/
+ // just select proper rows
+ //mModel->reload(mModel->index(0,0), mModel->index(mModel->rowCount(), mModel->columnCount()));
+ //mModel->changeLayout();
+ mModel->resetModel();
+ updateSelection();
+}
+
+void BeataDialog::copySelectedRowsToClipboard()
+{
+ QgisApp* pApp = dynamic_cast<QgisApp*>(parentWidget());
+ if (pApp)
+ pApp->editCopy(mLayer);
+}
+
+void BeataDialog::zoomMapToSelectedRows()
+{
+ QgisApp* pApp = dynamic_cast<QgisApp*>(parentWidget());
+ if (pApp)
+ pApp->zoomToSelected();
+}
+
+void BeataDialog::invertSelection()
+{
+ mLayer->invertSelection();
+}
+
+void BeataDialog::removeSelection()
+{
+ mLayer->removeSelection();
+}
+
+void BeataDialog::toggleShowDeselected(const QString &text)
+{
+ if (text == "Show unselected rows")
+ {
+ mFilterModel->mHideUnselected = false;
+ //TODO: divne
+ //mModel->changeLayout();
+ mFilterModel->invalidate();
+ return;
+ }
+
+ // show only selected
+ mFilterModel->mHideUnselected = true;
+ mFilterModel->invalidate();
+ //mModel->changeLayout();
+}
+
+void BeataDialog::columnBoxInit()
+{
+ QgsFieldMap fieldMap = mLayer->dataProvider()->fields();
+ QgsFieldMap::Iterator it = fieldMap.begin();
+
+ for (; it != fieldMap.end(); ++it)
+ mColumnBox->addItem(it.value().name());
+}
+
+int BeataDialog::columnBoxColumnId()
+{
+ QgsFieldMap fieldMap = mLayer->dataProvider()->fields();
+ QgsFieldMap::Iterator it = fieldMap.begin();
+
+ for (; it != fieldMap.end(); ++it)
+ if (it.value().name() == mColumnBox->currentText())
+ return it.key();
+
+ return 0;
+}
+
+void BeataDialog::updateSelection()
+{
+ QModelIndex index;
+ mView->setSelectionMode(QAbstractItemView::MultiSelection);
+
+ QItemSelection selection;
+
+ QgsFeatureIds::Iterator it = mSelectedFeatures.begin();
+ for (; it != mSelectedFeatures.end(); ++it)
+ {
+ QModelIndex leftUpIndex = mFilterModel->mapFromSource(mModel->index(mModel->idToRow(*it), 0));
+ QModelIndex rightBottomIndex = mFilterModel->mapFromSource(mModel->index(mModel->idToRow(*it), mModel->columnCount() - 1));
+ selection.append(QItemSelectionRange(leftUpIndex, rightBottomIndex));
+ //selection.append(QItemSelectionRange(leftUpIndex, leftUpIndex));
+ }
+
+ mSelectionModel->select(selection, QItemSelectionModel::ClearAndSelect);// | QItemSelectionModel::Columns);
+ mView->setSelectionModel(mSelectionModel);
+ mView->setSelectionMode(QAbstractItemView::NoSelection);
+
+ /*for (int i = 0; i < mModel->rowCount(); ++i)
+ {
+ int id = mModel->rowToId(i);
+ std::cout << id << "\n";
+ }
+ std::cout << "--------------\n";
+*/
+}
+
+void BeataDialog::updateRowSelection(int index)
+{
+ // map index to filter model
+ //index = mFilterModel->mapFromSource(mModel->index(index, 0)).row();
+
+ if (mView->shiftPressed) {
+ std::cout << "shift\n";
+ // get the first and last index of the rows to be selected/deselected
+ int first, last;
+ if (index > mLastClickedHeaderIndex) {
+ first = mLastClickedHeaderIndex + 1;
+ last = index;
+ }
+ else if (index == mLastClickedHeaderIndex) {
+ // row was selected and now it is shift-clicked
+ // ignore the shift and deselect the row
+ first = last = index;
+ }
+ else {
+ first = index;
+ last = mLastClickedHeaderIndex - 1;
+ }
+
+ // for all the rows update the selection, without starting a new selection
+ if (first <= last)
+ updateRowSelection(first, last, false);
+
+ mLastClickedHeaderIndex = last;
+ }
+ else if (mView->ctrlPressed) {
+ std::cout << "ctrl\n";
+ // update the single row selection, without starting a new selection
+ updateRowSelection(index, index, false);
+
+ // the next shift would start from here
+ mLastClickedHeaderIndex = index;
+ }
+ else {
+ std::cout << "ordinary click\n";
+ // update the single row selection, start a new selection if the row was not selected
+ updateRowSelection(index, index, true);
+
+ // the next shift would start from here
+ mLastClickedHeaderIndex = index;
+ }
+}
+
+// fast row deselection needed
+void BeataDialog::updateRowSelection(int first, int last, bool startNewSelection)
+{
+ disconnect(mLayer, SIGNAL(selectionChanged()), this, SLOT(updateSelectionFromLayer()));
+
+ //index = mFilterModel->mapFromSource(mModel->index(index, 0)).row();
+ // Id must be mapped to table/view row
+ QModelIndex index = mFilterModel->mapToSource(mFilterModel->index(first, 0));
+ int fid = mModel->rowToId(index.row());
+ bool wasSelected = mSelectedFeatures.contains(fid);
+
+ // new selection should be created
+ if (startNewSelection)
+ {
+ mView->clearSelection();
+ mSelectedFeatures.clear();
+
+ if (wasSelected)
+ {
+ mLayer->removeSelection();
+ connect(mLayer, SIGNAL(selectionChanged()), this, SLOT(updateSelectionFromLayer()));
+ return;
+ }
+
+ // set clicked row to current
+ mView->setCurrentIndex(mFilterModel->index(first, 0));
+ mView->setSelectionMode(QAbstractItemView::SingleSelection);
+
+ //QModelIndex index = mFilterModel->mapFromSource(mModel->index(first, 0));
+
+ mView->selectRow(first);
+ mView->setSelectionMode(QAbstractItemView::NoSelection);
+
+ mSelectedFeatures.insert(fid);
+ //mLayer->setSelectedFeatures(mSelectedFeatures);
+ mLayer->removeSelection();
+ mLayer->select(fid);
+ //mFilterModel->invalidate();
+ connect(mLayer, SIGNAL(selectionChanged()), this, SLOT(updateSelectionFromLayer()));
+ return;
+ }
+
+ // existing selection should be updated
+ for (int i = first; i <= last; ++i) {
+ if (i > first) {
+ // Id must be mapped to table/view row
+ index = mFilterModel->mapToSource(mFilterModel->index(i, 0));
+ fid = mModel->rowToId(index.row());
+ wasSelected = mSelectedFeatures.contains(fid);
+ }
+
+ if (wasSelected)
+ mSelectedFeatures.remove(fid);
+ else
+ mSelectedFeatures.insert(fid);
+ }
+ //mFilterModel->invalidate();
+
+ /*
+ QItemSelection selection;
+ QModelIndex leftUpIndex = mFilterModel->index(first, 0);
+ QModelIndex rightBottomIndex = mFilterModel->index(last, mModel->columnCount() - 1);
+ selection.append(QItemSelectionRange(leftUpIndex, rightBottomIndex));
+ mSelectionModel->select(selection, QItemSelectionModel::Select);
+ mView->setSelectionModel(mSelectionModel);
+ */
+ updateSelection();
+ mLayer->setSelectedFeatures(mSelectedFeatures);
+ connect(mLayer, SIGNAL(selectionChanged()), this, SLOT(updateSelectionFromLayer()));
+}
+
+void BeataDialog::updateSelectionFromLayer()
+{
+ std::cout << "updateFromLayer\n";
+ mSelectedFeatures = mLayer->selectedFeaturesIds();
+ updateSelection();
+}
+
+void BeataDialog::doSearch(QString searchString)
+{
+ // parse search string and build parsed tree
+ QgsSearchString search;
+ if (!search.setString(searchString))
+ {
+ QMessageBox::critical(this, tr("Search string parsing error"), search.parserErrorMsg());
+ return;
+ }
+
+ QgsSearchTreeNode* searchTree = search.tree();
+ if (searchTree == NULL)
+ {
+ QMessageBox::information(this, tr("Search results"), tr("You've supplied an empty search string."));
+ return;
+ }
+
+ QApplication::setOverrideCursor(Qt::WaitCursor);
+
+ mSelectedFeatures.clear();
+ mLayer->select(mLayer->pendingAllAttributesList(), QgsRectangle(), false);
+
+ QgsFeature f;
+ while (mLayer->nextFeature(f))
+ {
+ if (searchTree->checkAgainst(mLayer->pendingFields(), f.attributeMap()))
+ mSelectedFeatures << f.id();
+
+ // check if there were errors during evaluating
+ if (searchTree->hasError())
+ break;
+ }
+
+ QApplication::restoreOverrideCursor();
+
+ if (searchTree->hasError())
+ {
+ QMessageBox::critical(this, tr("Error during search"), searchTree->errorMsg());
+ return;
+ }
+
+ // update view
+ updateSelection();
+
+ disconnect(mLayer, SIGNAL(selectionChanged()), this, SLOT(updateSelectionFromLayer()));
+ mLayer->setSelectedFeatures(mSelectedFeatures);
+ connect(mLayer, SIGNAL(selectionChanged()), this, SLOT(updateSelectionFromLayer()));
+
+ QString str;
+ if (mSelectedFeatures.size())
+ str.sprintf(tr("Found %d matching features.", "", mSelectedFeatures.size()).toUtf8(), mSelectedFeatures.size());
+ else
+ str = tr("No matching features found.");
+
+ QMessageBox::information(this, tr("Search results"), str);
+}
+
+void BeataDialog::search()
+{
+
+ QString str = mColumnBox->currentText();
+
+ const QgsFieldMap& flds = mLayer->dataProvider()->fields();
+ int fldIndex = mLayer->dataProvider()->fieldNameIndex(str);
+ QVariant::Type fldType = flds[fldIndex].type();
+ bool numeric = (fldType == QVariant::Int || fldType == QVariant::Double);
+
+ if (numeric)
+ str += " = '";
+ else
+ str += " ~ '";
+
+ str += mQuery->displayText();
+ str += "'";
+
+ doSearch(str);
+}
+
+void BeataDialog::advancedSearch()
+{
+ QgsSearchQueryBuilder dlg(mLayer, this);
+ dlg.setSearchString(mQuery->displayText());
+
+ if (dlg.exec())
+ doSearch(dlg.searchString());
+}
+
+void BeataDialog::toggleEditing()
+{
+ emit editingToggled( mLayer );
+}
+
+void BeataDialog::editingToggled()
+{
+ mActionToggleEditing->setChecked( mLayer->isEditable() );
+
+ // (probably reload data if user stopped editing - possible revert)
+ mModel->reload(mModel->index(0,0), mModel->index(mModel->rowCount(), mModel->columnCount()));
+
+ // not necessary to set table read only if layer is not editable
+ // because model always reflects actual state when returning item flags
+}
+
+// not used now
+void BeataDialog::startEditing()
+{
+ mLayer->startEditing();
+}
+
+// not used now
+void BeataDialog::submit()
+{
+ mLayer->commitChanges();
+}
+
+// not used now
+void BeataDialog::revert()
+{
+ mLayer->rollBack();
+ mModel->revert();
+ mModel->reload(mModel->index(0,0), mModel->index(mModel->rowCount(), mModel->columnCount()));
+}
Added: trunk/qgis/src/app/attributetable/BeataDialog.h
===================================================================
--- trunk/qgis/src/app/attributetable/BeataDialog.h (rev 0)
+++ trunk/qgis/src/app/attributetable/BeataDialog.h 2009-03-20 18:24:19 UTC (rev 10337)
@@ -0,0 +1,103 @@
+/***************************************************************************
+ BeataDialog.h
+ BEtter Attribute TAble
+ -------------------
+ date : Feb 2009
+ copyright : Vita Cizek
+ email : weetya (at) gmail.com
+
+ ***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef BEATADIALOG_H_
+#define BEATADIALOG_H_
+
+#include <QDialog>
+#include <QModelIndex>
+#include <QItemSelectionModel>
+#include <QMutex>
+
+#include "ui_BeataGui.h"
+
+class QgsMapLayer;
+class QgsVectorLayer;
+
+#include "qgsvectorlayer.h" //QgsFeatureIds
+
+class QDialogButtonBox;
+class QPushButton;
+class QLineEdit;
+class QComboBox;
+class QMenu;
+
+class BeataModel;
+class BeataFilterModel;
+class BeataView;
+
+class BeataDialog : public QDialog, private Ui::BeataDialogGui
+{
+Q_OBJECT
+
+public:
+ BeataDialog(QgsVectorLayer *theLayer, QWidget *parent = 0, Qt::WindowFlags flags = Qt::Window);
+ ~BeataDialog();
+
+public slots:
+ void editingToggled();
+
+private slots:
+ void submit();
+ void revert();
+ void search();
+ void advancedSearch();
+ void updateSelection();
+ void updateSelectionFromLayer();
+ void updateRowSelection(int index);
+ void updateRowSelection(int first, int last, bool startNewSelection);
+ void toggleShowDeselected(const QString &text);
+
+ void startEditing();
+ void invertSelection();
+ void removeSelection();
+ void copySelectedRowsToClipboard();
+ void zoomMapToSelectedRows();
+ void selectedToTop();
+ void showAdvanced();
+ void toggleEditing();
+
+signals:
+ void editingToggled( QgsMapLayer * );
+
+protected:
+ void closeEvent( QCloseEvent* event );
+
+private:
+ void columnBoxInit();
+ int columnBoxColumnId();
+ void doSearch(QString searchString);
+
+ QIcon getThemeIcon( const QString theName );
+
+ QLineEdit *mQuery;
+ QComboBox *mColumnBox;
+ QComboBox *mShowBox;
+
+ QMenu* mMenuActions;
+ QAction* mActionToggleEditing;
+
+ BeataModel *mModel;
+ BeataFilterModel *mFilterModel;
+ QgsVectorLayer *mLayer;
+ QgsFeatureIds mSelectedFeatures;
+
+ QItemSelectionModel* mSelectionModel;
+ int mLastClickedHeaderIndex;
+};
+
+#endif
Added: trunk/qgis/src/app/attributetable/BeataModel.cpp
===================================================================
--- trunk/qgis/src/app/attributetable/BeataModel.cpp (rev 0)
+++ trunk/qgis/src/app/attributetable/BeataModel.cpp 2009-03-20 18:24:19 UTC (rev 10337)
@@ -0,0 +1,630 @@
+/***************************************************************************
+ BeataModel.cpp
+ --------------------------------------
+ Date : Feb 2009
+ Copyright : (C) 2009 Vita Cizek
+ Email : weetya (at) gmail.com
+ ***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "BeataModel.h"
+#include "BeataView.h"
+
+#include "qgsvectordataprovider.h"
+#include "qgsfield.h"
+#include "qgsvectorlayer.h"
+
+#include <QtGui>
+#include <QVariant>
+#include <QtAlgorithms>
+
+//could be faster when type guessed before sorting
+bool idColumnPair::operator<(const idColumnPair &b) const
+{
+ //QVariat thinks gid is a string!
+ QVariant::Type columnType = columnItem.type();
+
+ if (columnType == QVariant::Int || columnType == QVariant::UInt || columnType == QVariant::LongLong || columnType == QVariant::ULongLong)
+ return columnItem.toLongLong() < b.columnItem.toLongLong();
+
+ if (columnType == QVariant::Double)
+ return columnItem.toDouble() < b.columnItem.toDouble();
+
+ return columnItem.toString() < b.columnItem.toString();
+}
+
+//////////////////
+// Filter Model //
+//////////////////
+
+void BeataFilterModel::sort(int column, Qt::SortOrder order)
+{
+ ((BeataModel *)sourceModel())->sort(column, order);
+}
+
+BeataFilterModel::BeataFilterModel(QgsVectorLayer* theLayer)
+{
+ mLayer = theLayer;
+ mHideUnselected = false;
+ setDynamicSortFilter(true);
+}
+
+bool BeataFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
+{
+ if(mHideUnselected)
+ // unreadable? yes, i agree :-)
+ return mLayer->selectedFeaturesIds().contains(((BeataModel *)sourceModel())->rowToId(sourceRow));
+
+ return true;
+}
+
+/*
+QModelIndex BeataFilterModel::mapFromSource ( const QModelIndex& sourceIndex ) const
+{
+ return sourceIndex;
+}
+
+QModelIndex BeataFilterModel::mapToSource ( const QModelIndex& filterIndex ) const
+{
+ return filterIndex;
+}
+*/
+
+////////////////
+// BeataModel //
+////////////////
+
+BeataModel::BeataModel(QgsVectorLayer *theLayer, QObject *parent)
+: QAbstractTableModel(parent) {
+ mLastRowId = -1;
+ mLastRow = NULL;
+ mLayer = theLayer;
+ mFeatureCount = mLayer->pendingFeatureCount();
+ mFieldCount = mLayer->dataProvider()->fieldCount();
+ mAttributes = mLayer->dataProvider()->attributeIndexes();
+
+ connect(mLayer, SIGNAL(layerModified(bool)), this, SLOT( layerModified(bool)));
+ //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&)), this, SLOT( attributeValueChanged(int, int, const QVariant&)));
+ //connect(mLayer, SIGNAL(featureDeleted(int)), this, SLOT( featureDeleted(int)));
+ //connect(mLayer, SIGNAL(featureAdded(int)), this, SLOT( featureAdded(int)));
+
+ loadLayer();
+}
+
+void BeataModel::featureDeleted(int fid)
+{
+ std::cout << "BM feature deleted\n";
+
+ int idx = mIdRowMap[fid];
+ std::cout << idx;
+ std::cout << fid;
+
+ /*--mFeatureCount;
+ mIdRowMap.remove(fid);
+ mRowIdMap.remove(idx);
+
+ // fill the hole in the view
+ if (idx != mFeatureCount)
+ {
+ std::cout << "jo";
+ //mRowIdMap[idx] = mRowIdMap[mFeatureCount];
+ //mIdRowMap[mRowIdMap[idx]] = idx;
+ int movedId = mRowIdMap[mFeatureCount];
+ mRowIdMap.remove(mFeatureCount);
+ mRowIdMap.insert(idx, movedId);
+ mIdRowMap[movedId] = idx;
+ //mIdRowMap.remove(mRowIdMap[idx]);
+ //mIdRowMap.insert(mRowIdMap[idx], idx);
+ }
+
+ std::cout << "map sizes:" << mRowIdMap.size() << ", " << mIdRowMap.size();
+ emit layoutChanged();
+ //reload(index(0,0), index(rowCount(), columnCount()));
+ std::cout << "\n";
+*/
+ std::cout << "id->row";
+ QMap<int, int>::iterator it;
+ for (it = mIdRowMap.begin(); it != mIdRowMap.end(); ++it)
+ std::cout << it.key() << "->" << *it << "\n";
+
+ std::cout << "row->id";
+
+ for (it = mRowIdMap.begin(); it != mRowIdMap.end(); ++it)
+ std::cout << it.key() << "->" << *it << "\n";
+
+}
+
+void BeataModel::featureAdded(int fid)
+{
+ std::cout << "BM feature added\n";
+ ++mFeatureCount;
+ mIdRowMap.insert(fid, mFeatureCount - 1);
+ mRowIdMap.insert(mFeatureCount - 1, fid);
+ std::cout << "map sizes:" << mRowIdMap.size() << ", " << mIdRowMap.size() << "\n";;
+ reload(index(0,0), index(rowCount(), columnCount()));
+}
+
+void BeataModel::attributeAdded (int idx)
+{
+std::cout << "BM attribute added\n";
+ loadLayer();
+ std::cout << "map sizes:" << mRowIdMap.size() << ", " << mIdRowMap.size() << "\n";;
+ reload(index(0,0), index(rowCount(), columnCount()));
+ emit modelChanged();
+}
+
+void BeataModel::attributeDeleted (int idx)
+{
+std::cout << "BM attribute deleted\n";
+ loadLayer();
+ std::cout << "map sizes:" << mRowIdMap.size() << ", " << mIdRowMap.size() << "\n";;
+ reload(index(0,0), index(rowCount(), columnCount()));
+ emit modelChanged();
+}
+
+void BeataModel::layerDeleted()
+{
+std::cout << "BM attribute deleted\n";
+ mIdRowMap.clear();
+ mRowIdMap.clear();
+ std::cout << "map sizes:" << mRowIdMap.size() << ", " << mIdRowMap.size() << "\n";;
+ reload(index(0,0), index(rowCount(), columnCount()));
+}
+
+//TODO: check whether caching in data()/setData() doesn't cache old value
+void BeataModel::attributeValueChanged (int fid, int idx, const QVariant &value)
+{
+ std::cout << "BM attribute changed\n";
+ reload(index(0,0), index(rowCount(), columnCount()));
+}
+
+void BeataModel::layerModified(bool onlyGeometry)
+{
+ if (onlyGeometry)
+ return;
+
+ loadLayer();
+ emit modelChanged();
+}
+
+void BeataModel::loadLayer()
+{
+ std::cout << "BM loadlayer\n";
+
+ QgsFeature f;
+ bool ins = false, rm = false;
+
+ mRowIdMap.clear();
+ mIdRowMap.clear();
+
+ if (mFeatureCount < mLayer->pendingFeatureCount())
+ {
+ std::cout<<"ins\n";
+ ins = true;
+ beginInsertRows(QModelIndex(), mFeatureCount, mLayer->pendingFeatureCount() - 1);
+ //std::cout << mFeatureCount << ", " << mLayer->pendingFeatureCount() - 1 << "\n";
+ }
+ else if (mFeatureCount > mLayer->pendingFeatureCount())
+ {
+ std::cout<<"rm\n";
+ rm = true;
+ beginRemoveRows(QModelIndex(), mLayer->pendingFeatureCount(), mFeatureCount - 1);
+ //std::cout << mFeatureCount << ", " << mLayer->pendingFeatureCount() -1 << "\n";
+ }
+
+ mLayer->select(QgsAttributeList(), QgsRectangle(), false);
+
+ for (int i = 0; mLayer->nextFeature(f); ++i)
+ {
+ mRowIdMap.insert(i, f.id());
+ mIdRowMap.insert(f.id(), i);
+ }
+
+ // not needed when we have featureAdded signal
+ mFeatureCount = mLayer->pendingFeatureCount();
+ mFieldCount = mLayer->dataProvider()->fieldCount();
+
+ if (ins)
+ {
+ endInsertRows();
+ std::cout << "end ins\n";
+ }
+ else if (rm)
+ {
+ endRemoveRows();
+ std::cout << "end rm\n";
+ }
+
+/* std::cout << "id->row";
+ QMap<int, int>::iterator it;
+ for (it = mIdRowMap.begin(); it != mIdRowMap.end(); ++it)
+ std::cout << it.key() << "->" << *it << "\n";
+
+ std::cout << "row->id";
+
+ for (it = mRowIdMap.begin(); it != mRowIdMap.end(); ++it)
+ std::cout << it.key() << "->" << *it << "\n";*/
+
+
+}
+
+void BeataModel::swapRows(int a, int b)
+{
+ if (a == b)
+ return;
+
+ int rowA = idToRow(a);
+ int rowB = idToRow(b);
+
+ //emit layoutAboutToBeChanged();
+
+ mRowIdMap.remove(rowA);
+ mRowIdMap.remove(rowB);
+ mRowIdMap.insert(rowA, b);
+ mRowIdMap.insert(rowB, a);
+
+ mIdRowMap.remove(a);
+ mIdRowMap.remove(b);
+ mIdRowMap.insert(a, rowB);
+ mIdRowMap.insert(b, rowA);
+
+ //emit layoutChanged();
+}
+
+int BeataModel::idToRow(const int id) const
+{
+ if (!mIdRowMap.contains(id))
+ {
+ std::cout << "idToRow: id " << id << " not in map\n";
+ return -1;
+ }
+
+ return mIdRowMap[id];
+}
+
+int BeataModel::rowToId(const int id) const
+{
+ if (!mRowIdMap.contains(id))
+ {
+ std::cout << "rowToId: row " << id << " not in map\n";
+ return -1;
+ }
+
+ return mRowIdMap[id];
+}
+
+int BeataModel::rowCount(const QModelIndex &parent) const
+{
+ return mFeatureCount;
+}
+
+int BeataModel::columnCount(const QModelIndex &parent) const
+{
+ return mFieldCount;
+}
+
+QVariant BeataModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (role == Qt::DisplayRole)
+ {
+ if (orientation == Qt::Vertical) //row
+ {
+ return QVariant(section);
+ }
+ else
+ {
+ QgsField field = mLayer->dataProvider()->fields()[section]; //column
+ return QVariant(field.name());
+ }
+ }
+ else return QVariant();
+}
+
+void BeataModel::sort(int column, Qt::SortOrder order)
+{
+ QgsAttributeMap row;
+ idColumnPair pair;
+ QgsAttributeList attrs;
+ QgsFeature f;
+
+ attrs.append(column);
+
+ emit layoutAboutToBeChanged();
+ //std::cout << "SORTing\n";
+
+ mSortList.clear();
+ mLayer->select(attrs, QgsRectangle(), false);
+ while (mLayer->nextFeature(f))
+ {
+ row = f.attributeMap();
+
+ pair.id = f.id();
+ pair.columnItem = row[column];
+
+ mSortList.append(pair);
+ }
+
+ if (order == Qt::AscendingOrder)
+ qStableSort(mSortList.begin(), mSortList.end());
+ else
+ qStableSort(mSortList.begin(), mSortList.end(), qGreater<idColumnPair>());
+
+ // recalculate id<->row maps
+ mRowIdMap.clear();
+ mIdRowMap.clear();
+
+ int i = 0;
+ QList<idColumnPair>::Iterator it;
+ for (it = mSortList.begin(); it != mSortList.end(); ++it, ++i)
+ {
+ mRowIdMap.insert(i, it->id);
+ mIdRowMap.insert(it->id, i);
+ }
+
+ // restore selection
+ emit layoutChanged();
+ //reset();
+ emit modelChanged();
+}
+
+QVariant BeataModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid() || (role != Qt::TextAlignmentRole && role != Qt::DisplayRole && role != Qt::EditRole) )
+ return QVariant();
+
+ QVariant::Type fldType = mLayer->dataProvider()->fields()[index.column()].type();
+ bool fldNumeric = (fldType == QVariant::Int || fldType == QVariant::Double);
+
+ if (role == Qt::TextAlignmentRole)
+ {
+ if (fldNumeric)
+ return QVariant(Qt::AlignRight);
+ else
+ return QVariant(Qt::AlignLeft);
+ }
+
+ // if we don't have the row in current cache, load it from layer first
+ if (mLastRowId != rowToId(index.row()))
+ {
+ bool res = mLayer->featureAtId(rowToId(index.row()), mFeat, false, true);
+
+ if (!res)
+ return QVariant("ERROR");
+
+ mLastRowId = rowToId(index.row());
+ mLastRow = (QgsAttributeMap *)(&(mFeat.attributeMap()));
+ }
+
+ QVariant& val = (*mLastRow)[index.column()];
+
+ if (val.isNull())
+ {
+ // if the value is NULL, show that in table, but don't show "NULL" text in editor
+ if (role == Qt::EditRole)
+ return QVariant();
+ else
+ return QVariant("NULL");
+ }
+
+ // force also numeric data for EditRole to be strings
+ // otherwise it creates spinboxes instead of line edits
+ // (probably not what we do want)
+ if (fldNumeric && role == Qt::EditRole)
+ return val.toString();
+
+ // convert to QString from some other representation
+ // this prevents displaying greater numbers in exponential format
+ return val.toString();
+}
+
+bool BeataModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if (!index.isValid() || role != Qt::EditRole)
+ return false;
+
+ if (!mLayer->isEditable())
+ return false;
+
+ bool res = mLayer->featureAtId(rowToId(index.row()), mFeat, false, true);
+
+ if (res) {
+ mLastRowId = rowToId(index.row());
+ mLastRow = (QgsAttributeMap *)(&(mFeat.attributeMap()));
+
+ mLayer->changeAttributeValue(rowToId(index.row()), index.column(), value, true);
+ }
+
+ if (!mLayer->isModified())
+ return false;
+
+ emit dataChanged(index, index);
+ return true;
+}
+
+Qt::ItemFlags BeataModel::flags(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return Qt::ItemIsEnabled;
+
+ Qt::ItemFlags flags = QAbstractItemModel::flags(index);
+
+ if (mLayer->isEditable())
+ flags |= Qt::ItemIsEditable;
+
+ return flags;
+}
+
+void BeataModel::reload(const QModelIndex &index1, const QModelIndex &index2)
+{
+ emit dataChanged(index1, index2);
+}
+
+void BeataModel::resetModel()
+{
+ reset();
+}
+
+void BeataModel::changeLayout()
+{
+ emit layoutChanged();
+}
+
+void BeataModel::incomingChangeLayout()
+{
+ emit layoutAboutToBeChanged();
+}
+
+/////////////////////
+// In-Memory model //
+/////////////////////
+
+void BeataMemModel::loadLayer()
+{
+ BeataModel::loadLayer();
+ mLayer->select(mLayer->pendingAllAttributesList(), QgsRectangle(), false);
+
+ QgsFeature f;
+ while (mLayer->nextFeature(f))
+ mFeatureMap.insert(f.id(), f);
+}
+
+BeataMemModel::BeataMemModel
+(QgsVectorLayer *theLayer)
+: BeataModel(theLayer)
+{
+ loadLayer();
+}
+
+QVariant BeataMemModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid() || (role != Qt::TextAlignmentRole && role != Qt::DisplayRole && role != Qt::EditRole))
+ return QVariant();
+
+ QVariant::Type fldType = mLayer->dataProvider()->fields()[index.column()].type();
+ bool fldNumeric = (fldType == QVariant::Int || fldType == QVariant::Double);
+
+ if (role == Qt::TextAlignmentRole)
+ {
+ if (fldNumeric)
+ return QVariant(Qt::AlignRight);
+ else
+ return QVariant(Qt::AlignLeft);
+ }
+
+ // if we don't have the row in current cache, load it from layer first
+ if (mLastRowId != rowToId(index.row()))
+ {
+ //bool res = mLayer->featureAtId(rowToId(index.row()), mFeat, false, true);
+ bool res = mFeatureMap.contains(rowToId(index.row()));
+
+ if (!res)
+ return QVariant("ERROR");
+
+ mLastRowId = rowToId(index.row());
+ mFeat = mFeatureMap[rowToId(index.row())];
+ mLastRow = (QgsAttributeMap *)(&(mFeat.attributeMap()));
+ }
+
+ QVariant& val = (*mLastRow)[index.column()];
+
+ if (val.isNull())
+ {
+ // if the value is NULL, show that in table, but don't show "NULL" text in editor
+ if (role == Qt::EditRole)
+ return QVariant();
+ else
+ return QVariant("NULL");
+ }
+
+ // force also numeric data for EditRole to be strings
+ // otherwise it creates spinboxes instead of line edits
+ // (probably not what we do want)
+ if (fldNumeric && role == Qt::EditRole)
+ return val.toString();
+
+ // convert to QString from some other representation
+ // this prevents displaying greater numbers in exponential format
+ return val.toString();
+}
+
+bool BeataMemModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ if (!index.isValid() || role != Qt::EditRole)
+ return false;
+
+ if (!mLayer->isEditable())
+ return false;
+
+ //bool res = mLayer->featureAtId(rowToId(index.row()), mFeat, false, true);
+ bool res = mFeatureMap.contains(rowToId(index.row()));
+
+ if (res) {
+ mLastRowId = rowToId(index.row());
+ mFeat = mFeatureMap[rowToId(index.row())];
+ mLastRow = (QgsAttributeMap *)(&(mFeat.attributeMap()));
+
+
+ //std::cout << mFeatureMap[rowToId(index.row())].id();
+ mFeatureMap[rowToId(index.row())].changeAttribute(index.column(), value);
+ // propagate back to the layer
+ mLayer->changeAttributeValue(rowToId(index.row()), index.column(), value, true);
+ }
+
+ if (!mLayer->isModified())
+ return false;
+
+ emit dataChanged(index, index);
+ return true;
+}
+
+void BeataMemModel::featureDeleted(int fid)
+{
+std::cout << "BMM feature deleted\n";
+ mFeatureMap.remove(fid);
+ BeataModel::featureDeleted(fid);
+}
+
+void BeataMemModel::featureAdded(int fid)
+{
+ std::cout << "BMM feature added\n";
+ QgsFeature f;
+ mLayer->featureAtId(fid, f, false, true);
+ mFeatureMap.insert(fid, f);
+ BeataModel::featureAdded(fid);
+}
+
+/*void BeataMemModel::attributeAdded (int idx)
+{
+ std::cout << "attribute added\n";
+ loadLayer();
+ reload(index(0,0), index(rowCount(), columnCount()));
+}
+
+void BeataMemModel::attributeDeleted (int idx)
+{
+ std::cout << "attribute deleted\n";
+ loadLayer();
+ reload(index(0,0), index(rowCount(), columnCount()));
+}
+ */
+void BeataMemModel::layerDeleted ()
+{
+ std::cout << "BMM layer del\n";
+ mFeatureMap.clear();
+ BeataModel::layerDeleted();
+}
+
+void BeataMemModel::attributeValueChanged (int fid, int idx, const QVariant &value)
+{
+ std::cout << "BMM attribute changed\n";
+ mFeatureMap[fid].changeAttribute(idx, value);
+ reload(index(0,0), index(rowCount(), columnCount()));
+}
Added: trunk/qgis/src/app/attributetable/BeataModel.h
===================================================================
--- trunk/qgis/src/app/attributetable/BeataModel.h (rev 0)
+++ trunk/qgis/src/app/attributetable/BeataModel.h 2009-03-20 18:24:19 UTC (rev 10337)
@@ -0,0 +1,141 @@
+/***************************************************************************
+ BeataModel.h
+ BEtter Attribute TAble
+ -------------------
+ date : Feb 2009
+ copyright : Vita Cizek
+ email : weetya (at) gmail.com
+
+ ***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef BEATAMODEL_H
+#define BEATAMODEL_H
+
+#include <QAbstractTableModel>
+#include <QSortFilterProxyModel>
+#include <QModelIndex>
+#include <QObject>
+
+//QGIS Includes
+#include "qgis.h"
+#include "qgsfeature.h" //QgsAttributeMap
+#include "qgsvectorlayer.h" //QgsAttributeList
+
+class idColumnPair
+{
+public:
+ int id;
+ QVariant columnItem;
+
+ bool operator<(const idColumnPair &b) const;
+};
+
+class BeataFilterModel: public QSortFilterProxyModel
+{
+public:
+ BeataFilterModel(QgsVectorLayer* theLayer);
+ //QModelIndex mapToSource ( const QModelIndex & filterIndex ) const;
+ //QModelIndex mapFromSource ( const QModelIndex & sourceIndex ) const;
+ bool mHideUnselected;
+ virtual void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
+protected:
+ bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
+private:
+ QgsVectorLayer* mLayer;
+};
+
+
+class BeataModel: public QAbstractTableModel
+{
+Q_OBJECT
+
+public:
+ BeataModel(QgsVectorLayer *theLayer, QObject *parent = 0);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+
+ QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
+ virtual QVariant data(const QModelIndex &index, int role) const;
+ virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+ Qt::ItemFlags flags(const QModelIndex &index) const;
+
+ void reload(const QModelIndex &index1, const QModelIndex &index2);
+ void resetModel();
+ void changeLayout();
+ void incomingChangeLayout();
+ int idToRow(const int id) const;
+ int rowToId(const int id) const;
+ virtual void sort(int column, Qt::SortOrder order = Qt::AscendingOrder);
+ void swapRows(int a, int b);
+
+ QgsVectorLayer* layer() const { return mLayer; }
+
+signals:
+ void modelChanged();
+ void setNumRows(int oldNum, int newNum);
+
+private slots:
+ virtual void attributeAdded (int idx);
+ virtual void attributeDeleted (int idx);
+ virtual void attributeValueChanged (int fid, int idx, const QVariant &value);
+ virtual void layerModified(bool onlyGeometry);
+
+protected slots:
+ virtual void featureDeleted(int fid);
+ virtual void featureAdded(int fid);
+ virtual void layerDeleted ();
+
+protected:
+ QgsVectorLayer *mLayer;
+ int mFeatureCount;
+ int mFieldCount;
+ mutable int mLastRowId;
+ mutable QgsFeature mFeat;
+
+ mutable QgsAttributeMap *mLastRow;
+ QgsAttributeList mAttributes;
+
+ QList<idColumnPair> mSortList;
+ QMap<int, int> mIdRowMap;
+ QMap<int, int> mRowIdMap;
+
+ void initIdMaps();
+ virtual void loadLayer();
+
+};
+
+class BeataMemModel: public BeataModel
+{
+Q_OBJECT
+
+public:
+ BeataMemModel(QgsVectorLayer *theLayer);//, QObject *parent = 0);
+
+protected slots:
+ virtual void featureDeleted(int fid);
+ virtual void featureAdded(int fid);
+ virtual void layerDeleted ();
+
+private slots:
+ //virtual void attributeAdded (int idx);
+ //virtual void attributeDeleted (int idx);
+ virtual void attributeValueChanged (int fid, int idx, const QVariant &value);
+ //virtual void layerModified(bool onlyGeometry);
+
+private:
+ virtual QVariant data(const QModelIndex &index, int role) const;
+ virtual bool setData(const QModelIndex &index, const QVariant &value, int role);
+ virtual void loadLayer();
+
+ QMap<int, QgsFeature> mFeatureMap;
+};
+
+#endif
Added: trunk/qgis/src/app/attributetable/BeataView.cpp
===================================================================
--- trunk/qgis/src/app/attributetable/BeataView.cpp (rev 0)
+++ trunk/qgis/src/app/attributetable/BeataView.cpp 2009-03-20 18:24:19 UTC (rev 10337)
@@ -0,0 +1,144 @@
+/***************************************************************************
+ BeataView.cpp
+ --------------------------------------
+ Date : Feb 2009
+ Copyright : (C) 2009 Vita Cizek
+ Email : weetya (at) gmail.com
+ ***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include <QModelIndex>
+#include <QItemDelegate>
+#include <QHeaderView>
+#include <QSettings>
+#include <QLineEdit>
+#include <QPainter>
+#include <QKeyEvent>
+
+#include "BeataView.h"
+#include "BeataModel.h"
+
+#include "qgslogger.h"
+#include "qgsvectorlayer.h"
+#include "qgsvectordataprovider.h"
+
+
+class BeataDelegate : public QItemDelegate
+{
+public:
+ BeataDelegate(QObject* parent = NULL) : QItemDelegate(parent) {}
+
+ QWidget * 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 ) return editor;
+
+ const BeataModel* m = dynamic_cast<const BeataModel*>(index.model());
+ if ( !m ) return editor;
+
+ int col = index.column();
+ QVariant::Type type = m->layer()->dataProvider()->fields()[col].type();
+
+ if ( type == QVariant::Int )
+ {
+ le->setValidator( new QIntValidator( le ) );
+ }
+ else if ( type == QVariant::Double )
+ {
+ le->setValidator( new QDoubleValidator( le ) );
+ }
+
+ return editor;
+ }
+
+
+ void paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
+ {
+ QItemDelegate::paint(painter, option, index);
+
+ if (option.state & QStyle::State_HasFocus)
+ {
+ QRect r = option.rect.adjusted(1,1,-1,-1);
+ QPen p(QBrush(QColor(0,255,127)), 2);
+ painter->save();
+ painter->setPen(p);
+ painter->drawRect(r);
+ painter->restore();
+ }
+ }
+
+};
+
+BeataView::BeataView(QWidget* parent)
+ : QTableView(parent)
+{
+ QSettings settings;
+ restoreGeometry(settings.value("/BetterTable/geometry").toByteArray());
+
+ verticalHeader()->setDefaultSectionSize(20);
+ horizontalHeader()->setHighlightSections(false);
+
+ setItemDelegate(new BeataDelegate(this));
+
+ setSelectionBehavior(QAbstractItemView::SelectRows);
+ setSelectionMode(QAbstractItemView::NoSelection);
+ setSortingEnabled(true);
+
+ shiftPressed = false;
+ ctrlPressed = false;
+}
+
+void BeataView::setLayer(QgsVectorLayer* layer)
+{
+ BeataModel *bModel;
+
+ if (layer->dataProvider()->capabilities() & QgsVectorDataProvider::RandomSelectGeometryAtId)
+ bModel = new BeataModel(layer);
+ else
+ bModel = new BeataMemModel(layer);
+
+ BeataFilterModel* bfModel = new BeataFilterModel(layer);
+ bfModel->setSourceModel(bModel);
+
+ setModel(bfModel);
+}
+
+BeataView::~BeataView()
+{
+}
+
+void BeataView::closeEvent(QCloseEvent *event)
+{
+ QSettings settings;
+ settings.setValue("/BetterAttributeTable/geometry", QVariant(saveGeometry()));
+}
+
+void BeataView::keyPressEvent(QKeyEvent *event)
+{
+ // shift pressed
+ if (event->key() == Qt::Key_Shift)// && event->modifiers() & Qt::ShiftModifier)
+ shiftPressed = true;
+ else if (event->key() == Qt::Key_Control)
+ ctrlPressed = true;
+ else
+ QTableView::keyPressEvent(event);
+}
+
+void BeataView::keyReleaseEvent(QKeyEvent *event)
+{
+ // workaround for some Qt bug
+ if (event->key() == Qt::Key_Shift || event->key() == 0xffffffff)
+ shiftPressed = false;
+ else if (event->key() == Qt::Key_Control)
+ ctrlPressed = false;
+ else
+ QTableView::keyReleaseEvent(event);
+}
Added: trunk/qgis/src/app/attributetable/BeataView.h
===================================================================
--- trunk/qgis/src/app/attributetable/BeataView.h (rev 0)
+++ trunk/qgis/src/app/attributetable/BeataView.h 2009-03-20 18:24:19 UTC (rev 10337)
@@ -0,0 +1,44 @@
+/***************************************************************************
+ BeataView.h
+ --------------------------------------
+ Date : Feb 2009
+ Copyright : (C) 2009 Vita Cizek
+ Email : weetya (at) gmail.com
+ ***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef BEATAVIEW_H_
+#define BEATAVIEW_H_
+
+#include <QTableView>
+
+class QgsVectorLayer;
+
+
+class BeataView: public QTableView
+{
+//private slots:
+ //void setRows(int rows);
+
+public:
+ BeataView(QWidget* parent = NULL);
+ virtual ~BeataView();
+
+ void setLayer(QgsVectorLayer* layer);
+
+ void closeEvent(QCloseEvent *event);
+ void keyPressEvent(QKeyEvent *event);
+ void keyReleaseEvent(QKeyEvent *event);
+
+ //make those private
+ bool shiftPressed;
+ bool ctrlPressed;
+};
+
+#endif
Modified: trunk/qgis/src/app/legend/qgslegend.cpp
===================================================================
--- trunk/qgis/src/app/legend/qgslegend.cpp 2009-03-20 17:35:32 UTC (rev 10336)
+++ trunk/qgis/src/app/legend/qgslegend.cpp 2009-03-20 18:24:19 UTC (rev 10337)
@@ -39,6 +39,8 @@
#include "qgsvectorlayerproperties.h"
#include "qgsattributetabledisplay.h"
+#include "BeataDialog.h"
+
#include <cfloat>
#include <iostream>
@@ -1859,7 +1861,9 @@
if ( vlayer )
{
- QgsAttributeTableDisplay::attributeTable( vlayer );
+ BeataDialog *mDialog = new BeataDialog(vlayer);
+ mDialog->show();
+ // the dialog will be deleted by itself on close
}
else
{
Modified: trunk/qgis/src/app/legend/qgslegendlayerfile.cpp
===================================================================
--- trunk/qgis/src/app/legend/qgslegendlayerfile.cpp 2009-03-20 17:35:32 UTC (rev 10336)
+++ trunk/qgis/src/app/legend/qgslegendlayerfile.cpp 2009-03-20 18:24:19 UTC (rev 10337)
@@ -35,6 +35,9 @@
#include "qgsattributetable.h"
#include "qgsattributetabledisplay.h"
+#include "BeataDialog.h"
+
+
#include "qgsencodingfiledialog.h"
#include <QApplication>
@@ -217,7 +220,10 @@
void QgsLegendLayerFile::table()
{
- QgsAttributeTableDisplay::attributeTable( dynamic_cast<QgsVectorLayer*>( mLyr.layer() ) );
+ QgsVectorLayer * myLayer = dynamic_cast<QgsVectorLayer *>(mLyr.layer());
+ BeataDialog *mDialog = new BeataDialog(myLayer);
+ mDialog->show();
+ // the dialog will be deleted by itself on close
}
void QgsLegendLayerFile::saveSelectionAsShapefile()
Modified: trunk/qgis/src/app/qgisapp.cpp
===================================================================
--- trunk/qgis/src/app/qgisapp.cpp 2009-03-20 17:35:32 UTC (rev 10336)
+++ trunk/qgis/src/app/qgisapp.cpp 2009-03-20 18:24:19 UTC (rev 10337)
@@ -133,6 +133,7 @@
#include "qgsvectordataprovider.h"
#include "qgsvectorlayer.h"
#include "ogr/qgsopenvectorlayerdialog.h"
+#include "BeataDialog.h"
//
// Gdal/Ogr includes
//
@@ -3713,7 +3714,10 @@
return;
}
- QgsAttributeTableDisplay::attributeTable( dynamic_cast<QgsVectorLayer *>( mMapLegend->currentLayer() ) );
+ QgsVectorLayer * myLayer = dynamic_cast<QgsVectorLayer *>(mMapLegend->currentLayer());
+ BeataDialog *mDialog = new BeataDialog(myLayer);
+ mDialog->show();
+ // the dialog will be deleted by itself on close
}
void QgisApp::saveAsShapefile()
More information about the QGIS-commit
mailing list