Skip to content
Permalink
Browse files

[FEATURE][locator] Add search for settings pages to locator bar (#6625)

* [FEATURE][locator] Add search for settings pages to locator bar

Search Settings, Options, and Project Properties pages. Double clicking a search result will open the correct page and tab.

Short video: https://www.youtube.com/watch?v=duB2YekUmV0

The new filter presents itself with a prefix of "s" and with tr( "Settings" ) as displayname.

A settings locator filter is added to the built in locator filters (class QgsSettingsLocatorFilter is added to qgsinbuiltlocatorfilters.cpp). The wiring between the new filter and QgsApp has been implemented in:

For reading misc. pages:
* QgisApp::getProjectPropertiesPagesMap(),
* QgisApp::getSettingPagesMap(), and
* QgisApp::getOptionsPagesMap()

For navigating to selected page
* QgisApp::showProjectProperties( const QString &page ) and
* QgisApp::showSettings( const QString &page )

* Implement requested changes

* Implement required changes
  • Loading branch information
klavspc authored and nyalldawson committed May 14, 2018
1 parent 3ea6432 commit 49090a5554be2d59b07064090c6031a1efa86d54
@@ -339,6 +339,94 @@ void QgsExpressionCalculatorLocatorFilter::triggerResult( const QgsLocatorResult
{
QApplication::clipboard()->setText( result.userData.toString() );
}

// SettingsLocatorFilter
//
QgsSettingsLocatorFilter::QgsSettingsLocatorFilter( QObject *parent )
: QgsLocatorFilter( parent )
{}

QgsSettingsLocatorFilter *QgsSettingsLocatorFilter::clone() const
{
return new QgsSettingsLocatorFilter();
}

void QgsSettingsLocatorFilter::fetchResults( const QString &string, const QgsLocatorContext &context, QgsFeedback * )
{
QMap<QString, QMap<QString, QString>> matchingSettingsPagesMap;

QMap<QString, QString> optionsPagesMap = QgisApp::instance()->optionsPagesMap();
for ( auto optionsPagesIterator = optionsPagesMap.constBegin(); optionsPagesIterator != optionsPagesMap.constEnd(); ++optionsPagesIterator )
{
QString title = optionsPagesIterator.key();
if ( stringMatches( title, string ) || ( context.usingPrefix && string.isEmpty() ) )
{
matchingSettingsPagesMap.insert( title + " (" + tr( "Options" ) + ")", settingsPage( QStringLiteral( "optionpage" ), optionsPagesIterator.value() ) );
}
}

QMap<QString, QString> projectPropertyPagesMap = QgisApp::instance()->projectPropertiesPagesMap();
for ( auto projectPropertyPagesIterator = projectPropertyPagesMap.constBegin(); projectPropertyPagesIterator != projectPropertyPagesMap.constEnd(); ++projectPropertyPagesIterator )
{
QString title = projectPropertyPagesIterator.key();
if ( stringMatches( title, string ) || ( context.usingPrefix && string.isEmpty() ) )
{
matchingSettingsPagesMap.insert( title + " (" + tr( "Project Properties" ) + ")", settingsPage( QStringLiteral( "projectpropertypage" ), projectPropertyPagesIterator.value() ) );
}
}

QMap<QString, QString> settingPagesMap = QgisApp::instance()->settingPagesMap();
for ( auto settingPagesIterator = settingPagesMap.constBegin(); settingPagesIterator != settingPagesMap.constEnd(); ++settingPagesIterator )
{
QString title = settingPagesIterator.key();
if ( stringMatches( title, string ) || ( context.usingPrefix && string.isEmpty() ) )
{
matchingSettingsPagesMap.insert( title, settingsPage( QStringLiteral( "settingspage" ), settingPagesIterator.value() ) );
}
}

for ( auto matchingSettingsPagesIterator = matchingSettingsPagesMap.constBegin(); matchingSettingsPagesIterator != matchingSettingsPagesMap.constEnd(); ++matchingSettingsPagesIterator )
{
QString title = matchingSettingsPagesIterator.key();
QMap<QString, QString> settingsPage = matchingSettingsPagesIterator.value();
QgsLocatorResult result;
result.filter = this;
result.displayString = title;
result.userData.setValue( settingsPage );
result.score = static_cast< double >( string.length() ) / title.length();
emit resultFetched( result );
}
}

QMap<QString, QString> QgsSettingsLocatorFilter::settingsPage( const QString &type, const QString &page )
{
QMap<QString, QString> returnPage;
returnPage.insert( "type", type );
returnPage.insert( "page", page );
return returnPage;
}

void QgsSettingsLocatorFilter::triggerResult( const QgsLocatorResult &result )
{

QMap<QString, QString> settingsPage = qvariant_cast<QMap<QString, QString>>( result.userData );
QString type = settingsPage.value( "type" );
QString page = settingsPage.value( "page" );

if ( type == "optionpage" )
{
QgisApp::instance()->showOptionsDialog( QgisApp::instance(), page );
}
else if ( type == "projectpropertypage" )
{
QgisApp::instance()->showProjectProperties( page );
}
else if ( type == "settingspage" )
{
QgisApp::instance()->showSettings( page );
}
}

// QgBookmarkLocatorFilter
//

@@ -372,13 +460,12 @@ void QgsBookmarkLocatorFilter::fetchResults( const QString &string, const QgsLoc
result.filter = this;
result.displayString = name;
result.userData = index;
//TODO Create svg for "Bookmark"?
//result.icon = TBD
//TODO Create svg for "Bookmark"
//TODO result.icon =
result.score = static_cast< double >( string.length() ) / name.length();
emit resultFetched( result );
}
}

}

void QgsBookmarkLocatorFilter::triggerResult( const QgsLocatorResult &result )
@@ -141,14 +141,35 @@ class QgsBookmarkLocatorFilter : public QgsLocatorFilter
QgsBookmarkLocatorFilter( QObject *parent = nullptr );
QgsBookmarkLocatorFilter *clone() const override;
QString name() const override { return QStringLiteral( "bookmarks" ); }
QString displayName() const override { return tr( "Spatial bookmarks" ); }
QString displayName() const override { return tr( "Spatial Bookmarks" ); }
Priority priority() const override { return Highest; }
QString prefix() const override { return QStringLiteral( "b" ); }
QgsLocatorFilter::Flags flags() const override { return QgsLocatorFilter::FlagFast; }

void fetchResults( const QString &string, const QgsLocatorContext &context, QgsFeedback *feedback ) override;
void triggerResult( const QgsLocatorResult &result ) override;
};

class QgsSettingsLocatorFilter : public QgsLocatorFilter
{
Q_OBJECT

public:

QgsSettingsLocatorFilter( QObject *parent = nullptr );
QgsSettingsLocatorFilter *clone() const override;
QString name() const override { return QStringLiteral( "optionpages" ); }
QString displayName() const override { return tr( "Settings" ); }
Priority priority() const override { return Highest; }
QString prefix() const override { return QStringLiteral( "set" ); }
QgsLocatorFilter::Flags flags() const override { return QgsLocatorFilter::FlagFast; }

void fetchResults( const QString &string, const QgsLocatorContext &context, QgsFeedback *feedback ) override;
void triggerResult( const QgsLocatorResult &result ) override;

private:

QMap<QString, QString> settingsPage( const QString &type, const QString &page );
};

#endif // QGSINBUILTLOCATORFILTERS_H
@@ -731,6 +731,7 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, bool skipVersionCh

QgsSettings settings;


startProfile( QStringLiteral( "Building style sheet" ) );
// set up stylesheet builder and apply saved or default style options
mStyleSheetBuilder = new QgisAppStyleSheet( this );
@@ -2096,7 +2097,7 @@ void QgisApp::createActions()
connect( mActionToggleFullScreen, &QAction::triggered, this, &QgisApp::toggleFullScreen );
connect( mActionTogglePanelsVisibility, &QAction::triggered, this, &QgisApp::togglePanelsVisibility );
connect( mActionToggleMapOnly, &QAction::triggered, this, &QgisApp::toggleMapOnly );
connect( mActionProjectProperties, &QAction::triggered, this, &QgisApp::projectProperties );
connect( mActionProjectProperties, &QAction::triggered, this, [ = ] {projectProperties( QString() );} );
connect( mActionOptions, &QAction::triggered, this, &QgisApp::options );
connect( mActionCustomProjection, &QAction::triggered, this, &QgisApp::customProjection );
connect( mActionConfigureShortcuts, &QAction::triggered, this, &QgisApp::configureShortcuts );
@@ -3012,6 +3013,7 @@ void QgisApp::createStatusBar()
mLocatorWidget->locator()->registerFilter( new QgsActiveLayerFeaturesLocatorFilter() );
mLocatorWidget->locator()->registerFilter( new QgsExpressionCalculatorLocatorFilter() );
mLocatorWidget->locator()->registerFilter( new QgsBookmarkLocatorFilter() );
mLocatorWidget->locator()->registerFilter( new QgsSettingsLocatorFilter() );
}

void QgisApp::setIconSizes( int size )
@@ -9960,6 +9962,70 @@ void QgisApp::options()
showOptionsDialog( this );
}

QMap< QString, QString > QgisApp::projectPropertiesPagesMap()
{
if ( mProjectPropertiesPagesMap.isEmpty() )
{
std::unique_ptr< QgsProjectProperties > pp( new QgsProjectProperties( mMapCanvas, this ) );
mProjectPropertiesPagesMap = pp->pageWidgetNameMap();
}
return mProjectPropertiesPagesMap;
}

void QgisApp::showProjectProperties( const QString &page )
{
projectProperties( page );
}

QMap< QString, QString > QgisApp::settingPagesMap()
{
if ( mSettingPagesMap.isEmpty() )
{
mSettingPagesMap.insert( tr( "Style Manager" ), "stylemanager" );
mSettingPagesMap.insert( tr( "Keyboard Shortcuts" ), "shortcuts" );
mSettingPagesMap.insert( tr( "Custom Projections" ), "customprojection" );
mSettingPagesMap.insert( tr( "Interface Customization" ), "customize" );
}
return mSettingPagesMap;
}

void QgisApp::showSettings( const QString &page )
{
if ( page == "stylemanager" )
{
showStyleManager();
}
else if ( page == "shortcuts" )
{
configureShortcuts();
}
else if ( page == "customprojection" )
{
customProjection();
}
else if ( page == "customize" )
{
customize();
}
}

QMap< QString, QString > QgisApp::optionsPagesMap()
{
if ( mOptionsPagesMap.isEmpty() )
{
QList< QgsOptionsWidgetFactory * > factories;
Q_FOREACH ( const QPointer< QgsOptionsWidgetFactory > &f, mOptionsWidgetFactories )
{
// remove any deleted factories
if ( f )
factories << f;
}
std::unique_ptr< QgsOptions > f( new QgsOptions( this, QgsGuiUtils::ModalDialogFlags, factories ) );
mOptionsPagesMap = f->pageWidgetNameMap();
}
return mOptionsPagesMap;
}

void QgisApp::showOptionsDialog( QWidget *parent, const QString &currentPage )
{
QgsSettings mySettings;
@@ -10238,11 +10304,15 @@ void QgisApp::unregisterMapLayerPropertiesFactory( QgsMapLayerConfigWidgetFactor
void QgisApp::registerOptionsWidgetFactory( QgsOptionsWidgetFactory *factory )
{
mOptionsWidgetFactories << factory;
//clear mOptionsPagesMap forcing it to be repopulated next time optionsPagesMap() is called
mOptionsPagesMap.clear();
}

void QgisApp::unregisterOptionsWidgetFactory( QgsOptionsWidgetFactory *factory )
{
mOptionsWidgetFactories.removeAll( factory );
//clear mOptionsPagesMap forcing it to be repopulated next time optionsPagesMap() is called
mOptionsPagesMap.clear();
}

QgsMapLayer *QgisApp::activeLayer()
@@ -11545,7 +11615,7 @@ void QgisApp::projectPropertiesProjections()
projectProperties();
}

void QgisApp::projectProperties()
void QgisApp::projectProperties( const QString &currentPage )
{
/* Display the property sheet for the Project */
// set wait cursor since construction of the project properties
@@ -11569,6 +11639,10 @@ void QgisApp::projectProperties()
&QgsStatusBarScaleWidget::updateScales );
QApplication::restoreOverrideCursor();

if ( !currentPage.isEmpty() )
{
pp->setCurrentPage( currentPage );
}
// Display the modal dialog box.
pp->exec();

@@ -932,6 +932,20 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
//! Update project menu with the project templates
void updateProjectFromTemplates();

/**
* Settings pages section
*/
//! Get map of option pages
QMap< QString, QString > optionsPagesMap();
//! Get map of project property pages
QMap< QString, QString > projectPropertiesPagesMap();
//! Get map of setting pages
QMap< QString, QString > settingPagesMap();

void showProjectProperties( const QString &page = QString() );
void showSettings( const QString &page );
// End Settings pages section

//! Opens the options dialog
void showOptionsDialog( QWidget *parent = nullptr, const QString &currentPage = QString() );

@@ -1333,8 +1347,6 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
void options();
//! Whats-this help slot
void whatsThis();
//! Set project properties, including map untis
void projectProperties();
//! Open project properties dialog and show the projections tab
void projectPropertiesProjections();
/* void urlData(); */
@@ -1786,6 +1798,9 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow

void saveAsVectorFileGeneral( QgsVectorLayer *vlayer = nullptr, bool symbologyOption = true, bool onlySelected = false );

//! Set project properties, including map untis
void projectProperties( const QString &currentPage = QString() );

/**
* Paste features from clipboard into a new memory layer.
* If no features are in clipboard an empty layer is returned.
@@ -2213,6 +2228,11 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow
QgsFeature duplicateFeatures( QgsMapLayer *mlayer, const QgsFeature &feature );
QgsFeature duplicateFeatureDigitized( QgsMapLayer *mlayer, const QgsFeature &feature );

//! Internal vars supporting Settings Pages function
QMap< QString, QString > mOptionsPagesMap;
QMap< QString, QString > mProjectPropertiesPagesMap;
QMap< QString, QString > mSettingPagesMap;

friend class TestQgisAppPython;
};

@@ -1068,6 +1068,20 @@ QgsOptions::~QgsOptions()
delete mSettings;
}

QMap< QString, QString > QgsOptions::pageWidgetNameMap()
{
QMap< QString, QString > pageNames;
for ( int idx = 0; idx < mOptionsListWidget->count(); ++idx )
{
QWidget *currentPage = mOptionsStackedWidget->widget( idx );
QListWidgetItem *item = mOptionsListWidget->item( idx );
QString title = item->text();
QString name = currentPage->objectName();
pageNames.insert( title, name );
}
return pageNames;
}

void QgsOptions::setCurrentPage( const QString &pageWidgetName )
{
//find the page with a matching widget name
@@ -61,6 +61,9 @@ class APP_EXPORT QgsOptions : public QgsOptionsDialogBase, private Ui::QgsOption
*/
void setCurrentPage( const QString &pageWidgetName );

QMap<QString, QString> pageWidgetNameMap();


public slots:
void cbxProjectDefaultNew_toggled( bool checked );
void setCurrentProjectDefault();
@@ -2159,3 +2159,32 @@ void QgsProjectProperties::applyRequiredLayers()
}
QgsProject::instance()->setRequiredLayers( requiredLayers );
}

QMap< QString, QString > QgsProjectProperties::pageWidgetNameMap()
{
QMap< QString, QString > pageNames;
for ( int idx = 0; idx < mOptionsListWidget->count(); ++idx )
{
QWidget *currentPage = mOptionsStackedWidget->widget( idx );
QListWidgetItem *item = mOptionsListWidget->item( idx );
QString title = item->text();
QString name = currentPage->objectName();
pageNames.insert( title, name );
}
return pageNames;
}

void QgsProjectProperties::setCurrentPage( const QString &pageWidgetName )
{
//find the page with a matching widget name
for ( int idx = 0; idx < mOptionsStackedWidget->count(); ++idx )
{
QWidget *currentPage = mOptionsStackedWidget->widget( idx );
if ( currentPage->objectName() == pageWidgetName )
{
//found the page, set it as current
mOptionsStackedWidget->setCurrentIndex( idx );
return;
}
}
}

0 comments on commit 49090a5

Please sign in to comment.
You can’t perform that action at this time.