mirror of
https://github.com/qgis/QGIS.git
synced 2025-10-16 00:05:45 -04:00
Allow options dialog to use a tree structure for tab list instead
of a flat list widget
This commit is contained in:
parent
bb119aa979
commit
f22f742a9f
@ -13,7 +13,6 @@
|
||||
|
||||
|
||||
|
||||
|
||||
class QgsOptionsDialogBase : QDialog
|
||||
{
|
||||
%Docstring(signature="appended")
|
||||
@ -168,6 +167,8 @@ it is automatically called if a line edit has "mSearchLineEdit" as object name.
|
||||
%End
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
/************************************************************************
|
||||
|
@ -104,6 +104,33 @@ QgsOptions::QgsOptions( QWidget *parent, Qt::WindowFlags fl, const QList<QgsOpti
|
||||
|
||||
{
|
||||
setupUi( this );
|
||||
|
||||
mTreeModel = new QStandardItemModel( this );
|
||||
mTreeModel->appendRow( createItem( tr( "General" ), tr( "General" ), QStringLiteral( "propertyicons/general.svg" ) ) );
|
||||
mTreeModel->appendRow( createItem( tr( "System" ), tr( "System" ), QStringLiteral( "propertyicons/system.svg" ) ) );
|
||||
|
||||
QStandardItem *crsGroup = new QStandardItem( tr( "CRS and Transforms" ) );
|
||||
crsGroup->setSelectable( false );
|
||||
crsGroup->appendRow( createItem( tr( "CRS" ), tr( "CRS" ), QStringLiteral( "propertyicons/CRS.svg" ) ) );
|
||||
crsGroup->appendRow( createItem( tr( "Transformations" ), tr( "Coordinate transformations and operations" ), QStringLiteral( "transformation.svg" ) ) );
|
||||
mTreeModel->appendRow( crsGroup );
|
||||
|
||||
mTreeModel->appendRow( createItem( tr( "Data Sources" ), tr( "Data sources" ), QStringLiteral( "propertyicons/attributes.svg" ) ) );
|
||||
mTreeModel->appendRow( createItem( tr( "Rendering" ), tr( "Rendering" ), QStringLiteral( "propertyicons/rendering.svg" ) ) );
|
||||
mTreeModel->appendRow( createItem( tr( "Canvas & Legend" ), tr( "Canvas and legend" ), QStringLiteral( "propertyicons/overlay.svg" ) ) );
|
||||
mTreeModel->appendRow( createItem( tr( "Map Tools" ), tr( "Map tools" ), QStringLiteral( "propertyicons/map_tools.svg" ) ) );
|
||||
mTreeModel->appendRow( createItem( tr( "Colors" ), tr( "Colors" ), QStringLiteral( "propertyicons/colors.svg" ) ) );
|
||||
mTreeModel->appendRow( createItem( tr( "Digitizing" ), tr( "Digitizing" ), QStringLiteral( "propertyicons/digitizing.svg" ) ) );
|
||||
mTreeModel->appendRow( createItem( tr( "Layouts" ), tr( "Print layouts" ), QStringLiteral( "mIconLayout.svg" ) ) );
|
||||
mTreeModel->appendRow( createItem( tr( "GDAL" ), tr( "GDAL" ), QStringLiteral( "propertyicons/gdal.svg" ) ) );
|
||||
mTreeModel->appendRow( createItem( tr( "Variables" ), tr( "Variables" ), QStringLiteral( "mIconExpression.svg" ) ) );
|
||||
mTreeModel->appendRow( createItem( tr( "Authentication" ), tr( "Authentication" ), QStringLiteral( "locked.svg" ) ) );
|
||||
mTreeModel->appendRow( createItem( tr( "Network" ), tr( "Network" ), QStringLiteral( "propertyicons/network_and_proxy.svg" ) ) );
|
||||
mTreeModel->appendRow( createItem( tr( "Locator" ), tr( "Locator" ), QStringLiteral( "search.svg" ) ) );
|
||||
mTreeModel->appendRow( createItem( tr( "Acceleration" ), tr( "GPU acceleration" ), QStringLiteral( "mIconGPU.svg" ) ) );
|
||||
|
||||
mOptionsTreeView->setModel( mTreeModel );
|
||||
|
||||
connect( cbxProjectDefaultNew, &QCheckBox::toggled, this, &QgsOptions::cbxProjectDefaultNew_toggled );
|
||||
connect( leLayerGlobalCrs, &QgsProjectionSelectionWidget::crsChanged, this, &QgsOptions::leLayerGlobalCrs_crsChanged );
|
||||
connect( lstRasterDrivers, &QTreeWidget::itemDoubleClicked, this, &QgsOptions::lstRasterDrivers_itemDoubleClicked );
|
||||
@ -1334,7 +1361,10 @@ void QgsOptions::checkPageWidgetNameMap()
|
||||
{
|
||||
const QMap< QString, int > pageNames = QgisApp::instance()->optionsPagesMap();
|
||||
|
||||
#if 0
|
||||
Q_ASSERT_X( pageNames.count() == mOptionsListWidget->count(), "QgsOptions::checkPageWidgetNameMap()", "QgisApp::optionsPagesMap() is outdated, contains too many entries" );
|
||||
|
||||
|
||||
for ( int idx = 0; idx < mOptionsListWidget->count(); ++idx )
|
||||
{
|
||||
QWidget *currentPage = mOptionsStackedWidget->widget( idx );
|
||||
@ -1346,6 +1376,7 @@ void QgsOptions::checkPageWidgetNameMap()
|
||||
Q_ASSERT_X( pageNames.value( title ) == idx, "QgsOptions::checkPageWidgetNameMap()", QStringLiteral( "QgisApp::optionsPagesMap() is outdated, please update. %1 should be %2 not %3" ).arg( title ).arg( idx ).arg( pageNames.value( title ) ).toLocal8Bit().constData() );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void QgsOptions::setCurrentPage( const QString &pageWidgetName )
|
||||
|
@ -34,6 +34,7 @@ class QgsOptionsPageWidget;
|
||||
class QgsLocatorOptionsWidget;
|
||||
class QgsAuthConfigSelect;
|
||||
class QgsBearingNumericFormat;
|
||||
class QStandardItemModel;
|
||||
|
||||
/**
|
||||
* \class QgsOptions
|
||||
@ -313,6 +314,8 @@ class APP_EXPORT QgsOptions : public QgsOptionsDialogBase, private Ui::QgsOption
|
||||
|
||||
std::unique_ptr< QgsBearingNumericFormat > mBearingFormat;
|
||||
|
||||
QStandardItemModel *mTreeModel = nullptr;
|
||||
|
||||
void updateActionsForCurrentColorScheme( QgsColorScheme *scheme );
|
||||
|
||||
void checkPageWidgetNameMap();
|
||||
|
@ -152,6 +152,23 @@ void QgisAppStyleSheet::buildStyleSheet( const QMap<QString, QVariant> &opts )
|
||||
" padding-right: 0px;"
|
||||
"}" ).arg( frameMargin );
|
||||
|
||||
style += QStringLiteral( "QTreeView#mOptionsTreeView {"
|
||||
" background-color: rgba(69, 69, 69, 0);"
|
||||
" outline: 0;"
|
||||
"}"
|
||||
"QFrame#mOptionsListFrame {"
|
||||
" background-color: rgba(69, 69, 69, 220);"
|
||||
"}"
|
||||
"QTreeView#mOptionsTreeView::item {"
|
||||
" color: white;"
|
||||
" padding: %1px;"
|
||||
"}"
|
||||
"QTreeView#mOptionsTreeView::item::selected {"
|
||||
" color: black;"
|
||||
" background-color:palette(Window);"
|
||||
" padding-right: 0px;"
|
||||
"}" ).arg( frameMargin );
|
||||
|
||||
QString toolbarSpacing = opts.value( QStringLiteral( "toolbarSpacing" ), QString() ).toString();
|
||||
if ( !toolbarSpacing.isEmpty() )
|
||||
{
|
||||
|
@ -306,6 +306,7 @@ void QgsAppScreenShots::takeGlobalOptions()
|
||||
dlg->setMinimumHeight( 600 );
|
||||
dlg->show();
|
||||
QCoreApplication::processEvents();
|
||||
#if 0
|
||||
for ( int row = 0; row < dlg->mOptionsListWidget->count(); ++row )
|
||||
{
|
||||
dlg->mOptionsListWidget->setCurrentRow( row );
|
||||
@ -327,7 +328,7 @@ void QgsAppScreenShots::takeGlobalOptions()
|
||||
QCoreApplication::processEvents();
|
||||
QCoreApplication::processEvents(); // seems a second call is needed, the tabble might not be fully displayed otherwise
|
||||
takeScreenshot( QStringLiteral( "advanced_with_settings_shown" ), folder, dlg );
|
||||
|
||||
#endif
|
||||
// exit properly
|
||||
dlg->close();
|
||||
dlg->deleteLater();
|
||||
|
@ -27,6 +27,10 @@
|
||||
#include <QSplitter>
|
||||
#include <QStackedWidget>
|
||||
#include <QTimer>
|
||||
#include <QStandardItem>
|
||||
#include <QTreeView>
|
||||
#include <QHeaderView>
|
||||
#include <functional>
|
||||
|
||||
#include "qgsfilterlineedit.h"
|
||||
#include "qgsmessagebaritem.h"
|
||||
@ -34,14 +38,12 @@
|
||||
#include "qgsoptionsdialoghighlightwidget.h"
|
||||
#include "qgsoptionswidgetfactory.h"
|
||||
#include "qgsguiutils.h"
|
||||
#include "qgsapplication.h"
|
||||
|
||||
QgsOptionsDialogBase::QgsOptionsDialogBase( const QString &settingsKey, QWidget *parent, Qt::WindowFlags fl, QgsSettings *settings )
|
||||
: QDialog( parent, fl )
|
||||
, mOptsKey( settingsKey )
|
||||
, mInit( false )
|
||||
, mIconOnly( false )
|
||||
, mSettings( settings )
|
||||
, mDelSettings( false )
|
||||
{
|
||||
}
|
||||
|
||||
@ -90,6 +92,12 @@ void QgsOptionsDialogBase::initOptionsBase( bool restoreUi, const QString &title
|
||||
|
||||
// start with copy of qgsoptionsdialog_template.ui to ensure existence of these objects
|
||||
mOptListWidget = findChild<QListWidget *>( QStringLiteral( "mOptionsListWidget" ) );
|
||||
mOptTreeView = findChild<QTreeView *>( QStringLiteral( "mOptionsTreeView" ) );
|
||||
if ( mOptTreeView )
|
||||
{
|
||||
mOptTreeModel = qobject_cast< QStandardItemModel * >( mOptTreeView->model() );
|
||||
}
|
||||
|
||||
QFrame *optionsFrame = findChild<QFrame *>( QStringLiteral( "mOptionsFrame" ) );
|
||||
mOptStackedWidget = findChild<QStackedWidget *>( QStringLiteral( "mOptionsStackedWidget" ) );
|
||||
mOptSplitter = findChild<QSplitter *>( QStringLiteral( "mOptionsSplitter" ) );
|
||||
@ -97,17 +105,28 @@ void QgsOptionsDialogBase::initOptionsBase( bool restoreUi, const QString &title
|
||||
QFrame *buttonBoxFrame = findChild<QFrame *>( QStringLiteral( "mButtonBoxFrame" ) );
|
||||
mSearchLineEdit = findChild<QgsFilterLineEdit *>( QStringLiteral( "mSearchLineEdit" ) );
|
||||
|
||||
if ( !mOptListWidget || !mOptStackedWidget || !mOptSplitter || !optionsFrame )
|
||||
if ( ( !mOptListWidget && !mOptTreeView ) || !mOptStackedWidget || !mOptSplitter || !optionsFrame )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int size = QgsGuiUtils::scaleIconSize( mSettings->value( QStringLiteral( "/IconSize" ), 24 ).toInt() );
|
||||
// buffer size to match displayed icon size in toolbars, and expected geometry restore
|
||||
// newWidth (above) may need adjusted if you adjust iconBuffer here
|
||||
const int iconBuffer = QgsGuiUtils::scaleIconSize( 4 );
|
||||
mOptListWidget->setIconSize( QSize( size + iconBuffer, size + iconBuffer ) );
|
||||
mOptListWidget->setFrameStyle( QFrame::NoFrame );
|
||||
QAbstractItemView *optView = mOptListWidget ? static_cast< QAbstractItemView * >( mOptListWidget ) : static_cast< QAbstractItemView * >( mOptTreeView );
|
||||
int iconSize = 16;
|
||||
if ( mOptListWidget )
|
||||
{
|
||||
int size = QgsGuiUtils::scaleIconSize( mSettings->value( QStringLiteral( "/IconSize" ), 24 ).toInt() );
|
||||
// buffer size to match displayed icon size in toolbars, and expected geometry restore
|
||||
// newWidth (above) may need adjusted if you adjust iconBuffer here
|
||||
const int iconBuffer = QgsGuiUtils::scaleIconSize( 4 );
|
||||
iconSize = size + iconBuffer;
|
||||
}
|
||||
else if ( mOptTreeView )
|
||||
{
|
||||
iconSize = QgsGuiUtils::scaleIconSize( mSettings->value( QStringLiteral( "/IconSize" ), 16 ).toInt() );
|
||||
mOptTreeView->header()->setVisible( false );
|
||||
}
|
||||
optView->setIconSize( QSize( iconSize, iconSize ) );
|
||||
optView->setFrameStyle( QFrame::NoFrame );
|
||||
|
||||
const int frameMargin = QgsGuiUtils::scaleIconSize( 3 );
|
||||
optionsFrame->layout()->setContentsMargins( 0, frameMargin, frameMargin, frameMargin );
|
||||
@ -135,6 +154,24 @@ void QgsOptionsDialogBase::initOptionsBase( bool restoreUi, const QString &title
|
||||
connect( mOptStackedWidget, &QStackedWidget::currentChanged, this, &QgsOptionsDialogBase::optionsStackedWidget_CurrentChanged );
|
||||
connect( mOptStackedWidget, &QStackedWidget::widgetRemoved, this, &QgsOptionsDialogBase::optionsStackedWidget_WidgetRemoved );
|
||||
|
||||
if ( mOptTreeView )
|
||||
{
|
||||
// sync selection in tree view with current stacked widget index
|
||||
connect( mOptTreeView->selectionModel(), &QItemSelectionModel::selectionChanged, mOptStackedWidget, [ = ]( const QItemSelection &, const QItemSelection & )
|
||||
{
|
||||
const QModelIndexList selected = mOptTreeView->selectionModel()->selectedIndexes();
|
||||
if ( selected.isEmpty() )
|
||||
return;
|
||||
|
||||
const QModelIndex index = selected.at( 0 );
|
||||
|
||||
if ( !mOptTreeModel || !mOptTreeModel->itemFromIndex( index )->isSelectable() )
|
||||
return;
|
||||
|
||||
mOptStackedWidget->setCurrentIndex( viewIndexToPageNumber( index ) );
|
||||
} );
|
||||
}
|
||||
|
||||
if ( mSearchLineEdit )
|
||||
{
|
||||
mSearchLineEdit->setShowSearchIcon( true );
|
||||
@ -179,15 +216,19 @@ void QgsOptionsDialogBase::restoreOptionsBaseUi( const QString &title )
|
||||
restoreGeometry( mSettings->value( QStringLiteral( "/Windows/%1/geometry" ).arg( mOptsKey ) ).toByteArray() );
|
||||
// mOptListWidget width is fixed to take up less space in QtDesigner
|
||||
// revert it now unless the splitter's state hasn't been saved yet
|
||||
mOptListWidget->setMaximumWidth(
|
||||
mSettings->value( QStringLiteral( "/Windows/%1/splitState" ).arg( mOptsKey ) ).isNull() ? 150 : 16777215 );
|
||||
QAbstractItemView *optView = mOptListWidget ? static_cast< QAbstractItemView * >( mOptListWidget ) : static_cast< QAbstractItemView * >( mOptTreeView );
|
||||
if ( optView )
|
||||
{
|
||||
optView->setMaximumWidth(
|
||||
mSettings->value( QStringLiteral( "/Windows/%1/splitState" ).arg( mOptsKey ) ).isNull() ? 150 : 16777215 );
|
||||
// get rid of annoying outer focus rect on Mac
|
||||
optView->setAttribute( Qt::WA_MacShowFocusRect, false );
|
||||
}
|
||||
|
||||
mOptSplitter->restoreState( mSettings->value( QStringLiteral( "/Windows/%1/splitState" ).arg( mOptsKey ) ).toByteArray() );
|
||||
|
||||
restoreLastPage();
|
||||
|
||||
// get rid of annoying outer focus rect on Mac
|
||||
mOptListWidget->setAttribute( Qt::WA_MacShowFocusRect, false );
|
||||
|
||||
// brute force approach to try to standardize page margins!
|
||||
for ( int i = 0; i < mOptStackedWidget->count(); ++i )
|
||||
{
|
||||
@ -217,11 +258,84 @@ void QgsOptionsDialogBase::restoreLastPage()
|
||||
}
|
||||
}
|
||||
|
||||
if ( mOptStackedWidget->count() != 0 && mOptListWidget->count() != 0 )
|
||||
if ( mOptStackedWidget->count() == 0 )
|
||||
return;
|
||||
|
||||
mOptStackedWidget->setCurrentIndex( curIndx );
|
||||
setListToItemAtIndex( curIndx );
|
||||
}
|
||||
|
||||
void QgsOptionsDialogBase::setListToItemAtIndex( int index )
|
||||
{
|
||||
if ( mOptListWidget && mOptListWidget->count() > index )
|
||||
{
|
||||
mOptStackedWidget->setCurrentIndex( curIndx );
|
||||
mOptListWidget->setCurrentRow( curIndx );
|
||||
mOptListWidget->setCurrentRow( index );
|
||||
}
|
||||
else if ( mOptTreeView && mOptTreeModel )
|
||||
{
|
||||
mOptTreeView->setCurrentIndex( pageNumberToTreeViewIndex( index ) );
|
||||
}
|
||||
}
|
||||
|
||||
QModelIndex QgsOptionsDialogBase::pageNumberToTreeViewIndex( int page )
|
||||
{
|
||||
if ( !mOptTreeModel )
|
||||
return QModelIndex();
|
||||
|
||||
int pagesRemaining = page;
|
||||
std::function<QModelIndex( const QModelIndex & )> traversePages;
|
||||
|
||||
// traverse through the model, counting all selectable items until we hit the desired page number
|
||||
traversePages = [&]( const QModelIndex & parent ) -> QModelIndex
|
||||
{
|
||||
for ( int row = 0; row < mOptTreeModel->rowCount( parent ); ++row )
|
||||
{
|
||||
const QModelIndex currentIndex = mOptTreeModel->index( row, 0, parent );
|
||||
if ( mOptTreeModel->itemFromIndex( currentIndex )->isSelectable() && pagesRemaining == 0 )
|
||||
return currentIndex;
|
||||
|
||||
const QModelIndex res = traversePages( currentIndex );
|
||||
if ( res.isValid() )
|
||||
return res;
|
||||
|
||||
if ( mOptTreeModel->itemFromIndex( currentIndex )->isSelectable() )
|
||||
pagesRemaining--;
|
||||
}
|
||||
return QModelIndex();
|
||||
};
|
||||
|
||||
return traversePages( QModelIndex() );
|
||||
}
|
||||
|
||||
int QgsOptionsDialogBase::viewIndexToPageNumber( const QModelIndex &index )
|
||||
{
|
||||
if ( !mOptTreeModel )
|
||||
return 0;
|
||||
|
||||
int page = 0;
|
||||
|
||||
std::function<int( const QModelIndex & )> traverseModel;
|
||||
|
||||
// traverse through the model, counting all which correspond to pages till we hit the desired index
|
||||
traverseModel = [&]( const QModelIndex & parent ) -> int
|
||||
{
|
||||
for ( int row = 0; row < mOptTreeModel->rowCount( parent ); ++row )
|
||||
{
|
||||
const QModelIndex currentIndex = mOptTreeModel->index( row, 0, parent );
|
||||
if ( currentIndex == index )
|
||||
return page;
|
||||
|
||||
const int res = traverseModel( currentIndex );
|
||||
if ( res >= 0 )
|
||||
return res;
|
||||
|
||||
if ( mOptTreeModel->itemFromIndex( currentIndex )->isSelectable() )
|
||||
page++;
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
|
||||
return traverseModel( QModelIndex() );
|
||||
}
|
||||
|
||||
void QgsOptionsDialogBase::resizeAlltabs( int index )
|
||||
@ -270,7 +384,17 @@ void QgsOptionsDialogBase::addPage( const QString &title, const QString &tooltip
|
||||
item->setText( title );
|
||||
item->setToolTip( tooltip );
|
||||
|
||||
mOptListWidget->addItem( item );
|
||||
if ( mOptListWidget )
|
||||
{
|
||||
mOptListWidget->addItem( item );
|
||||
}
|
||||
else if ( mOptTreeModel )
|
||||
{
|
||||
QStandardItem *item = new QStandardItem( icon, title );
|
||||
item->setToolTip( tooltip );
|
||||
mOptTreeModel->appendRow( item );
|
||||
}
|
||||
|
||||
mOptStackedWidget->addWidget( widget );
|
||||
}
|
||||
|
||||
@ -289,7 +413,17 @@ void QgsOptionsDialogBase::insertPage( const QString &title, const QString &tool
|
||||
item->setText( title );
|
||||
item->setToolTip( tooltip );
|
||||
|
||||
mOptListWidget->insertItem( idx, item );
|
||||
if ( mOptListWidget )
|
||||
{
|
||||
mOptListWidget->insertItem( idx, item );
|
||||
}
|
||||
else if ( mOptTreeModel )
|
||||
{
|
||||
QStandardItem *item = new QStandardItem( icon, title );
|
||||
item->setToolTip( tooltip );
|
||||
mOptTreeModel->insertRow( idx, item );
|
||||
}
|
||||
|
||||
mOptStackedWidget->insertWidget( idx, widget );
|
||||
return;
|
||||
}
|
||||
@ -312,21 +446,28 @@ void QgsOptionsDialogBase::searchText( const QString &text )
|
||||
mOptStackedWidget->show();
|
||||
if ( mOptButtonBox && mOptButtonBox->isHidden() )
|
||||
mOptButtonBox->show();
|
||||
|
||||
// hide all page if text has to be search, show them all otherwise
|
||||
for ( int r = 0; r < mOptListWidget->count(); ++r )
|
||||
if ( mOptListWidget )
|
||||
{
|
||||
mOptListWidget->setRowHidden( r, text.length() >= minimumTextLength );
|
||||
for ( int r = 0; r < mOptListWidget->count(); ++r )
|
||||
{
|
||||
mOptListWidget->setRowHidden( r, text.length() >= minimumTextLength );
|
||||
}
|
||||
}
|
||||
|
||||
for ( const QPair< QgsOptionsDialogHighlightWidget *, int > &rsw : std::as_const( mRegisteredSearchWidgets ) )
|
||||
{
|
||||
if ( rsw.first->searchHighlight( text.length() >= minimumTextLength ? text : QString() ) )
|
||||
{
|
||||
mOptListWidget->setRowHidden( rsw.second, false );
|
||||
if ( mOptListWidget )
|
||||
{
|
||||
mOptListWidget->setRowHidden( rsw.second, false );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( mOptListWidget->isRowHidden( mOptStackedWidget->currentIndex() ) )
|
||||
if ( mOptListWidget && mOptListWidget->isRowHidden( mOptStackedWidget->currentIndex() ) )
|
||||
{
|
||||
for ( int r = 0; r < mOptListWidget->count(); ++r )
|
||||
{
|
||||
@ -385,16 +526,30 @@ void QgsOptionsDialogBase::registerTextSearchWidgets()
|
||||
}
|
||||
}
|
||||
|
||||
QStandardItem *QgsOptionsDialogBase::createItem( const QString &name, const QString &tooltip, const QString &icon )
|
||||
{
|
||||
QStandardItem *res = new QStandardItem( QgsApplication::getThemeIcon( icon ), name );
|
||||
res->setToolTip( tooltip );
|
||||
return res;
|
||||
}
|
||||
|
||||
void QgsOptionsDialogBase::showEvent( QShowEvent *e )
|
||||
{
|
||||
if ( mInit )
|
||||
{
|
||||
updateOptionsListVerticalTabs();
|
||||
optionsStackedWidget_CurrentChanged( mOptListWidget->currentRow() );
|
||||
if ( mOptListWidget )
|
||||
{
|
||||
optionsStackedWidget_CurrentChanged( mOptListWidget->currentRow() );
|
||||
}
|
||||
else if ( mOptTreeView )
|
||||
{
|
||||
optionsStackedWidget_CurrentChanged( viewIndexToPageNumber( mOptTreeView->currentIndex() ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QTimer::singleShot( 0, this, SLOT( warnAboutMissingObjects() ) );
|
||||
QTimer::singleShot( 0, this, &QgsOptionsDialogBase::warnAboutMissingObjects );
|
||||
}
|
||||
|
||||
if ( mSearchLineEdit )
|
||||
@ -408,20 +563,21 @@ void QgsOptionsDialogBase::showEvent( QShowEvent *e )
|
||||
void QgsOptionsDialogBase::paintEvent( QPaintEvent *e )
|
||||
{
|
||||
if ( mInit )
|
||||
QTimer::singleShot( 0, this, SLOT( updateOptionsListVerticalTabs() ) );
|
||||
QTimer::singleShot( 0, this, &QgsOptionsDialogBase::updateOptionsListVerticalTabs );
|
||||
|
||||
QDialog::paintEvent( e );
|
||||
}
|
||||
|
||||
void QgsOptionsDialogBase::updateWindowTitle()
|
||||
{
|
||||
QListWidgetItem *curitem = mOptListWidget->currentItem();
|
||||
if ( curitem )
|
||||
const QString itemText = mOptListWidget && mOptListWidget->currentItem() ? mOptListWidget->currentItem()->text()
|
||||
: mOptTreeView && mOptTreeView->currentIndex().isValid() ? mOptTreeView->currentIndex().data( Qt::DisplayRole ).toString() : QString();
|
||||
if ( !itemText.isEmpty() )
|
||||
{
|
||||
setWindowTitle( QStringLiteral( "%1 %2 %3" )
|
||||
.arg( mDialogTitle )
|
||||
.arg( QChar( 0x2014 ) ) // em-dash unicode
|
||||
.arg( curitem->text() ) );
|
||||
.arg( itemText ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -434,42 +590,58 @@ void QgsOptionsDialogBase::updateOptionsListVerticalTabs()
|
||||
if ( !mInit )
|
||||
return;
|
||||
|
||||
if ( mOptListWidget->maximumWidth() != 16777215 )
|
||||
mOptListWidget->setMaximumWidth( 16777215 );
|
||||
// auto-resize splitter for vert scrollbar without covering icons in icon-only mode
|
||||
// TODO: mOptListWidget has fixed 32px wide icons for now, allow user-defined
|
||||
// Note: called on splitter resize and dialog paint event, so only update when necessary
|
||||
int iconWidth = mOptListWidget->iconSize().width();
|
||||
int snapToIconWidth = iconWidth + 32;
|
||||
|
||||
QList<int> splitSizes = mOptSplitter->sizes();
|
||||
mIconOnly = ( splitSizes.at( 0 ) <= snapToIconWidth );
|
||||
|
||||
// iconBuffer (above) may need adjusted if you adjust iconWidth here
|
||||
int newWidth = mOptListWidget->verticalScrollBar()->isVisible() ? iconWidth + 22 : iconWidth + 9;
|
||||
bool diffWidth = mOptListWidget->minimumWidth() != newWidth;
|
||||
|
||||
if ( diffWidth )
|
||||
mOptListWidget->setMinimumWidth( newWidth );
|
||||
|
||||
if ( mIconOnly && ( diffWidth || mOptListWidget->width() != newWidth ) )
|
||||
QAbstractItemView *optView = mOptListWidget ? static_cast< QAbstractItemView * >( mOptListWidget ) : static_cast< QAbstractItemView * >( mOptTreeView );
|
||||
if ( optView )
|
||||
{
|
||||
splitSizes[1] = splitSizes.at( 1 ) - ( splitSizes.at( 0 ) - newWidth );
|
||||
splitSizes[0] = newWidth;
|
||||
mOptSplitter->setSizes( splitSizes );
|
||||
}
|
||||
if ( optView->maximumWidth() != 16777215 )
|
||||
optView->setMaximumWidth( 16777215 );
|
||||
// auto-resize splitter for vert scrollbar without covering icons in icon-only mode
|
||||
// TODO: mOptListWidget has fixed 32px wide icons for now, allow user-defined
|
||||
// Note: called on splitter resize and dialog paint event, so only update when necessary
|
||||
int iconWidth = optView->iconSize().width();
|
||||
int snapToIconWidth = iconWidth + 32;
|
||||
|
||||
if ( mOptListWidget->wordWrap() && mIconOnly )
|
||||
mOptListWidget->setWordWrap( false );
|
||||
if ( !mOptListWidget->wordWrap() && !mIconOnly )
|
||||
mOptListWidget->setWordWrap( true );
|
||||
QList<int> splitSizes = mOptSplitter->sizes();
|
||||
mIconOnly = ( splitSizes.at( 0 ) <= snapToIconWidth );
|
||||
|
||||
// iconBuffer (above) may need adjusted if you adjust iconWidth here
|
||||
int newWidth = optView->verticalScrollBar()->isVisible() ? iconWidth + 22 : iconWidth + 9;
|
||||
bool diffWidth = optView->minimumWidth() != newWidth;
|
||||
|
||||
if ( diffWidth )
|
||||
optView->setMinimumWidth( newWidth );
|
||||
|
||||
if ( mIconOnly && ( diffWidth || optView->width() != newWidth ) )
|
||||
{
|
||||
splitSizes[1] = splitSizes.at( 1 ) - ( splitSizes.at( 0 ) - newWidth );
|
||||
splitSizes[0] = newWidth;
|
||||
mOptSplitter->setSizes( splitSizes );
|
||||
}
|
||||
|
||||
if ( mOptListWidget )
|
||||
{
|
||||
if ( mOptListWidget->wordWrap() && mIconOnly )
|
||||
mOptListWidget->setWordWrap( false );
|
||||
if ( !mOptListWidget->wordWrap() && !mIconOnly )
|
||||
mOptListWidget->setWordWrap( true );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsOptionsDialogBase::optionsStackedWidget_CurrentChanged( int index )
|
||||
{
|
||||
mOptListWidget->blockSignals( true );
|
||||
mOptListWidget->setCurrentRow( index );
|
||||
mOptListWidget->blockSignals( false );
|
||||
if ( mOptListWidget )
|
||||
{
|
||||
mOptListWidget->blockSignals( true );
|
||||
mOptListWidget->setCurrentRow( index );
|
||||
mOptListWidget->blockSignals( false );
|
||||
}
|
||||
else if ( mOptTreeView )
|
||||
{
|
||||
mOptTreeView->blockSignals( true );
|
||||
mOptTreeView->setCurrentIndex( pageNumberToTreeViewIndex( index ) );
|
||||
mOptTreeView->blockSignals( false );
|
||||
}
|
||||
|
||||
updateWindowTitle();
|
||||
}
|
||||
@ -477,7 +649,14 @@ void QgsOptionsDialogBase::optionsStackedWidget_CurrentChanged( int index )
|
||||
void QgsOptionsDialogBase::optionsStackedWidget_WidgetRemoved( int index )
|
||||
{
|
||||
// will need to take item first, if widgets are set for item in future
|
||||
delete mOptListWidget->item( index );
|
||||
if ( mOptListWidget )
|
||||
{
|
||||
delete mOptListWidget->item( index );
|
||||
}
|
||||
else if ( mOptTreeModel )
|
||||
{
|
||||
mOptTreeModel->removeRow( index );
|
||||
}
|
||||
|
||||
QList<QPair< QgsOptionsDialogHighlightWidget *, int > >::iterator it = mRegisteredSearchWidgets.begin();
|
||||
while ( it != mRegisteredSearchWidgets.end() )
|
||||
|
@ -35,11 +35,13 @@ class QPainter;
|
||||
class QStackedWidget;
|
||||
class QStyleOptionViewItem;
|
||||
class QSplitter;
|
||||
class QStandardItem;
|
||||
class QTreeView;
|
||||
class QStandardItemModel;
|
||||
|
||||
class QgsFilterLineEdit;
|
||||
class QgsOptionsDialogHighlightWidget;
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup gui
|
||||
* \class QgsOptionsDialogBase
|
||||
@ -177,21 +179,36 @@ class GUI_EXPORT QgsOptionsDialogBase : public QDialog
|
||||
*/
|
||||
void registerTextSearchWidgets();
|
||||
|
||||
/**
|
||||
* Creates a new QStandardItem with the specified name, tooltip and icon.
|
||||
*
|
||||
* \since QGIS 3.22
|
||||
*/
|
||||
QStandardItem *createItem( const QString &name, const QString &tooltip, const QString &icon ) SIP_SKIP;
|
||||
|
||||
QList< QPair< QgsOptionsDialogHighlightWidget *, int > > mRegisteredSearchWidgets;
|
||||
|
||||
QString mOptsKey;
|
||||
bool mInit;
|
||||
bool mInit = false;
|
||||
QListWidget *mOptListWidget = nullptr;
|
||||
QTreeView *mOptTreeView = nullptr;
|
||||
QStandardItemModel *mOptTreeModel = nullptr;
|
||||
QStackedWidget *mOptStackedWidget = nullptr;
|
||||
QSplitter *mOptSplitter = nullptr;
|
||||
QDialogButtonBox *mOptButtonBox = nullptr;
|
||||
QgsFilterLineEdit *mSearchLineEdit = nullptr;
|
||||
QString mDialogTitle;
|
||||
bool mIconOnly;
|
||||
bool mIconOnly = false;
|
||||
// pointer to app or custom, external QgsSettings
|
||||
// QPointer in case custom settings obj gets deleted while dialog is open
|
||||
QPointer<QgsSettings> mSettings;
|
||||
bool mDelSettings;
|
||||
bool mDelSettings = false;
|
||||
|
||||
private:
|
||||
|
||||
void setListToItemAtIndex( int index );
|
||||
QModelIndex pageNumberToTreeViewIndex( int page );
|
||||
int viewIndexToPageNumber( const QModelIndex &index );
|
||||
};
|
||||
|
||||
#endif // QGSOPTIONSDIALOGBASE_H
|
||||
|
@ -61,7 +61,7 @@
|
||||
<widget class="QgsFilterLineEdit" name="mSearchLineEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="mOptionsListWidget">
|
||||
<widget class="QTreeView" name="mOptionsTreeView">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>58</width>
|
||||
@ -89,216 +89,6 @@
|
||||
<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>General</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>General</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../images/images.qrc">
|
||||
<normaloff>:/images/themes/default/propertyicons/general.svg</normaloff>:/images/themes/default/propertyicons/general.svg</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>System</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>System</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>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>CRS</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>CRS</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../images/images.qrc">
|
||||
<normaloff>:/images/themes/default/propertyicons/CRS.svg</normaloff>:/images/themes/default/propertyicons/CRS.svg</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Transformations</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Coordinate transformations and operations</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../images/images.qrc">
|
||||
<normaloff>:/images/themes/default/transformation.svg</normaloff>:/images/themes/default/transformation.svg</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Data Sources</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Data sources</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../images/images.qrc">
|
||||
<normaloff>:/images/themes/default/propertyicons/attributes.svg</normaloff>:/images/themes/default/propertyicons/attributes.svg</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Rendering</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Rendering</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../images/images.qrc">
|
||||
<normaloff>:/images/themes/default/propertyicons/rendering.svg</normaloff>:/images/themes/default/propertyicons/rendering.svg</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Canvas & Legend</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Canvas and legend</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../images/images.qrc">
|
||||
<normaloff>:/images/themes/default/propertyicons/overlay.svg</normaloff>:/images/themes/default/propertyicons/overlay.svg</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Map Tools</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Map tools</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../images/images.qrc">
|
||||
<normaloff>:/images/themes/default/propertyicons/map_tools.svg</normaloff>:/images/themes/default/propertyicons/map_tools.svg</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Colors</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Colors</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../images/images.qrc">
|
||||
<normaloff>:/images/themes/default/propertyicons/colors.svg</normaloff>:/images/themes/default/propertyicons/colors.svg</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Digitizing</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Digitizing</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../images/images.qrc">
|
||||
<normaloff>:/images/themes/default/propertyicons/digitizing.svg</normaloff>:/images/themes/default/propertyicons/digitizing.svg</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Layouts</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Print layouts</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../images/images.qrc">
|
||||
<normaloff>:/images/themes/default/mIconLayout.svg</normaloff>:/images/themes/default/mIconLayout.svg</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>GDAL</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>GDAL</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../images/images.qrc">
|
||||
<normaloff>:/images/themes/default/propertyicons/gdal.svg</normaloff>:/images/themes/default/propertyicons/gdal.svg</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Variables</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Variables</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../images/images.qrc">
|
||||
<normaloff>:/images/themes/default/mIconExpression.svg</normaloff>:/images/themes/default/mIconExpression.svg</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Authentication</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Authentication</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../images/images.qrc">
|
||||
<normaloff>:/images/themes/default/locked.svg</normaloff>:/images/themes/default/locked.svg</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Network</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Network</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../images/images.qrc">
|
||||
<normaloff>:/images/themes/default/propertyicons/network_and_proxy.svg</normaloff>:/images/themes/default/propertyicons/network_and_proxy.svg</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Locator</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Locator</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../images/images.qrc">
|
||||
<normaloff>:/images/themes/default/search.svg</normaloff>:/images/themes/default/search.svg</iconset>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Acceleration</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Configure GPU for processing algorithms</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../images/images.qrc">
|
||||
<normaloff>:/images/themes/default/mIconGPU.svg</normaloff>:/images/themes/default/mIconGPU.svg</iconset>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
@ -6316,7 +6106,7 @@ p, li { white-space: pre-wrap; }
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>mSearchLineEdit</tabstop>
|
||||
<tabstop>mOptionsListWidget</tabstop>
|
||||
<tabstop>mOptionsTreeView</tabstop>
|
||||
<tabstop>mOptionsScrollArea_01</tabstop>
|
||||
<tabstop>grpLocale</tabstop>
|
||||
<tabstop>cboTranslation</tabstop>
|
||||
@ -6550,22 +6340,6 @@ p, li { white-space: pre-wrap; }
|
||||
<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>144</x>
|
||||
<y>196</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>790</x>
|
||||
<y>43</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>chkMaxThreads</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
|
Loading…
x
Reference in New Issue
Block a user