18#include "moc_qgsoptionsdialogbase.cpp"
21#include <QDialogButtonBox>
24#include <QListWidgetItem>
29#include <QStackedWidget>
31#include <QStandardItem>
46 : QDialog( parent, fl )
47 , mOptsKey( settingsKey )
48 , mSettings( settings )
56 mSettings->setValue( QStringLiteral(
"/Windows/%1/geometry" ).arg(
mOptsKey ), saveGeometry() );
83 if ( title.isEmpty() )
90 if (
auto *lLayout = layout() )
92 lLayout->setContentsMargins( 0, 0, 0, 0 );
96 mOptListWidget = findChild<QListWidget *>( QStringLiteral(
"mOptionsListWidget" ) );
97 mOptTreeView = findChild<QTreeView *>( QStringLiteral(
"mOptionsTreeView" ) );
107 QFrame *optionsFrame = findChild<QFrame *>( QStringLiteral(
"mOptionsFrame" ) );
108 mOptStackedWidget = findChild<QStackedWidget *>( QStringLiteral(
"mOptionsStackedWidget" ) );
109 mOptSplitter = findChild<QSplitter *>( QStringLiteral(
"mOptionsSplitter" ) );
110 mOptButtonBox = findChild<QDialogButtonBox *>( QStringLiteral(
"buttonBox" ) );
111 QFrame *buttonBoxFrame = findChild<QFrame *>( QStringLiteral(
"mButtonBoxFrame" ) );
112 mSearchLineEdit = findChild<QgsFilterLineEdit *>( QStringLiteral(
"mSearchLineEdit" ) );
127 iconSize = size + iconBuffer;
134 optView->setIconSize( QSize( iconSize, iconSize ) );
135 optView->setFrameStyle( QFrame::NoFrame );
138 optionsFrame->layout()->setContentsMargins( 0, frameMargin, frameMargin, frameMargin );
139 QVBoxLayout *layout =
static_cast<QVBoxLayout *
>( optionsFrame->layout() );
141 if ( buttonBoxFrame )
143 buttonBoxFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
144 layout->insertWidget( layout->count(), buttonBoxFrame );
154 disconnect(
mOptButtonBox, &QDialogButtonBox::accepted,
this, &QDialog::accept );
155 connect(
mOptButtonBox, &QDialogButtonBox::accepted,
this, &QDialog::accept );
156 disconnect(
mOptButtonBox, &QDialogButtonBox::rejected,
this, &QDialog::reject );
157 connect(
mOptButtonBox, &QDialogButtonBox::rejected,
this, &QDialog::reject );
166 connect(
mOptTreeView->selectionModel(), &QItemSelectionModel::selectionChanged,
mOptStackedWidget, [ = ](
const QItemSelection &,
const QItemSelection & )
168 const QModelIndexList selected = mOptTreeView->selectionModel()->selectedIndexes();
169 if ( selected.isEmpty() )
172 const QModelIndex index = mTreeProxyModel->mapToSource( selected.at( 0 ) );
174 if ( !mOptTreeModel || !mOptTreeModel->itemFromIndex( index )->isSelectable() )
177 mOptStackedWidget->setCurrentIndex( mTreeProxyModel->sourceIndexToPageNumber( index ) );
215 if ( !title.isEmpty() )
226 restoreGeometry(
mSettings->value( QStringLiteral(
"/Windows/%1/geometry" ).arg(
mOptsKey ) ).toByteArray() );
232 optView->setMaximumWidth(
235 optView->setAttribute( Qt::WA_MacShowFocusRect,
false );
247 l->setContentsMargins( 0, 0, 0, 0 );
254 int curIndx =
mSettings->value( QStringLiteral(
"/Windows/%1/tab" ).arg(
mOptsKey ), 0 ).toInt();
275 setListToItemAtIndex( curIndx );
278void QgsOptionsDialogBase::setListToItemAtIndex(
int index )
297 QSizePolicy::Policy policy = QSizePolicy::Ignored;
300 policy = QSizePolicy::MinimumExpanding;
320 if ( currentPage->objectName() == page )
329void QgsOptionsDialogBase::addPage(
const QString &title,
const QString &tooltip,
const QIcon &icon, QWidget *widget,
const QStringList &path,
const QString &key )
335 QListWidgetItem *item =
new QListWidgetItem();
336 item->setIcon( icon );
337 item->setText( title );
338 item->setToolTip( tooltip );
343 QStandardItem *item =
new QStandardItem( icon, title );
344 item->setToolTip( tooltip );
345 if ( !key.isEmpty() )
347 item->setData( key );
351 QStandardItem *parentItem =
nullptr;
354 QStringList parents = path;
355 while ( !parents.empty() )
357 const QString parentPath = parents.takeFirst();
359 QModelIndex thisParent;
360 for (
int row = 0; row <
mOptTreeModel->rowCount( parent ); ++row )
362 const QModelIndex index =
mOptTreeModel->index( row, 0, parent );
363 if ( index.data().toString().compare( parentPath, Qt::CaseInsensitive ) == 0
364 || index.data( Qt::UserRole + 1 ).toString().compare( parentPath, Qt::CaseInsensitive ) == 0 )
372 if ( !thisParent.isValid() )
374 QStandardItem *newParentItem =
new QStandardItem( parentPath );
375 newParentItem->setToolTip( parentPath );
376 newParentItem->setSelectable(
false );
378 parentItem->appendRow( newParentItem );
381 parentItem = newParentItem;
393 parentItem->appendRow( item );
394 const QModelIndex newIndex =
mOptTreeModel->indexFromItem( item );
402 scrollArea->setWidgetResizable(
true );
403 scrollArea->setFrameShape( QFrame::NoFrame );
404 scrollArea->setObjectName( widget->objectName() );
405 scrollArea->setWidget( widget );
413void QgsOptionsDialogBase::insertPage(
const QString &title,
const QString &tooltip,
const QIcon &icon, QWidget *widget,
const QString &before,
const QStringList &path,
const QString &key )
419 if ( currentPage->objectName() == before )
425 QListWidgetItem *item =
new QListWidgetItem();
426 item->setIcon( icon );
427 item->setText( title );
428 item->setToolTip( tooltip );
433 QModelIndex sourceIndexBefore =
mTreeProxyModel->pageNumberToSourceIndex( page );
434 QList< QModelIndex > sourceBeforeIndices;
435 while ( sourceIndexBefore.parent().isValid() )
437 sourceBeforeIndices.insert( 0, sourceIndexBefore );
438 sourceIndexBefore = sourceIndexBefore.parent();
440 sourceBeforeIndices.insert( 0, sourceIndexBefore );
442 QStringList parentPaths = path;
444 QModelIndex parentIndex;
445 QStandardItem *parentItem =
nullptr;
446 while ( !parentPaths.empty() )
448 QString thisPath = parentPaths.takeFirst();
449 QModelIndex sourceIndex = !sourceBeforeIndices.isEmpty() ? sourceBeforeIndices.takeFirst() : QModelIndex();
451 if ( sourceIndex.data().toString().compare( thisPath, Qt::CaseInsensitive ) == 0
452 || sourceIndex.data( Qt::UserRole + 1 ).toString().compare( thisPath, Qt::CaseInsensitive ) == 0 )
454 parentIndex = sourceIndex;
459 QStandardItem *newParentItem =
new QStandardItem( thisPath );
460 newParentItem->setToolTip( thisPath );
461 newParentItem->setSelectable(
false );
462 if ( sourceIndex.isValid() )
466 parentItem->insertRow( sourceIndex.row(), newParentItem );
468 mOptTreeModel->insertRow( sourceIndex.row(), newParentItem );
474 parentItem->appendRow( newParentItem );
478 parentItem = newParentItem;
482 QStandardItem *item =
new QStandardItem( icon, title );
483 item->setToolTip( tooltip );
484 if ( !key.isEmpty() )
486 item->setData( key );
490 if ( sourceBeforeIndices.empty() )
491 parentItem->appendRow( item );
494 parentItem->insertRow( sourceBeforeIndices.at( 0 ).row(), item );
504 scrollArea->setWidgetResizable(
true );
505 scrollArea->setFrameShape( QFrame::NoFrame );
506 scrollArea->setWidget( widget );
507 scrollArea->setObjectName( widget->objectName() );
514 addPage( title, tooltip, icon, widget, path );
519 const int minimumTextLength = 3;
536 if (
mOptListWidget->item( r )->text().contains( text, Qt::CaseInsensitive ) )
542 mOptListWidget->setRowHidden( r, text.length() >= minimumTextLength );
548 if ( rsw.first->searchHighlight( text.length() >= minimumTextLength ? text : QString() ) )
556 QMap< int, bool > hiddenPages;
559 hiddenPages.insert( r, text.length() >= minimumTextLength );
562 std::function<void(
const QModelIndex & )> traverseModel;
564 traverseModel = [&](
const QModelIndex & parent )
566 for (
int row = 0; row <
mOptTreeModel->rowCount( parent ); ++row )
568 const QModelIndex currentIndex =
mOptTreeModel->index( row, 0, parent );
569 if ( currentIndex.data().toString().contains( text, Qt::CaseInsensitive ) )
571 hiddenPages.insert(
mTreeProxyModel->sourceIndexToPageNumber( currentIndex ), false );
573 traverseModel( currentIndex );
576 traverseModel( QModelIndex() );
580 if ( rsw.first->searchHighlight( text.length() >= minimumTextLength ? text : QString() ) )
582 hiddenPages.insert( rsw.second,
false );
585 for (
auto it = hiddenPages.constBegin(); it != hiddenPages.constEnd(); ++it )
590 if (
mOptTreeView && text.length() >= minimumTextLength )
616 if ( !
mTreeProxyModel->filterAcceptsRow( currentSourceIndex.row(), currentSourceIndex.parent() ) )
618 std::function<QModelIndex(
const QModelIndex & )> traverseModel;
619 traverseModel = [&](
const QModelIndex & parent ) -> QModelIndex
623 const QModelIndex proxyIndex =
mTreeProxyModel->index( row, 0, parent );
624 const QModelIndex sourceIndex =
mTreeProxyModel->mapToSource( proxyIndex );
625 if (
mOptTreeModel->itemFromIndex( sourceIndex )->isSelectable() )
631 QModelIndex res = traverseModel( proxyIndex );
636 return QModelIndex();
639 const QModelIndex firstVisibleSourceIndex = traverseModel( QModelIndex() );
641 if ( firstVisibleSourceIndex.isValid() )
667 const QList< QWidget * > widgets =
mOptStackedWidget->widget( i )->findChildren<QWidget *>();
668 for ( QWidget *widget : widgets )
675 QHash<QWidget *, QgsOptionsDialogHighlightWidget *> customHighlightWidgets;
682 if ( customHighlightWidgets.contains( widget ) )
684 shw = customHighlightWidgets.value( widget );
694 QgsDebugMsgLevel( QStringLiteral(
"Registering: %1" ).arg( widget->objectName() ), 4 );
708 res->setToolTip( tooltip );
736 QDialog::showEvent( e );
744 QDialog::paintEvent( e );
751 if ( !itemText.isEmpty() )
753 setWindowTitle( QStringLiteral(
"%1 %2 %3" )
755 .arg( QChar( 0x2014 ) )
772 if ( optView->maximumWidth() != 16777215 )
773 optView->setMaximumWidth( 16777215 );
777 int iconWidth = optView->iconSize().width();
778 int snapToIconWidth = iconWidth + 32;
781 mIconOnly = ( splitSizes.at( 0 ) <= snapToIconWidth );
784 int newWidth = optView->verticalScrollBar()->isVisible() ? iconWidth + 22 : iconWidth + 9;
785 bool diffWidth = optView->minimumWidth() != newWidth;
788 optView->setMinimumWidth( newWidth );
790 if (
mIconOnly && ( diffWidth || optView->width() != newWidth ) )
792 splitSizes[1] = splitSizes.at( 1 ) - ( splitSizes.at( 0 ) - newWidth );
793 splitSizes[0] = newWidth;
840 if ( ( *it ).second == index )
849 QMessageBox::warning(
nullptr, tr(
"Missing Objects" ),
850 tr(
"Base options dialog could not be initialized.\n\n"
851 "Missing some of the .ui template objects:\n" )
852 +
" mOptionsListWidget,\n mOptionsStackedWidget,\n mOptionsSplitter,\n mOptionsListFrame",
859QgsOptionsProxyModel::QgsOptionsProxyModel( QObject *parent )
860 : QSortFilterProxyModel( parent )
862 setDynamicSortFilter(
true );
865void QgsOptionsProxyModel::setPageHidden(
int page,
bool hidden )
867 mHiddenPages[ page ] = hidden;
871QModelIndex QgsOptionsProxyModel::pageNumberToSourceIndex(
int page )
const
873 QStandardItemModel *itemModel = qobject_cast< QStandardItemModel * >( sourceModel() );
875 return QModelIndex();
877 int pagesRemaining = page;
878 std::function<QModelIndex(
const QModelIndex & )> traversePages;
881 traversePages = [&](
const QModelIndex & parent ) -> QModelIndex
883 for (
int row = 0; row < itemModel->rowCount( parent ); ++row )
885 const QModelIndex currentIndex = itemModel->index( row, 0, parent );
886 if ( itemModel->itemFromIndex( currentIndex )->isSelectable() )
888 if ( pagesRemaining == 0 )
891 else pagesRemaining--;
894 const QModelIndex res = traversePages( currentIndex );
898 return QModelIndex();
901 return traversePages( QModelIndex() );
904int QgsOptionsProxyModel::sourceIndexToPageNumber(
const QModelIndex &index )
const
906 QStandardItemModel *itemModel = qobject_cast< QStandardItemModel * >( sourceModel() );
912 std::function<int(
const QModelIndex & )> traverseModel;
915 traverseModel = [&](
const QModelIndex & parent ) ->
int
917 for (
int row = 0; row < itemModel->rowCount( parent ); ++row )
919 const QModelIndex currentIndex = itemModel->index( row, 0, parent );
920 if ( currentIndex == index )
923 if ( itemModel->itemFromIndex( currentIndex )->isSelectable() )
926 const int res = traverseModel( currentIndex );
933 return traverseModel( QModelIndex() );
936bool QgsOptionsProxyModel::filterAcceptsRow(
int source_row,
const QModelIndex &source_parent )
const
938 QStandardItemModel *itemModel = qobject_cast< QStandardItemModel * >( sourceModel() );
942 const QModelIndex sourceIndex = sourceModel()->index( source_row, 0, source_parent );
944 const int pageNumber = sourceIndexToPageNumber( sourceIndex );
945 if ( !mHiddenPages.value( pageNumber,
false ) )
948 if ( sourceModel()->hasChildren( sourceIndex ) )
951 for (
int row = 0; row < sourceModel()->rowCount( sourceIndex ); ++row )
953 if ( filterAcceptsRow( row, sourceIndex ) )
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
void setShowSearchIcon(bool visible)
Define if a search icon shall be shown on the left of the image when no text is entered.
void cleared()
Emitted when the widget is cleared.
virtual void updateWindowTitle()
QPointer< QgsSettings > mSettings
void warnAboutMissingObjects()
void resizeAlltabs(int index)
Resizes all tabs when the dialog is resized.
void paintEvent(QPaintEvent *e) override
void restoreLastPage()
Refocus the active tab from the last time the dialog was shown.
void searchText(const QString &text)
searchText searches for a text in all the pages of the stacked widget and highlight the results
void registerTextSearchWidgets()
register widgets in the dialog to search for text in it it is automatically called if a line edit has...
virtual void optionsStackedWidget_CurrentChanged(int index)
Select relevant tab on current page change.
QList< QPair< QgsOptionsDialogHighlightWidget *, int > > mRegisteredSearchWidgets
~QgsOptionsDialogBase() override
QgsOptionsDialogBase(const QString &settingsKey, QWidget *parent=nullptr, Qt::WindowFlags fl=Qt::WindowFlags(), QgsSettings *settings=nullptr)
Constructor.
QgsFilterLineEdit * mSearchLineEdit
void setSettings(QgsSettings *settings)
virtual void optionsStackedWidget_WidgetRemoved(int index)
Remove tab and unregister widgets on page remove.
QDialogButtonBox * mOptButtonBox
QgsOptionsProxyModel * mTreeProxyModel
void addPage(const QString &title, const QString &tooltip, const QIcon &icon, QWidget *widget, const QStringList &path=QStringList(), const QString &key=QString())
Adds a new page to the dialog pages.
QStandardItemModel * mOptTreeModel
QStandardItem * createItem(const QString &name, const QString &tooltip, const QString &icon)
Creates a new QStandardItem with the specified name, tooltip and icon.
virtual void updateOptionsListVerticalTabs()
Update tabs on the splitter move.
QListWidget * mOptListWidget
void restoreOptionsBaseUi(const QString &title=QString())
Restore the base ui.
QStackedWidget * mOptStackedWidget
void initOptionsBase(bool restoreUi=true, const QString &title=QString())
Set up the base ui connections for vertical tabs.
void showEvent(QShowEvent *e) override
void insertPage(const QString &title, const QString &tooltip, const QIcon &icon, QWidget *widget, const QString &before, const QStringList &path=QStringList(), const QString &key=QString())
Inserts a new page into the dialog pages.
void setCurrentPage(const QString &page)
Sets the dialog page (by object name) to show.
Base class for widgets for pages included in the options dialog.
QHash< QWidget *, QgsOptionsDialogHighlightWidget * > registeredHighlightWidgets()
Returns the registered highlight widgets used to search and highlight text in options dialogs.
This class is a composition of two QSettings instances:
static bool isNull(const QVariant &variant, bool silenceNullWarnings=false)
Returns true if the specified variant should be considered a NULL value.
int scaleIconSize(int standardSize)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly,...
#define QgsDebugMsgLevel(str, level)