Initial starting point for annotation layer properties page

This commit is contained in:
Nyall Dawson 2021-09-10 12:43:15 +10:00
parent 4e0d0f6692
commit 985b989276
5 changed files with 779 additions and 0 deletions

View File

@ -107,6 +107,7 @@ set(QGIS_APP_SRCS
qgsmaptooltextannotation.cpp
annotations/qgsannotationitempropertieswidget.cpp
annotations/qgsannotationlayerproperties.cpp
decorations/qgsdecorationitem.cpp
decorations/qgsdecorationtitle.cpp

View File

@ -0,0 +1,298 @@
/***************************************************************************
qgsannotationlayerproperties.cpp
--------------------------------------
Date : September 2021
Copyright : (C) 2021 by 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 "qgsannotationlayerproperties.h"
#include "qgsfileutils.h"
#include "qgshelp.h"
#include "qgsmaplayerstylemanager.h"
#include "qgsmaplayerstyleguiutils.h"
#include "qgsgui.h"
#include "qgsnative.h"
#include "qgsapplication.h"
#include "qgsmetadatawidget.h"
#include "qgsmaplayerloadstyledialog.h"
#include "qgsmaplayerconfigwidgetfactory.h"
#include "qgsmaplayerconfigwidget.h"
#include "qgsdatumtransformdialog.h"
#include <QFileDialog>
#include <QMenu>
#include <QMessageBox>
#include <QDesktopServices>
#include <QUrl>
QgsAnnotationLayerProperties::QgsAnnotationLayerProperties( QgsAnnotationLayer *layer, QgsMapCanvas *canvas, QgsMessageBar *, QWidget *parent, Qt::WindowFlags flags )
: QgsOptionsDialogBase( QStringLiteral( "AnnotationLayerProperties" ), parent, flags )
, mLayer( layer )
, mMapCanvas( canvas )
{
setupUi( this );
connect( this, &QDialog::accepted, this, &QgsAnnotationLayerProperties::apply );
connect( this, &QDialog::rejected, this, &QgsAnnotationLayerProperties::onCancel );
connect( buttonBox->button( QDialogButtonBox::Apply ), &QAbstractButton::clicked, this, &QgsAnnotationLayerProperties::apply );
connect( buttonBox, &QDialogButtonBox::helpRequested, this, &QgsAnnotationLayerProperties::showHelp );
connect( mCrsSelector, &QgsProjectionSelectionWidget::crsChanged, this, &QgsAnnotationLayerProperties::crsChanged );
// QgsOptionsDialogBase handles saving/restoring of geometry, splitter and current tab states,
// switching vertical tabs between icon/text to icon-only modes (splitter collapsed to left),
// and connecting QDialogButtonBox's accepted/rejected signals to dialog's accept/reject slots
initOptionsBase( false );
mOptsPage_Information->setContentsMargins( 0, 0, 0, 0 );
// update based on layer's current state
syncToLayer();
QgsSettings settings;
if ( !settings.contains( QStringLiteral( "/Windows/AnnotationLayerProperties/tab" ) ) )
{
settings.setValue( QStringLiteral( "Windows/AnnotationLayerProperties/tab" ),
mOptStackedWidget->indexOf( mOptsPage_Information ) );
}
QString title = tr( "Layer Properties - %1" ).arg( mLayer->name() );
mBtnStyle = new QPushButton( tr( "Style" ) );
QMenu *menuStyle = new QMenu( this );
menuStyle->addAction( tr( "Load Style…" ), this, &QgsAnnotationLayerProperties::loadStyle );
menuStyle->addAction( tr( "Save Style…" ), this, &QgsAnnotationLayerProperties::saveStyleAs );
menuStyle->addSeparator();
menuStyle->addAction( tr( "Save as Default" ), this, &QgsAnnotationLayerProperties::saveDefaultStyle );
menuStyle->addAction( tr( "Restore Default" ), this, &QgsAnnotationLayerProperties::loadDefaultStyle );
mBtnStyle->setMenu( menuStyle );
connect( menuStyle, &QMenu::aboutToShow, this, &QgsAnnotationLayerProperties::aboutToShowStyleMenu );
buttonBox->addButton( mBtnStyle, QDialogButtonBox::ResetRole );
if ( !mLayer->styleManager()->isDefault( mLayer->styleManager()->currentStyle() ) )
title += QStringLiteral( " (%1)" ).arg( mLayer->styleManager()->currentStyle() );
restoreOptionsBaseUi( title );
}
void QgsAnnotationLayerProperties::addPropertiesPageFactory( const QgsMapLayerConfigWidgetFactory *factory )
{
if ( !factory->supportsLayer( mLayer ) || !factory->supportLayerPropertiesDialog() )
{
return;
}
QgsMapLayerConfigWidget *page = factory->createWidget( mLayer, mMapCanvas, false, this );
mConfigWidgets << page;
const QString beforePage = factory->layerPropertiesPagePositionHint();
if ( beforePage.isEmpty() )
addPage( factory->title(), factory->title(), factory->icon(), page );
else
insertPage( factory->title(), factory->title(), factory->icon(), page, beforePage );
page->syncToLayer( mLayer );
}
void QgsAnnotationLayerProperties::apply()
{
mLayer->setName( mLayerOrigNameLineEdit->text() );
for ( QgsMapLayerConfigWidget *w : mConfigWidgets )
w->apply();
mLayer->triggerRepaint();
}
void QgsAnnotationLayerProperties::onCancel()
{
if ( mOldStyle.xmlData() != mLayer->styleManager()->style( mLayer->styleManager()->currentStyle() ).xmlData() )
{
// need to reset style to previous - style applied directly to the layer (not in apply())
QString myMessage;
QDomDocument doc( QStringLiteral( "qgis" ) );
int errorLine, errorColumn;
doc.setContent( mOldStyle.xmlData(), false, &myMessage, &errorLine, &errorColumn );
mLayer->importNamedStyle( doc, myMessage );
syncToLayer();
}
}
void QgsAnnotationLayerProperties::syncToLayer()
{
// populate the general information
mLayerOrigNameLineEdit->setText( mLayer->name() );
/*
* Information Tab
*/
QString myStyle = QgsApplication::reportStyleSheet();
myStyle.append( QStringLiteral( "body { margin: 10px; }\n " ) );
mInformationTextBrowser->clear();
mInformationTextBrowser->document()->setDefaultStyleSheet( myStyle );
mInformationTextBrowser->setHtml( mLayer->htmlMetadata() );
mInformationTextBrowser->setOpenLinks( false );
connect( mInformationTextBrowser, &QTextBrowser::anchorClicked, this, &QgsAnnotationLayerProperties::urlClicked );
mCrsSelector->setCrs( mLayer->crs() );
for ( QgsMapLayerConfigWidget *w : mConfigWidgets )
w->syncToLayer( mLayer );
}
void QgsAnnotationLayerProperties::loadDefaultStyle()
{
bool defaultLoadedFlag = false;
const QString myMessage = mLayer->loadDefaultStyle( defaultLoadedFlag );
// reset if the default style was loaded OK only
if ( defaultLoadedFlag )
{
syncToLayer();
}
else
{
// otherwise let the user know what went wrong
QMessageBox::information( this,
tr( "Default Style" ),
myMessage
);
}
}
void QgsAnnotationLayerProperties::saveDefaultStyle()
{
apply(); // make sure the style to save is up-to-date
// a flag passed by reference
bool defaultSavedFlag = false;
// after calling this the above flag will be set true for success
// or false if the save operation failed
const QString myMessage = mLayer->saveDefaultStyle( defaultSavedFlag );
if ( !defaultSavedFlag )
{
// let the user know what went wrong
QMessageBox::information( this,
tr( "Default Style" ),
myMessage
);
}
}
void QgsAnnotationLayerProperties::loadStyle()
{
QgsSettings settings;
const QString lastUsedDir = settings.value( QStringLiteral( "style/lastStyleDir" ), QDir::homePath() ).toString();
QString fileName = QFileDialog::getOpenFileName(
this,
tr( "Load layer properties from style file" ),
lastUsedDir,
tr( "QGIS Layer Style File" ) + " (*.qml)" );
if ( fileName.isEmpty() )
return;
// ensure the user never omits the extension from the file name
if ( !fileName.endsWith( QLatin1String( ".qml" ), Qt::CaseInsensitive ) )
fileName += QLatin1String( ".qml" );
mOldStyle = mLayer->styleManager()->style( mLayer->styleManager()->currentStyle() );
bool defaultLoadedFlag = false;
const QString message = mLayer->loadNamedStyle( fileName, defaultLoadedFlag );
if ( defaultLoadedFlag )
{
settings.setValue( QStringLiteral( "style/lastStyleDir" ), QFileInfo( fileName ).absolutePath() );
syncToLayer();
}
else
{
QMessageBox::information( this, tr( "Load Style" ), message );
}
}
void QgsAnnotationLayerProperties::saveStyleAs()
{
QgsSettings settings;
const QString lastUsedDir = settings.value( QStringLiteral( "style/lastStyleDir" ), QDir::homePath() ).toString();
QString outputFileName = QFileDialog::getSaveFileName(
this,
tr( "Save layer properties as style file" ),
lastUsedDir,
tr( "QGIS Layer Style File" ) + " (*.qml)" );
if ( outputFileName.isEmpty() )
return;
// ensure the user never omits the extension from the file name
outputFileName = QgsFileUtils::ensureFileNameHasExtension( outputFileName, QStringList() << QStringLiteral( "qml" ) );
apply(); // make sure the style to save is up-to-date
// then export style
bool defaultLoadedFlag = false;
QString message;
message = mLayer->saveNamedStyle( outputFileName, defaultLoadedFlag );
if ( defaultLoadedFlag )
{
settings.setValue( QStringLiteral( "style/lastStyleDir" ), QFileInfo( outputFileName ).absolutePath() );
}
else
QMessageBox::information( this, tr( "Save Style" ), message );
}
void QgsAnnotationLayerProperties::aboutToShowStyleMenu()
{
QMenu *m = qobject_cast<QMenu *>( sender() );
QgsMapLayerStyleGuiUtils::instance()->removesExtraMenuSeparators( m );
// re-add style manager actions!
m->addSeparator();
QgsMapLayerStyleGuiUtils::instance()->addStyleManagerActions( m, mLayer );
}
void QgsAnnotationLayerProperties::showHelp()
{
const QVariant helpPage = mOptionsStackedWidget->currentWidget()->property( "helpPage" );
if ( helpPage.isValid() )
{
QgsHelp::openHelp( helpPage.toString() );
}
else
{
QgsHelp::openHelp( QStringLiteral( "working_with_vector_tiles/vector_tiles_properties.html" ) );
}
}
void QgsAnnotationLayerProperties::urlClicked( const QUrl &url )
{
const QFileInfo file( url.toLocalFile() );
if ( file.exists() && !file.isDir() )
QgsGui::instance()->nativePlatformInterface()->openFileExplorerAndSelectFile( url.toLocalFile() );
else
QDesktopServices::openUrl( url );
}
void QgsAnnotationLayerProperties::crsChanged( const QgsCoordinateReferenceSystem &crs )
{
QgsDatumTransformDialog::run( crs, QgsProject::instance()->crs(), this, mMapCanvas, tr( "Select transformation for the layer" ) );
mLayer->setCrs( crs );
}
void QgsAnnotationLayerProperties::optionsStackedWidget_CurrentChanged( int index )
{
QgsOptionsDialogBase::optionsStackedWidget_CurrentChanged( index );
mBtnStyle->setVisible( true );
}

View File

@ -0,0 +1,80 @@
/***************************************************************************
qgsannotationlayerproperties.h
--------------------------------------
Date : September 2021
Copyright : (C) 2021 by 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 QGSANNOTATIONLAYERPROPERTIES_H
#define QGSANNOTATIONLAYERPROPERTIES_H
#include "qgsoptionsdialogbase.h"
#include "ui_qgsannotationlayerpropertiesbase.h"
#include "qgsmaplayerstylemanager.h"
#include "qgsannotationlayer.h"
class QgsMapLayer;
class QgsMapCanvas;
class QgsMessageBar;
class QgsAnnotationLayer;
class QgsMetadataWidget;
class QgsMapLayerConfigWidgetFactory;
class QgsMapLayerConfigWidget;
class QgsAnnotationLayerProperties : public QgsOptionsDialogBase, private Ui::QgsAnnotationLayerPropertiesBase
{
Q_OBJECT
public:
QgsAnnotationLayerProperties( QgsAnnotationLayer *layer, QgsMapCanvas *canvas, QgsMessageBar *messageBar, QWidget *parent = nullptr, Qt::WindowFlags = QgsGuiUtils::ModalDialogFlags );
void addPropertiesPageFactory( const QgsMapLayerConfigWidgetFactory *factory );
private slots:
void apply();
void onCancel();
void loadDefaultStyle();
void saveDefaultStyle();
void loadStyle();
void saveStyleAs();
void aboutToShowStyleMenu();
void showHelp();
void urlClicked( const QUrl &url );
void crsChanged( const QgsCoordinateReferenceSystem &crs );
protected slots:
void optionsStackedWidget_CurrentChanged( int index ) override SIP_SKIP ;
private:
void syncToLayer();
private:
QgsAnnotationLayer *mLayer = nullptr;
QPushButton *mBtnStyle = nullptr;
QgsMapCanvas *mMapCanvas = nullptr;
/**
* Previous layer style. Used to reset style to previous state if new style
* was loaded but dialog is canceled.
*/
QgsMapLayerStyle mOldStyle;
QList<QgsMapLayerConfigWidget *> mConfigWidgets;
};
#endif // QGSANNOTATIONLAYERPROPERTIES_H

View File

@ -433,6 +433,7 @@ Q_GUI_EXPORT extern int qt_defaultDpiX();
#include "qgssublayersdialog.h"
#include "ogr/qgsvectorlayersaveasdialog.h"
#include "qgsannotationitemguiregistry.h"
#include "annotations/qgsannotationlayerproperties.h"
#include "qgscreateannotationitemmaptool.h"
#include "pointcloud/qgspointcloudelevationpropertieswidget.h"
@ -16720,6 +16721,25 @@ void QgisApp::showLayerProperties( QgsMapLayer *mapLayer, const QString &page )
case QgsMapLayerType::AnnotationLayer:
{
QgsAnnotationLayerProperties annotationLayerPropertiesDialog( qobject_cast<QgsAnnotationLayer *>( mapLayer ), mMapCanvas, visibleMessageBar(), this );
if ( !page.isEmpty() )
annotationLayerPropertiesDialog.setCurrentPage( page );
else
annotationLayerPropertiesDialog.restoreLastPage();
for ( const QgsMapLayerConfigWidgetFactory *factory : std::as_const( providerFactories ) )
{
annotationLayerPropertiesDialog.addPropertiesPageFactory( factory );
}
mMapStyleWidget->blockUpdates( true );
if ( annotationLayerPropertiesDialog.exec() )
{
activateDeactivateLayerRelatedActions( mapLayer );
mMapStyleWidget->updateCurrentWidgetLayer();
}
mMapStyleWidget->blockUpdates( false ); // delete since dialog cannot be reused without updating code
break;
}

View File

@ -0,0 +1,380 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QgsAnnotationLayerPropertiesBase</class>
<widget class="QDialog" name="QgsAnnotationLayerPropertiesBase">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>815</width>
<height>557</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>700</width>
<height>0</height>
</size>
</property>
<property name="windowTitle">
<string>Annotation Layer Properties</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<item>
<widget class="QSplitter" name="mOptionsSplitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="childrenCollapsible">
<bool>false</bool>
</property>
<widget class="QFrame" name="mOptionsListFrame">
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QgsFilterLineEdit" name="mSearchLineEdit"/>
</item>
<item>
<widget class="QListWidget" name="mOptionsListWidget">
<property name="minimumSize">
<size>
<width>58</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>150</width>
<height>16777215</height>
</size>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="iconSize">
<size>
<width>32</width>
<height>32</height>
</size>
</property>
<property name="textElideMode">
<enum>Qt::ElideNone</enum>
</property>
<property name="resizeMode">
<enum>QListView::Adjust</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<item>
<property name="text">
<string>Information</string>
</property>
<property name="toolTip">
<string>Information</string>
</property>
<property name="icon">
<iconset resource="../../../images/images.qrc">
<normaloff>:/images/themes/default/propertyicons/metadata.svg</normaloff>:/images/themes/default/propertyicons/metadata.svg</iconset>
</property>
</item>
<item>
<property name="text">
<string>Source</string>
</property>
<property name="toolTip">
<string>Source</string>
</property>
<property name="icon">
<iconset resource="../../../images/images.qrc">
<normaloff>:/images/themes/default/propertyicons/system.svg</normaloff>:/images/themes/default/propertyicons/system.svg</iconset>
</property>
</item>
</widget>
</item>
</layout>
</widget>
<widget class="QFrame" name="mOptionsFrame">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QStackedWidget" name="mOptionsStackedWidget">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="currentIndex">
<number>1</number>
</property>
<widget class="QWidget" name="mOptsPage_Information">
<layout class="QVBoxLayout" name="verticalLayout_4">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QTextBrowser" name="mInformationTextBrowser"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="mOptsPage_Source">
<layout class="QVBoxLayout" name="verticalLayout_9">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QgsCollapsibleGroupBox" name="groupBox_60">
<property name="title">
<string>Settings</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_260">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_13">
<item>
<widget class="QLabel" name="label_6">
<property name="text">
<string>Layer name</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="mLayerOrigNameLineEdit"/>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QgsCollapsibleGroupBox" name="mCrsGroupBox">
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="title">
<string>Assigned Coordinate Reference System (CRS)</string>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<property name="syncGroup" stdset="0">
<string notr="true">vectorgeneral</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_28">
<property name="spacing">
<number>6</number>
</property>
<item>
<widget class="QgsProjectionSelectionWidget" name="mCrsSelector" native="true">
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600;&quot;&gt;Changing this option does not modify the original data source or perform any reprojection of points. Rather, it can be used to override the layer's CRS within this project if it could not be detected or has been incorrectly detected.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QFrame" name="mButtonBoxFrame">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Raised</enum>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0" colspan="2">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QgsFilterLineEdit</class>
<extends>QLineEdit</extends>
<header>qgsfilterlineedit.h</header>
</customwidget>
<customwidget>
<class>QgsCollapsibleGroupBox</class>
<extends>QGroupBox</extends>
<header>qgscollapsiblegroupbox.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>QgsProjectionSelectionWidget</class>
<extends>QWidget</extends>
<header>qgsprojectionselectionwidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>mSearchLineEdit</tabstop>
<tabstop>mOptionsListWidget</tabstop>
</tabstops>
<resources>
<include location="../../../images/images.qrc"/>
</resources>
<connections>
<connection>
<sender>mOptionsListWidget</sender>
<signal>currentRowChanged(int)</signal>
<receiver>mOptionsStackedWidget</receiver>
<slot>setCurrentIndex(int)</slot>
<hints>
<hint type="sourcelabel">
<x>86</x>
<y>325</y>
</hint>
<hint type="destinationlabel">
<x>794</x>
<y>14</y>
</hint>
</hints>
</connection>
</connections>
</ui>