New class QgsBookmarkManagerModel

Move bookmark model logic to core, add tests
This commit is contained in:
Nyall Dawson 2019-09-04 06:50:47 +10:00
parent aa3a83c7bd
commit 1afa6a8ec5
10 changed files with 762 additions and 550 deletions

View File

@ -0,0 +1,77 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgsbookmarkmodel.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsBookmarkManagerModel: QAbstractTableModel
{
%Docstring
Implements a model for the contents of QgsBookmarkManager objects.
QgsBookmarkModel provides a Qt table model for displaying and manipulating
the bookmarks managed by a QgsBookmarkManager object. The model requires
both a main manager (usually the application bookmark manager, accessed
via QgsApplication.bookmarkManager()) and a project-based manager. The resultant
model data is a merge of the bookmarks stored in both managers.
.. versionadded:: 3.10
%End
%TypeHeaderCode
#include "qgsbookmarkmodel.h"
%End
public:
enum Columns
{
ColumnName,
ColumnGroup,
ColumnXMin,
ColumnYMin,
ColumnXMax,
ColumnYMax,
ColumnCrs,
ColumnStore,
};
QgsBookmarkManagerModel( QgsBookmarkManager *manager, QgsBookmarkManager *projectManager = 0, QObject *parent = 0 );
%Docstring
Constructor for QgsBookmarkManagerModel, associated with a main ``manager``
(usually the application bookmark manager, accessed via QgsApplication.bookmarkManager())
and a secondary ``projectManager`` (a project based bookmark manager).
%End
virtual int rowCount( const QModelIndex &parent = QModelIndex() ) const;
virtual int columnCount( const QModelIndex &parent = QModelIndex() ) const;
virtual QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const;
virtual Qt::ItemFlags flags( const QModelIndex &index ) const;
virtual bool setData( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole );
virtual bool insertRows( int row, int count, const QModelIndex &parent = QModelIndex() );
virtual bool removeRows( int row, int count, const QModelIndex &parent = QModelIndex() );
virtual QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const;
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/qgsbookmarkmodel.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -342,6 +342,7 @@
%Include auto_generated/qgsauxiliarystorage.sip
%Include auto_generated/qgsblockingnetworkrequest.sip
%Include auto_generated/qgsbookmarkmanager.sip
%Include auto_generated/qgsbookmarkmodel.sip
%Include auto_generated/qgsbrowsermodel.sip
%Include auto_generated/qgsbrowserproxymodel.sip
%Include auto_generated/qgscoordinatereferencesystem.sip

Binary file not shown.

View File

@ -24,6 +24,7 @@
#include "qgssettings.h"
#include "qgsgui.h"
#include "qgsbookmarkmanager.h"
#include "qgsbookmarkmodel.h"
#include "qgsmessagebar.h"
#include <QFileDialog>
@ -71,36 +72,19 @@ QgsBookmarks::QgsBookmarks( QWidget *parent )
mBookmarkToolbar->addWidget( btnImpExp );
mQgisModel = new QgsBookmarkManagerModel( QgsApplication::bookmarkManager(), this );
mProjectModel = new QgsBookmarkManagerModel( QgsProject::instance()->bookmarkManager(), this );
mMergedModel = new QgsMergedBookmarksTableModel( *mQgisModel, *mProjectModel, lstBookmarks, this );
mBookmarkModel = new QgsBookmarkManagerModel( QgsApplication::bookmarkManager(), QgsProject::instance()->bookmarkManager(), this );
mProxyModel = new QgsBookmarksProxyModel( );
mProxyModel->setSourceModel( mMergedModel );
mProxyModel->setSortCaseSensitivity( Qt::CaseInsensitive );
lstBookmarks->setModel( mProxyModel );
lstBookmarks->setModel( mBookmarkModel );
lstBookmarks->setItemDelegate( new QgsDoubleSpinBoxBookmarksDelegate( this ) );
lstBookmarks->setSortingEnabled( true );
lstBookmarks->sortByColumn( 1, Qt::AscendingOrder );
connect( mMergedModel, &QgsMergedBookmarksTableModel::selectItem, this, [ = ]( const QModelIndex & index )
{
QModelIndex proxyIndex( mProxyModel->mapFromSource( index ) );
lstBookmarks->scrollTo( proxyIndex );
lstBookmarks->setCurrentIndex( proxyIndex );
} );
connect( mMergedModel, &QgsMergedBookmarksTableModel::layoutChanged, mProxyModel, &QgsBookmarksProxyModel::_resetModel );
QgsSettings settings;
lstBookmarks->header()->restoreState( settings.value( QStringLiteral( "Windows/Bookmarks/headerstate" ) ).toByteArray() );
}
QgsBookmarks::~QgsBookmarks()
{
delete mQgisModel;
delete mProxyModel;
saveWindowLocation();
}
@ -112,9 +96,6 @@ void QgsBookmarks::saveWindowLocation()
void QgsBookmarks::addClicked()
{
Q_ASSERT( mMergedModel );
Q_ASSERT( mQgisModel );
QgsMapCanvas *canvas = QgisApp::instance()->mapCanvas();
Q_ASSERT( canvas );
@ -138,7 +119,7 @@ void QgsBookmarks::addClicked()
b.setExtent( QgsReferencedRectangle( canvas->extent(), canvas->mapSettings().destinationCrs() ) );
QgsApplication::bookmarkManager()->addBookmark( b );
QModelIndex newIdx = mProxyModel->mapFromSource( mMergedModel->index( mQgisModel->rowCount() - 1, 0 ) );
QModelIndex newIdx = mBookmarkModel->index( QgsApplication::bookmarkManager()->bookmarks().count() - 1, 0 );
// Edit new bookmark title
lstBookmarks->scrollTo( newIdx );
lstBookmarks->setCurrentIndex( newIdx );
@ -147,7 +128,7 @@ void QgsBookmarks::addClicked()
void QgsBookmarks::deleteClicked()
{
QItemSelection selection( mProxyModel->mapSelectionToSource( lstBookmarks->selectionModel()->selection() ) );
QItemSelection selection = lstBookmarks->selectionModel()->selection();
std::vector<int> rows;
for ( const auto &selectedIdx : selection.indexes() )
{
@ -169,9 +150,8 @@ void QgsBookmarks::deleteClicked()
for ( const auto &row : rows )
{
mMergedModel->removeRow( row );
mBookmarkModel->removeRow( row );
}
mProxyModel->_resetModel();
}
void QgsBookmarks::lstBookmarks_doubleClicked( const QModelIndex &index )
@ -237,18 +217,16 @@ void QgsBookmarks::importFromXml()
{
QgisApp::instance()->messageBar()->pushSuccess( tr( "Import Bookmarks" ), tr( "Bookmarks imported successfully" ) );
}
mProxyModel->_resetModel();
}
QMap<QString, QModelIndex> QgsBookmarks::getIndexMap()
{
QMap<QString, QModelIndex> map;
int rowCount = mMergedModel->rowCount();
int rowCount = mBookmarkModel->rowCount();
for ( int i = 0; i < rowCount; ++i )
{
QModelIndex idx = mMergedModel->index( i, 1 ); //Name col
QModelIndex idx = mBookmarkModel->index( i, 1 ); //Name col
if ( idx.isValid() )
{
QString name = idx.data( Qt::DisplayRole ).toString();
@ -297,422 +275,9 @@ void QgsBookmarks::exportToXml()
settings.setValue( QStringLiteral( "Windows/Bookmarks/LastUsedDirectory" ), QFileInfo( fileName ).path() );
}
QgsBookmarkManagerModel::QgsBookmarkManagerModel( QgsBookmarkManager *manager, QObject *parent )
: QAbstractTableModel( parent )
, mManager( manager )
{
connect(
mManager, &QgsBookmarkManager::bookmarkAdded,
this, &QgsBookmarkManagerModel::bookmarkAdded );
connect(
mManager, &QgsBookmarkManager::bookmarkAboutToBeAdded,
this, &QgsBookmarkManagerModel::bookmarkAboutToBeAdded );
connect(
mManager, &QgsBookmarkManager::bookmarkRemoved,
this, &QgsBookmarkManagerModel::bookmarkRemoved );
connect(
mManager, &QgsBookmarkManager::bookmarkAboutToBeRemoved,
this, &QgsBookmarkManagerModel::bookmarkAboutToBeRemoved );
connect(
mManager, &QgsBookmarkManager::bookmarkChanged,
this, &QgsBookmarkManagerModel::bookmarkChanged );
}
int QgsBookmarkManagerModel::rowCount( const QModelIndex &parent ) const
{
Q_UNUSED( parent )
return mManager->bookmarks().count();
}
int QgsBookmarkManagerModel::columnCount( const QModelIndex &parent ) const
{
Q_UNUSED( parent )
return 7;
}
QVariant QgsBookmarkManagerModel::data( const QModelIndex &index, int role ) const
{
if ( role != Qt::DisplayRole && role != Qt::EditRole )
{
return QVariant();
}
QgsBookmark b = mManager->bookmarks().at( index.row() );
switch ( index.column() )
{
case 0:
return b.name();
case 1:
return b.group();
case 2:
return b.extent().xMinimum();
case 3:
return b.extent().yMinimum();
case 4:
return b.extent().xMaximum();
case 5:
return b.extent().yMaximum();
case 6:
return b.extent().crs().authid();
default:
return QVariant();
}
}
bool QgsBookmarkManagerModel::setData( const QModelIndex &index, const QVariant &value, int role )
{
Q_UNUSED( role )
Q_ASSERT( role == Qt::EditRole );
QgsBookmark b = mManager->bookmarks().at( index.row() );
QgsReferencedRectangle extent = b.extent();
switch ( index.column() )
{
case 0:
b.setName( value.toString() );
break;
case 1:
b.setGroup( value.toString() );
break;
case 2:
{
bool ok = false;
extent.setXMinimum( value.toDouble( &ok ) );
if ( !ok )
return false;
break;
}
case 3:
{
bool ok = false;
extent.setYMinimum( value.toDouble( &ok ) );
if ( !ok )
return false;
break;
}
case 4:
{
bool ok = false;
extent.setXMaximum( value.toDouble( &ok ) );
if ( !ok )
return false;
break;
}
case 5:
{
bool ok = false;
extent.setYMaximum( value.toDouble( &ok ) );
if ( !ok )
return false;
break;
}
case 6:
{
QgsCoordinateReferenceSystem crs;
if ( !crs.createFromString( value.toString() ) )
return false;
extent.setCrs( crs );
break;
}
default:
return false;
}
b.setExtent( extent );
return mManager->updateBookmark( b );
}
bool QgsBookmarkManagerModel::insertRows( int row, int count, const QModelIndex &parent )
{
Q_UNUSED( parent )
Q_UNUSED( row )
// append
int oldCount = mManager->bookmarks().count();
beginInsertRows( parent, oldCount, oldCount + count );
bool result = true;
for ( int i = 0; i < count; ++i )
{
bool res = false;
mBlocked = true;
mManager->addBookmark( QgsBookmark(), &res );
mBlocked = false;
result &= res;
}
endInsertRows();
return result;
}
bool QgsBookmarkManagerModel::removeRows( int row, int count, const QModelIndex &parent )
{
Q_UNUSED( parent )
beginRemoveRows( parent, row, row + count );
QList< QgsBookmark > bookmarks = mManager->bookmarks();
for ( int r = row + count - 1; r >= row; --r )
{
mManager->removeBookmark( bookmarks.at( r ).id() );
}
endRemoveRows();
return true;
}
void QgsBookmarkManagerModel::bookmarkAboutToBeAdded( const QString & )
{
if ( mBlocked )
return;
beginInsertRows( QModelIndex(), mManager->bookmarks().count(), mManager->bookmarks().count() );
}
void QgsBookmarkManagerModel::bookmarkAdded( const QString & )
{
if ( mBlocked )
return;
endInsertRows();
}
void QgsBookmarkManagerModel::bookmarkAboutToBeRemoved( const QString &id )
{
if ( mBlocked )
return;
QList< QgsBookmark > bookmarks = mManager->bookmarks();
bool found = false;
int i = 0;
for ( i = 0; i < bookmarks.count(); ++i )
{
if ( bookmarks.at( i ).id() == id )
{
found = true;
break;
}
}
if ( !found )
return;
beginRemoveRows( QModelIndex(), i, i );
}
void QgsBookmarkManagerModel::bookmarkRemoved( const QString & )
{
if ( mBlocked )
return;
endRemoveRows();
}
void QgsBookmarkManagerModel::bookmarkChanged( const QString &id )
{
if ( mBlocked )
return;
QList< QgsBookmark > bookmarks = mManager->bookmarks();
bool found = false;
int i = 0;
for ( i = 0; i < bookmarks.count(); ++i )
{
if ( bookmarks.at( i ).id() == id )
{
found = true;
break;
}
}
if ( !found )
return;
emit dataChanged( index( i, 0 ), index( i, columnCount() - 1 ) );
}
QgsMergedBookmarksTableModel::QgsMergedBookmarksTableModel( QAbstractTableModel &qgisTableModel, QAbstractTableModel &projectTableModel, QTreeView *treeView, QObject *parent )
: QAbstractTableModel( parent )
, mQgisTableModel( qgisTableModel )
, mProjectTableModel( projectTableModel )
, mTreeView( treeView )
{
connect(
&mQgisTableModel, &QAbstractTableModel::layoutChanged,
this, &QgsMergedBookmarksTableModel::allLayoutChanged );
connect(
&mQgisTableModel, &QAbstractTableModel::rowsInserted,
this, &QgsMergedBookmarksTableModel::allLayoutChanged );
connect(
&mQgisTableModel, &QAbstractTableModel::rowsRemoved,
this, &QgsMergedBookmarksTableModel::allLayoutChanged );
connect(
&projectTableModel, &QAbstractTableModel::layoutChanged,
this, &QgsMergedBookmarksTableModel::allLayoutChanged );
connect(
&projectTableModel, &QAbstractTableModel::rowsInserted,
this, &QgsMergedBookmarksTableModel::allLayoutChanged );
connect(
&projectTableModel, &QAbstractTableModel::rowsRemoved,
this, &QgsMergedBookmarksTableModel::allLayoutChanged );
}
int QgsMergedBookmarksTableModel::rowCount( const QModelIndex &parent ) const
{
return mQgisTableModel.rowCount( parent ) + mProjectTableModel.rowCount( parent );
}
int QgsMergedBookmarksTableModel::columnCount( const QModelIndex &parent ) const
{
return mQgisTableModel.columnCount( parent ) + 1;
}
QVariant QgsMergedBookmarksTableModel::data( const QModelIndex &index, int role ) const
{
QVariant value;
// Is it checkbox column?
if ( index.column() == mQgisTableModel.columnCount() && role == Qt::CheckStateRole )
{
value = index.row() < mQgisTableModel.rowCount() ? Qt::Unchecked : Qt::Checked;
}
else
{
// Is it a SQLite stored entry ?
if ( index.row() < mQgisTableModel.rowCount() )
{
value = mQgisTableModel.data( index, role );
}
else // ... it is a project stored bookmark
{
value = mProjectTableModel.data( this->index( index.row() - mQgisTableModel.rowCount(), index.column() ), role );
}
}
return value;
}
bool QgsMergedBookmarksTableModel::setData( const QModelIndex &index, const QVariant &value, int role )
{
bool result = false;
// last column triggers a move from QGIS to project bookmark
if ( index.column() == mQgisTableModel.columnCount() )
{
if ( index.row() < mQgisTableModel.rowCount() )
{
// Move from application storage to project
const QString id = QgsApplication::bookmarkManager()->bookmarks().at( index.row() ).id();
QgsApplication::bookmarkManager()->moveBookmark( id, QgsProject::instance()->bookmarkManager() );
emit selectItem( this->index( rowCount() - 1, 1 ) );
}
else
{
//Move from project to application storage
const QString id = QgsProject::instance()->bookmarkManager()->bookmarks().at( index.row() - mQgisTableModel.rowCount() ).id();
QgsProject::instance()->bookmarkManager()->moveBookmark( id, QgsApplication::bookmarkManager() );
emit selectItem( this->index( mQgisTableModel.rowCount() - 1, 1 ) );
}
result = true;
}
else
{
if ( index.row() < mQgisTableModel.rowCount() )
{
result = mQgisTableModel.setData( index, value, role );
}
else
{
result = mProjectTableModel.setData( this->index( index.row() - mQgisTableModel.rowCount(), index.column() ), value, role );
}
}
if ( result )
emit dataChanged( index, index );
return result;
}
Qt::ItemFlags QgsMergedBookmarksTableModel::flags( const QModelIndex &index ) const
{
Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
if ( index.column() == mQgisTableModel.columnCount() )
{
if ( !projectAvailable() )
{
return Qt::ItemIsSelectable;
}
flags |= Qt::ItemIsUserCheckable;
}
else
{
// Skip projection: not editable!
if ( index.column() != mQgisTableModel.columnCount() - 1 )
flags |= Qt::ItemIsEditable;
}
return flags;
}
bool QgsMergedBookmarksTableModel::removeRows( int row, int count, const QModelIndex &parent )
{
Q_ASSERT( count == 1 );
bool result;
if ( row < mQgisTableModel.rowCount() )
{
result = mQgisTableModel.removeRows( row, count, parent );
}
else
{
result = mProjectTableModel.removeRows( row - mQgisTableModel.rowCount(), count, parent );
}
allLayoutChanged();
return result;
}
QVariant QgsMergedBookmarksTableModel::headerData( int section, Qt::Orientation orientation, int role ) const
{
if ( role == Qt::DisplayRole )
{
switch ( section )
{
case 0:
return tr( "Name" );
case 1:
return tr( "Group" );
case 2:
return tr( "xMin" );
case 3:
return tr( "yMin" );
case 4:
return tr( "xMax" );
case 5:
return tr( "yMax" );
case 6:
return tr( "CRS" );
case 7:
return tr( "In Project" );
}
}
return mQgisTableModel.headerData( section, orientation, role );
}
QAbstractTableModel *QgsMergedBookmarksTableModel::qgisModel()
{
return &mQgisTableModel;
}
bool QgsMergedBookmarksTableModel::projectAvailable() const
{
return ! QgsProject::instance()->fileName().isEmpty();
}
QgsBookmarksProxyModel::QgsBookmarksProxyModel( QObject *parent ):
QSortFilterProxyModel( parent )
{
}
QVariant QgsBookmarksProxyModel::headerData( int section, Qt::Orientation orientation, int role ) const
{
return sourceModel()->headerData( section, orientation, role );
}
//
// QgsDoubleSpinBoxBookmarksDelegate
//
QgsDoubleSpinBoxBookmarksDelegate::QgsDoubleSpinBoxBookmarksDelegate( QObject *parent )
: QStyledItemDelegate( parent )

View File

@ -27,62 +27,7 @@
class QgsBookmark;
class QgsBookmarkManager;
/*
* Model for project bookmarks
*/
class QgsBookmarkManagerModel: public QAbstractTableModel
{
Q_OBJECT
public:
QgsBookmarkManagerModel( QgsBookmarkManager *manager, QObject *parent = nullptr );
int rowCount( const QModelIndex &parent = QModelIndex() ) const override;
int columnCount( const QModelIndex &parent = QModelIndex() ) const override;
QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const override;
bool setData( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole ) override;
bool insertRows( int row, int count, const QModelIndex &parent = QModelIndex() ) override;
bool removeRows( int row, int count, const QModelIndex &parent = QModelIndex() ) override;
private slots:
void bookmarkAboutToBeAdded( const QString &id );
void bookmarkAdded( const QString &id );
void bookmarkAboutToBeRemoved( const QString &id );
void bookmarkRemoved( const QString &id );
void bookmarkChanged( const QString &id );
private:
bool mBlocked = false;
QgsBookmarkManager *mManager = nullptr;
};
class QgsBookmarksProxyModel: public QSortFilterProxyModel
{
Q_OBJECT
public:
QgsBookmarksProxyModel( QObject *parent = nullptr );
//! This override is required because the merge model only defines headers for the SQL model
QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const override;
public slots:
void _resetModel()
{
reset();
}
};
class QgsBookmarkManagerModel;
/**
* \brief QgsDoubleSpinBoxBookmarksDelegate class shows 6 digits when value is a double
@ -106,47 +51,6 @@ class QgsDoubleSpinBoxBookmarksDelegate : public QStyledItemDelegate
};
/*
* Model that merge the QGIS and project model
*/
class QgsMergedBookmarksTableModel: public QAbstractTableModel
{
Q_OBJECT
public:
QgsMergedBookmarksTableModel( QAbstractTableModel &qgisTableModel, QAbstractTableModel &projectTableModel, QTreeView *treeView, QObject *parent = nullptr );
int rowCount( const QModelIndex &parent = QModelIndex() ) const override;
int columnCount( const QModelIndex &parent = QModelIndex() ) const override;
QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const override;
bool setData( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole ) override;
Qt::ItemFlags flags( const QModelIndex &index ) const override;
bool removeRows( int row, int count, const QModelIndex &parent = QModelIndex() ) override;
QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const override;
QAbstractTableModel *qgisModel();
private:
QAbstractTableModel &mQgisTableModel;
QAbstractTableModel &mProjectTableModel;
QTreeView *mTreeView = nullptr;
bool projectAvailable() const;
signals:
void selectItem( const QModelIndex &index );
private slots:
void allLayoutChanged()
{
emit layoutChanged();
}
};
class APP_EXPORT QgsBookmarks : public QgsDockWidget, private Ui::QgsBookmarksBase
{
@ -170,10 +74,7 @@ class APP_EXPORT QgsBookmarks : public QgsDockWidget, private Ui::QgsBookmarksBa
void lstBookmarks_doubleClicked( const QModelIndex & );
private:
QgsBookmarkManagerModel *mQgisModel = nullptr;
QgsBookmarkManagerModel *mProjectModel = nullptr;
QgsMergedBookmarksTableModel *mMergedModel = nullptr;
QgsBookmarksProxyModel *mProxyModel = nullptr;
QgsBookmarkManagerModel *mBookmarkModel = nullptr;
void saveWindowLocation();

View File

@ -192,6 +192,7 @@ SET(QGIS_CORE_SRCS
qgsbearingutils.cpp
qgsblockingnetworkrequest.cpp
qgsbookmarkmanager.cpp
qgsbookmarkmodel.cpp
qgsbrowsermodel.cpp
qgsbrowserproxymodel.cpp
qgscachedfeatureiterator.cpp
@ -653,6 +654,7 @@ SET(QGIS_CORE_MOC_HDRS
qgsauxiliarystorage.h
qgsblockingnetworkrequest.h
qgsbookmarkmanager.h
qgsbookmarkmodel.h
qgsbrowsermodel.h
qgsbrowserproxymodel.h
qgscoordinatereferencesystem.h

View File

@ -0,0 +1,351 @@
/***************************************************************************
qgsbookmarkmodel.cpp
--------------------
Date : September 2019
Copyright : (C) 2019 Nyall Dawson
Email : nyall dot dawson at gmail dot 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 "qgsbookmarkmodel.h"
#include "qgsbookmarkmanager.h"
QgsBookmarkManagerModel::QgsBookmarkManagerModel( QgsBookmarkManager *manager, QgsBookmarkManager *projectManager, QObject *parent )
: QAbstractTableModel( parent )
, mManager( manager )
, mProjectManager( projectManager )
{
for ( QgsBookmarkManager *manager : { manager, projectManager } )
{
connect( manager, &QgsBookmarkManager::bookmarkAdded, this, &QgsBookmarkManagerModel::bookmarkAdded );
connect( manager, &QgsBookmarkManager::bookmarkAboutToBeAdded, this, &QgsBookmarkManagerModel::bookmarkAboutToBeAdded );
connect( manager, &QgsBookmarkManager::bookmarkRemoved, this, &QgsBookmarkManagerModel::bookmarkRemoved );
connect( manager, &QgsBookmarkManager::bookmarkAboutToBeRemoved, this, &QgsBookmarkManagerModel::bookmarkAboutToBeRemoved );
connect( manager, &QgsBookmarkManager::bookmarkChanged, this, &QgsBookmarkManagerModel::bookmarkChanged );
}
}
int QgsBookmarkManagerModel::rowCount( const QModelIndex & ) const
{
return mManager->bookmarks().count() + mProjectManager->bookmarks().count();
}
int QgsBookmarkManagerModel::columnCount( const QModelIndex & ) const
{
return ColumnStore + 1;
}
QVariant QgsBookmarkManagerModel::data( const QModelIndex &index, int role ) const
{
if ( !index.isValid() )
return QVariant();
QgsBookmark b = bookmarkForIndex( index );
const int managerCount = mManager->bookmarks().count();
switch ( role )
{
case Qt::DisplayRole:
case Qt::EditRole:
{
switch ( index.column() )
{
case ColumnName:
return b.name();
case ColumnGroup:
return b.group();
case ColumnXMin:
return b.extent().xMinimum();
case ColumnYMin:
return b.extent().yMinimum();
case ColumnXMax:
return b.extent().xMaximum();
case ColumnYMax:
return b.extent().yMaximum();
case ColumnCrs:
return b.extent().crs().authid();
case ColumnStore:
return QVariant();
}
break;
}
case Qt::CheckStateRole:
{
if ( index.column() == ColumnStore )
return index.row() < managerCount ? Qt::Unchecked : Qt::Checked;
break;
}
}
return QVariant();
}
Qt::ItemFlags QgsBookmarkManagerModel::flags( const QModelIndex &index ) const
{
if ( !index.isValid() || index.row() < 0 || index.row() >= rowCount() )
return nullptr;
Qt::ItemFlags flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
if ( index.column() == ColumnStore )
{
flags |= Qt::ItemIsUserCheckable;
}
else
{
// projection column is not editable!
if ( index.column() != ColumnCrs )
flags |= Qt::ItemIsEditable;
}
return flags;
}
bool QgsBookmarkManagerModel::setData( const QModelIndex &index, const QVariant &value, int role )
{
if ( !index.isValid() )
return false;
QgsBookmark b = bookmarkForIndex( index );
const int managerCount = mManager->bookmarks().count();
switch ( role )
{
case Qt::EditRole:
{
QgsReferencedRectangle extent = b.extent();
switch ( index.column() )
{
case ColumnName:
b.setName( value.toString() );
break;
case ColumnGroup:
b.setGroup( value.toString() );
break;
case ColumnXMin:
{
bool ok = false;
extent.setXMinimum( value.toDouble( &ok ) );
if ( !ok )
return false;
break;
}
case ColumnYMin:
{
bool ok = false;
extent.setYMinimum( value.toDouble( &ok ) );
if ( !ok )
return false;
break;
}
case ColumnXMax:
{
bool ok = false;
extent.setXMaximum( value.toDouble( &ok ) );
if ( !ok )
return false;
break;
}
case ColumnYMax:
{
bool ok = false;
extent.setYMaximum( value.toDouble( &ok ) );
if ( !ok )
return false;
break;
}
case ColumnCrs:
{
QgsCoordinateReferenceSystem crs;
if ( !crs.createFromString( value.toString() ) )
return false;
extent.setCrs( crs );
break;
}
default:
return false;
}
b.setExtent( extent );
return index.row() < managerCount ? mManager->updateBookmark( b ) : mProjectManager->updateBookmark( b );
}
case Qt::CheckStateRole:
{
if ( index.column() != ColumnStore )
return false;
if ( index.row() < managerCount )
{
if ( value.toInt() != Qt::Checked )
return false;
return mManager->moveBookmark( b.id(), mProjectManager );
}
else
{
if ( value.toInt() != Qt::Unchecked )
return false;
return mProjectManager->moveBookmark( b.id(), mManager );
}
}
}
return false;
}
bool QgsBookmarkManagerModel::insertRows( int, int count, const QModelIndex &parent )
{
// append
int oldCount = mManager->bookmarks().count();
beginInsertRows( parent, oldCount, oldCount + count );
bool result = true;
for ( int i = 0; i < count; ++i )
{
bool res = false;
mBlocked = true;
mManager->addBookmark( QgsBookmark(), &res );
mBlocked = false;
result &= res;
}
endInsertRows();
return result;
}
bool QgsBookmarkManagerModel::removeRows( int row, int count, const QModelIndex &parent )
{
beginRemoveRows( parent, row, row + count );
QList< QgsBookmark > bookmarks = mManager->bookmarks();
for ( int r = row + count - 1; r >= row; --r )
{
mManager->removeBookmark( bookmarks.at( r ).id() );
}
endRemoveRows();
return true;
}
QVariant QgsBookmarkManagerModel::headerData( int section, Qt::Orientation orientation, int role ) const
{
if ( role == Qt::DisplayRole )
{
switch ( section )
{
case ColumnName:
return tr( "Name" );
case ColumnGroup:
return tr( "Group" );
case ColumnXMin:
return tr( "xMin" );
case ColumnYMin:
return tr( "yMin" );
case ColumnXMax:
return tr( "xMax" );
case ColumnYMax:
return tr( "yMax" );
case ColumnCrs:
return tr( "CRS" );
case ColumnStore:
return tr( "In Project" );
}
}
return QAbstractTableModel::headerData( section, orientation, role );
}
void QgsBookmarkManagerModel::bookmarkAboutToBeAdded( const QString & )
{
if ( mBlocked )
return;
if ( qobject_cast< QgsBookmarkManager * >( sender() ) == mManager )
beginInsertRows( QModelIndex(), mManager->bookmarks().count(), mManager->bookmarks().count() );
else
beginInsertRows( QModelIndex(), mManager->bookmarks().count() + mProjectManager->bookmarks().count(),
mManager->bookmarks().count() + mProjectManager->bookmarks().count() );
}
void QgsBookmarkManagerModel::bookmarkAdded( const QString & )
{
if ( mBlocked )
return;
endInsertRows();
}
void QgsBookmarkManagerModel::bookmarkAboutToBeRemoved( const QString &id )
{
if ( mBlocked )
return;
QgsBookmarkManager *manager = qobject_cast< QgsBookmarkManager * >( sender() );
QList< QgsBookmark > bookmarks = manager->bookmarks();
bool found = false;
int i = 0;
for ( i = 0; i < bookmarks.count(); ++i )
{
if ( bookmarks.at( i ).id() == id )
{
found = true;
break;
}
}
if ( !found )
return;
if ( manager == mManager )
beginRemoveRows( QModelIndex(), i, i );
else
beginRemoveRows( QModelIndex(), mManager->bookmarks().count() + i,
mManager->bookmarks().count() + i );
}
void QgsBookmarkManagerModel::bookmarkRemoved( const QString & )
{
if ( mBlocked )
return;
endRemoveRows();
}
void QgsBookmarkManagerModel::bookmarkChanged( const QString &id )
{
if ( mBlocked )
return;
QgsBookmarkManager *manager = qobject_cast< QgsBookmarkManager * >( sender() );
QList< QgsBookmark > bookmarks = manager->bookmarks();
bool found = false;
int i = 0;
for ( i = 0; i < bookmarks.count(); ++i )
{
if ( bookmarks.at( i ).id() == id )
{
found = true;
break;
}
}
if ( !found )
return;
if ( manager == mManager )
emit dataChanged( index( i, 0 ), index( i, columnCount() - 1 ) );
else
emit dataChanged( index( mManager->bookmarks().count() + i, 0 ), index( mManager->bookmarks().count() + i, columnCount() - 1 ) );
}
QgsBookmark QgsBookmarkManagerModel::bookmarkForIndex( const QModelIndex &index ) const
{
if ( !index.isValid() )
return QgsBookmark();
const int managerCount = mManager->bookmarks().count();
const int projectCount = mProjectManager->bookmarks().count();
if ( index.row() < managerCount )
return mManager->bookmarks().at( index.row() );
else if ( index.row() < managerCount + projectCount )
return mProjectManager->bookmarks().at( index.row() - managerCount );
return QgsBookmark();
}

View File

@ -0,0 +1,91 @@
/***************************************************************************
qgsbookmarkmodel.h
------------------
Date : Septemeber 2019
Copyright : (C) 2019 Nyall Dawson
Email : nyall dot dawson at gmail dot 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 QGSBOOKMARKMODEL_H
#define QGSBOOKMARKMODEL_H
#include "qgis_core.h"
#include "qgis_sip.h"
#include <QAbstractTableModel>
class QgsBookmarkManager;
class QgsBookmark;
/**
* \ingroup core
* \class QgsBookmarkModel
*
* \brief Implements a model for the contents of QgsBookmarkManager objects.
*
* QgsBookmarkModel provides a Qt table model for displaying and manipulating
* the bookmarks managed by a QgsBookmarkManager object. The model requires
* both a main manager (usually the application bookmark manager, accessed
* via QgsApplication::bookmarkManager()) and a project-based manager. The resultant
* model data is a merge of the bookmarks stored in both managers.
*
* \since QGIS 3.10
*/
class CORE_EXPORT QgsBookmarkManagerModel: public QAbstractTableModel
{
Q_OBJECT
public:
//! Model columns
enum Columns
{
ColumnName, //!< Name column
ColumnGroup, //!< Group column
ColumnXMin, //!< Extent x-minimum
ColumnYMin, //!< Extent y-minimum
ColumnXMax, //!< Extent x-maximum
ColumnYMax, //!< Extent y-maxnimum
ColumnCrs, //!< CRS of extent
ColumnStore, //!< Manager storing the bookmark (TRUE if stored in project bookmark manager)
};
/**
* Constructor for QgsBookmarkManagerModel, associated with a main \a manager
* (usually the application bookmark manager, accessed via QgsApplication::bookmarkManager())
* and a secondary \a projectManager (a project based bookmark manager).
*/
QgsBookmarkManagerModel( QgsBookmarkManager *manager, QgsBookmarkManager *projectManager = nullptr, QObject *parent = nullptr );
int rowCount( const QModelIndex &parent = QModelIndex() ) const override;
int columnCount( const QModelIndex &parent = QModelIndex() ) const override;
QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const override;
Qt::ItemFlags flags( const QModelIndex &index ) const override;
bool setData( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole ) override;
bool insertRows( int row, int count, const QModelIndex &parent = QModelIndex() ) override;
bool removeRows( int row, int count, const QModelIndex &parent = QModelIndex() ) override;
QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const override;
private slots:
void bookmarkAboutToBeAdded( const QString &id );
void bookmarkAdded( const QString &id );
void bookmarkAboutToBeRemoved( const QString &id );
void bookmarkRemoved( const QString &id );
void bookmarkChanged( const QString &id );
private:
bool mBlocked = false;
QgsBookmarkManager *mManager = nullptr;
QgsBookmarkManager *mProjectManager = nullptr;
QgsBookmark bookmarkForIndex( const QModelIndex &index ) const;
};
#endif // QGSBOOKMARKMODEL_H

View File

@ -11,9 +11,6 @@ ENDIF (WITH_SERVER)
ADD_PYTHON_TEST(PyCoreAdittions test_core_additions.py)
ADD_PYTHON_TEST(PyPythonRepr test_python_repr.py)
ADD_PYTHON_TEST(PyQgsActionManager test_qgsactionmanager.py)
ADD_PYTHON_TEST(PyQgsBookmarkManager test_qgsbookmarkmanager.py)
ADD_PYTHON_TEST(PyQgsProviderConnectionPostgres test_qgsproviderconnection_postgres.py)
ADD_PYTHON_TEST(PyQgsProviderConnectionGpkg test_qgsproviderconnection_ogr_gpkg.py)
ADD_PYTHON_TEST(PyQgsAFSProvider test_provider_afs.py)
ADD_PYTHON_TEST(PyQgsAlignmentComboBox test_qgsalignmentcombobox.py)
ADD_PYTHON_TEST(PyQgsPythonProvider test_provider_python.py)
@ -29,6 +26,8 @@ ADD_PYTHON_TEST(PyQgsBearingUtils test_qgsbearingutils.py)
ADD_PYTHON_TEST(PyQgsBinaryWidget test_qgsbinarywidget.py)
ADD_PYTHON_TEST(PyQgsBlendModes test_qgsblendmodes.py)
ADD_PYTHON_TEST(PyQgsBlockingNetworkRequest test_qgsblockingnetworkrequest.py)
ADD_PYTHON_TEST(PyQgsBookmarkManager test_qgsbookmarkmanager.py)
ADD_PYTHON_TEST(PyQgsBookmarkModel test_qgsbookmarkmodel.py)
ADD_PYTHON_TEST(PyQgsBox3d test_qgsbox3d.py)
ADD_PYTHON_TEST(PyQgsCategorizedSymbolRenderer test_qgscategorizedsymbolrenderer.py)
ADD_PYTHON_TEST(PyQgsCheckableComboBox test_qgscheckablecombobox.py)
@ -174,6 +173,8 @@ ADD_PYTHON_TEST(PyQgsImportIntoPostGIS test_processing_importintopostgis.py)
ADD_PYTHON_TEST(PyQgsProjectionSelectionWidgets test_qgsprojectionselectionwidgets.py)
ADD_PYTHON_TEST(PyQgsProjectMetadata test_qgsprojectmetadata.py)
ADD_PYTHON_TEST(PyQgsPropertyOverrideButton test_qgspropertyoverridebutton.py)
ADD_PYTHON_TEST(PyQgsProviderConnectionPostgres test_qgsproviderconnection_postgres.py)
ADD_PYTHON_TEST(PyQgsProviderConnectionGpkg test_qgsproviderconnection_ogr_gpkg.py)
ADD_PYTHON_TEST(PyQgsRange test_qgsrange.py)
ADD_PYTHON_TEST(PyQgsRangeWidgets test_qgsrangewidgets.py)
ADD_PYTHON_TEST(PyQgsRasterBandComboBox test_qgsrasterbandcombobox.py)

View File

@ -0,0 +1,223 @@
# -*- coding: utf-8 -*-
"""QGIS Unit tests for QgsBookmarkModel.
.. note:: 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.
"""
__author__ = '(C) 2019 by Nyall Dawson'
__date__ = '02/09/2019'
__copyright__ = 'Copyright 2019, The QGIS Project'
import qgis # NOQA
from qgis.PyQt.QtCore import Qt, QCoreApplication, QLocale
from qgis.core import (QgsBookmark,
QgsBookmarkManager,
QgsBookmarkManagerModel,
QgsProject,
QgsReferencedRectangle,
QgsRectangle,
QgsCoordinateReferenceSystem,
QgsSettings)
from qgis.testing import start_app, unittest
from utilities import unitTestDataPath
start_app()
TEST_DATA_DIR = unitTestDataPath()
class TestQgsBookmarkManagerModel(unittest.TestCase):
@classmethod
def setUpClass(cls):
"""Run before all tests"""
QCoreApplication.setOrganizationName("QGIS_Test")
QCoreApplication.setOrganizationDomain("QGIS_TestQgsBookmarkManager.com")
QCoreApplication.setApplicationName("QGIS_TestQgsBookmarkManager")
QgsSettings().clear()
QLocale.setDefault(QLocale(QLocale.English))
start_app()
def testBookmarkModel(self):
p = QgsProject()
project_manager = QgsBookmarkManager.createProjectBasedManager(p)
app_manager = QgsBookmarkManager()
# initially no bookmarks
model = QgsBookmarkManagerModel(app_manager, project_manager)
self.assertEqual(model.rowCount(), 0)
self.assertEqual(model.columnCount(), 8)
self.assertFalse(model.data(model.index(-1, 0)))
self.assertFalse(model.data(model.index(1, 0)))
self.assertFalse(model.data(model.index(0, 0)))
self.assertEqual(model.headerData(0, Qt.Horizontal), 'Name')
self.assertEqual(model.headerData(9, Qt.Horizontal), 10)
self.assertEqual(model.headerData(-1, Qt.Horizontal), 0)
self.assertFalse(model.setData(model.index(-1, 0), 4, Qt.EditRole))
self.assertFalse(model.setData(model.index(0, 0), 4, Qt.EditRole))
self.assertFalse(int(model.flags(model.index(0, 0)) & Qt.ItemIsEnabled))
self.assertFalse(int(model.flags(model.index(0, 0)) & Qt.ItemIsEditable))
# add some bookmarks
b = QgsBookmark()
b.setId('1')
b.setGroup('group 1')
b.setName('b1')
b.setExtent(QgsReferencedRectangle(QgsRectangle(11, 21, 31, 41), QgsCoordinateReferenceSystem('EPSG:4326')))
b2 = QgsBookmark()
b2.setId('2')
b2.setGroup('group 2')
b2.setName('b2')
b2.setExtent(QgsReferencedRectangle(QgsRectangle(12, 22, 32, 42), QgsCoordinateReferenceSystem('EPSG:4326')))
app_manager.addBookmark(b)
app_manager.addBookmark(b2)
self.assertEqual(model.rowCount(), 2)
self.assertFalse(model.data(model.index(-1, 0)))
self.assertEqual(model.data(model.index(0, 0)), 'b1')
self.assertEqual(model.data(model.index(0, 1)), 'group 1')
self.assertEqual(model.data(model.index(0, 2)), 11.0)
self.assertEqual(model.data(model.index(0, 3)), 21.0)
self.assertEqual(model.data(model.index(0, 4)), 31.0)
self.assertEqual(model.data(model.index(0, 5)), 41.0)
self.assertEqual(model.data(model.index(0, 6)), 'EPSG:4326')
self.assertEqual(model.data(model.index(0, 7)), None)
self.assertEqual(model.data(model.index(0, 7), Qt.CheckStateRole), Qt.Unchecked)
self.assertEqual(model.data(model.index(1, 0)), 'b2')
self.assertEqual(model.data(model.index(1, 1)), 'group 2')
self.assertEqual(model.data(model.index(1, 2)), 12.0)
self.assertEqual(model.data(model.index(1, 3)), 22.0)
self.assertEqual(model.data(model.index(1, 4)), 32.0)
self.assertEqual(model.data(model.index(1, 5)), 42.0)
self.assertEqual(model.data(model.index(1, 6)), 'EPSG:4326')
self.assertEqual(model.data(model.index(1, 7)), None)
self.assertEqual(model.data(model.index(1, 7), Qt.CheckStateRole), Qt.Unchecked)
self.assertFalse(model.data(model.index(2, 0)))
self.assertFalse(model.setData(model.index(-1, 0), 4, Qt.EditRole))
self.assertTrue(model.setData(model.index(0, 0), 'new name', Qt.EditRole))
self.assertEqual(model.data(model.index(0, 0)), 'new name')
self.assertEqual(app_manager.bookmarks()[0].name(), 'new name')
self.assertTrue(model.setData(model.index(1, 1), 'new group', Qt.EditRole))
self.assertEqual(model.data(model.index(1, 1)), 'new group')
self.assertEqual(app_manager.bookmarks()[1].group(), 'new group')
self.assertTrue(model.setData(model.index(0, 2), 1, Qt.EditRole))
self.assertEqual(model.data(model.index(0, 2)), 1.0)
self.assertEqual(app_manager.bookmarks()[0].extent().xMinimum(), 1.0)
self.assertTrue(model.setData(model.index(0, 3), 2, Qt.EditRole))
self.assertEqual(model.data(model.index(0, 3)), 2.0)
self.assertEqual(app_manager.bookmarks()[0].extent().yMinimum(), 2.0)
self.assertTrue(model.setData(model.index(0, 4), 3, Qt.EditRole))
self.assertEqual(model.data(model.index(0, 4)), 3.0)
self.assertEqual(app_manager.bookmarks()[0].extent().xMaximum(), 3.0)
self.assertTrue(model.setData(model.index(0, 5), 4, Qt.EditRole))
self.assertEqual(model.data(model.index(0, 5)), 4.0)
self.assertEqual(app_manager.bookmarks()[0].extent().yMaximum(), 4.0)
self.assertFalse(model.setData(model.index(2, 0), 4, Qt.EditRole))
self.assertTrue(int(model.flags(model.index(0, 0)) & Qt.ItemIsEnabled))
self.assertTrue(int(model.flags(model.index(0, 0)) & Qt.ItemIsEditable))
self.assertTrue(int(model.flags(model.index(0, 7)) & Qt.ItemIsUserCheckable))
self.assertTrue(int(model.flags(model.index(1, 7)) & Qt.ItemIsUserCheckable))
self.assertTrue(int(model.flags(model.index(1, 0)) & Qt.ItemIsEnabled))
self.assertTrue(int(model.flags(model.index(1, 0)) & Qt.ItemIsEditable))
self.assertFalse(int(model.flags(model.index(2, 0)) & Qt.ItemIsEnabled))
self.assertFalse(int(model.flags(model.index(2, 0)) & Qt.ItemIsEditable))
self.assertFalse(int(model.flags(model.index(2, 7)) & Qt.ItemIsUserCheckable))
# add bookmark to project manager
b3 = QgsBookmark()
b3.setId('3')
b3.setName('b3')
b3.setGroup('group 3')
b3.setExtent(QgsReferencedRectangle(QgsRectangle(32, 32, 33, 43), QgsCoordinateReferenceSystem('EPSG:28355')))
project_manager.addBookmark(b3)
self.assertEqual(model.rowCount(), 3)
self.assertFalse(model.data(model.index(-1, 0)))
self.assertEqual(model.data(model.index(0, 0)), 'new name')
self.assertEqual(model.data(model.index(0, 1)), 'group 1')
self.assertEqual(model.data(model.index(0, 2)), 1.0)
self.assertEqual(model.data(model.index(0, 3)), 2.0)
self.assertEqual(model.data(model.index(0, 4)), 3.0)
self.assertEqual(model.data(model.index(0, 5)), 4.0)
self.assertEqual(model.data(model.index(0, 6)), 'EPSG:4326')
self.assertEqual(model.data(model.index(0, 7)), None)
self.assertEqual(model.data(model.index(0, 7), Qt.CheckStateRole), Qt.Unchecked)
self.assertEqual(model.data(model.index(1, 0)), 'b2')
self.assertEqual(model.data(model.index(1, 1)), 'new group')
self.assertEqual(model.data(model.index(1, 2)), 12.0)
self.assertEqual(model.data(model.index(1, 3)), 22.0)
self.assertEqual(model.data(model.index(1, 4)), 32.0)
self.assertEqual(model.data(model.index(1, 5)), 42.0)
self.assertEqual(model.data(model.index(1, 6)), 'EPSG:4326')
self.assertEqual(model.data(model.index(1, 7)), None)
self.assertEqual(model.data(model.index(1, 7), Qt.CheckStateRole), Qt.Unchecked)
self.assertEqual(model.data(model.index(2, 0)), 'b3')
self.assertEqual(model.data(model.index(2, 1)), 'group 3')
self.assertEqual(model.data(model.index(2, 2)), 32.0)
self.assertEqual(model.data(model.index(2, 3)), 32.0)
self.assertEqual(model.data(model.index(2, 4)), 33.0)
self.assertEqual(model.data(model.index(2, 5)), 43.0)
self.assertEqual(model.data(model.index(2, 6)), 'EPSG:28355')
self.assertEqual(model.data(model.index(2, 7)), None)
self.assertEqual(model.data(model.index(2, 7), Qt.CheckStateRole), Qt.Checked)
self.assertFalse(model.data(model.index(3, 0)))
self.assertTrue(model.setData(model.index(2, 0), 'new name 2', Qt.EditRole))
self.assertEqual(model.data(model.index(2, 0)), 'new name 2')
self.assertEqual(project_manager.bookmarks()[0].name(), 'new name 2')
self.assertTrue(model.setData(model.index(2, 1), 'new group', Qt.EditRole))
self.assertEqual(model.data(model.index(2, 1)), 'new group')
self.assertEqual(project_manager.bookmarks()[0].group(), 'new group')
self.assertTrue(model.setData(model.index(2, 2), 1, Qt.EditRole))
self.assertEqual(model.data(model.index(2, 2)), 1.0)
self.assertEqual(project_manager.bookmarks()[0].extent().xMinimum(), 1.0)
self.assertTrue(model.setData(model.index(2, 3), 2, Qt.EditRole))
self.assertEqual(model.data(model.index(2, 3)), 2.0)
self.assertEqual(project_manager.bookmarks()[0].extent().yMinimum(), 2.0)
self.assertTrue(model.setData(model.index(2, 4), 3, Qt.EditRole))
self.assertEqual(model.data(model.index(2, 4)), 3.0)
self.assertEqual(project_manager.bookmarks()[0].extent().xMaximum(), 3.0)
self.assertTrue(model.setData(model.index(2, 5), 4, Qt.EditRole))
self.assertEqual(model.data(model.index(2, 5)), 4.0)
self.assertEqual(project_manager.bookmarks()[0].extent().yMaximum(), 4.0)
self.assertFalse(model.setData(model.index(3, 0), 4, Qt.EditRole))
self.assertTrue(int(model.flags(model.index(0, 0)) & Qt.ItemIsEnabled))
self.assertTrue(int(model.flags(model.index(0, 0)) & Qt.ItemIsEditable))
self.assertTrue(int(model.flags(model.index(0, 7)) & Qt.ItemIsUserCheckable))
self.assertTrue(int(model.flags(model.index(1, 7)) & Qt.ItemIsUserCheckable))
self.assertTrue(int(model.flags(model.index(1, 0)) & Qt.ItemIsEnabled))
self.assertTrue(int(model.flags(model.index(1, 0)) & Qt.ItemIsEditable))
self.assertTrue(int(model.flags(model.index(2, 0)) & Qt.ItemIsEnabled))
self.assertTrue(int(model.flags(model.index(2, 0)) & Qt.ItemIsEditable))
self.assertTrue(int(model.flags(model.index(2, 7)) & Qt.ItemIsUserCheckable))
self.assertFalse(int(model.flags(model.index(3, 0)) & Qt.ItemIsEnabled))
self.assertFalse(int(model.flags(model.index(3, 0)) & Qt.ItemIsEditable))
self.assertFalse(int(model.flags(model.index(3, 7)) & Qt.ItemIsUserCheckable))
# try transferring bookmark from app->project
self.assertTrue(model.setData(model.index(1, 7), Qt.Checked, Qt.CheckStateRole))
self.assertEqual([b.name() for b in project_manager.bookmarks()], ['new name 2', 'b2'])
self.assertEqual([b.name() for b in app_manager.bookmarks()], ['new name'])
self.assertFalse(model.setData(model.index(1, 7), Qt.Checked, Qt.CheckStateRole))
# try transferring bookmark from project->app
self.assertTrue(model.setData(model.index(1, 7), Qt.Unchecked, Qt.CheckStateRole))
self.assertEqual([b.name() for b in project_manager.bookmarks()], ['b2'])
self.assertEqual([b.name() for b in app_manager.bookmarks()], ['new name', 'new name 2'])
self.assertFalse(model.setData(model.index(1, 7), Qt.Unchecked, Qt.CheckStateRole))
if __name__ == '__main__':
unittest.main()