20#include <QDialogButtonBox> 
   23#include <QListWidgetItem> 
   28#include <QStackedWidget> 
   30#include <QStandardItem> 
   44  : QDialog( parent, fl )
 
   45  , mOptsKey( settingsKey )
 
   46  , mSettings( settings )
 
   81  if ( title.isEmpty() )
 
   88  if ( 
auto *lLayout = layout() )
 
   90    lLayout->setContentsMargins( 0, 0, 0, 0 ); 
 
   94  mOptListWidget = findChild<QListWidget *>( QStringLiteral( 
"mOptionsListWidget" ) );
 
   95  mOptTreeView = findChild<QTreeView *>( QStringLiteral( 
"mOptionsTreeView" ) );
 
  105  QFrame *optionsFrame = findChild<QFrame *>( QStringLiteral( 
"mOptionsFrame" ) );
 
  106  mOptStackedWidget = findChild<QStackedWidget *>( QStringLiteral( 
"mOptionsStackedWidget" ) );
 
  107  mOptSplitter = findChild<QSplitter *>( QStringLiteral( 
"mOptionsSplitter" ) );
 
  108  mOptButtonBox = findChild<QDialogButtonBox *>( QStringLiteral( 
"buttonBox" ) );
 
  109  QFrame *buttonBoxFrame = findChild<QFrame *>( QStringLiteral( 
"mButtonBoxFrame" ) );
 
  110  mSearchLineEdit = findChild<QgsFilterLineEdit *>( QStringLiteral( 
"mSearchLineEdit" ) );
 
  133  optView->setFrameStyle( QFrame::NoFrame );
 
  136  optionsFrame->layout()->setContentsMargins( 0, frameMargin, frameMargin, frameMargin );
 
  137  QVBoxLayout *layout = 
static_cast<QVBoxLayout *
>( optionsFrame->layout() );
 
  139  if ( buttonBoxFrame )
 
  141    buttonBoxFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
 
  142    layout->insertWidget( layout->count(), buttonBoxFrame );
 
  152    disconnect( 
mOptButtonBox, &QDialogButtonBox::accepted, 
this, &QDialog::accept );
 
  153    connect( 
mOptButtonBox, &QDialogButtonBox::accepted, 
this, &QDialog::accept );
 
  154    disconnect( 
mOptButtonBox, &QDialogButtonBox::rejected, 
this, &QDialog::reject );
 
  155    connect( 
mOptButtonBox, &QDialogButtonBox::rejected, 
this, &QDialog::reject );
 
  164    connect( 
mOptTreeView->selectionModel(), &QItemSelectionModel::selectionChanged, 
mOptStackedWidget, [ = ]( 
const QItemSelection &, 
const QItemSelection & )
 
  166      const QModelIndexList selected = mOptTreeView->selectionModel()->selectedIndexes();
 
  167      if ( selected.isEmpty() )
 
  170      const QModelIndex index = mTreeProxyModel->mapToSource( selected.at( 0 ) );
 
  172      if ( !mOptTreeModel || !mOptTreeModel->itemFromIndex( index )->isSelectable() )
 
  175      mOptStackedWidget->setCurrentIndex( mTreeProxyModel->sourceIndexToPageNumber( index ) );
 
  213  if ( !title.isEmpty() )
 
  230    optView->setMaximumWidth(
 
  233    optView->setAttribute( Qt::WA_MacShowFocusRect, 
false );
 
  245      l->setContentsMargins( 0, 0, 0, 0 );
 
  252  int curIndx = 
mSettings->value( QStringLiteral( 
"/Windows/%1/tab" ).arg( 
mOptsKey ), 0 ).toInt();
 
  273  setListToItemAtIndex( curIndx );
 
  276void QgsOptionsDialogBase::setListToItemAtIndex( 
int index )
 
  295    QSizePolicy::Policy policy = QSizePolicy::Ignored;
 
  298      policy = QSizePolicy::MinimumExpanding;
 
  318    if ( currentPage->objectName() == page )
 
  327void QgsOptionsDialogBase::addPage( 
const QString &title, 
const QString &tooltip, 
const QIcon &icon, QWidget *widget, 
const QStringList &path, 
const QString &key )
 
  333    QListWidgetItem *item = 
new QListWidgetItem();
 
  334    item->setIcon( icon );
 
  335    item->setText( title );
 
  336    item->setToolTip( tooltip );
 
  341    QStandardItem *item = 
new QStandardItem( icon, title );
 
  342    item->setToolTip( tooltip );
 
  343    if ( !key.isEmpty() )
 
  345      item->setData( key );
 
  349    QStandardItem *parentItem = 
nullptr;
 
  352      QStringList parents = path;
 
  353      while ( !parents.empty() )
 
  355        const QString parentPath = parents.takeFirst();
 
  357        QModelIndex thisParent;
 
  358        for ( 
int row = 0; row < 
mOptTreeModel->rowCount( parent ); ++row )
 
  360          const QModelIndex index = 
mOptTreeModel->index( row, 0, parent );
 
  361          if ( index.data().toString().compare( parentPath, Qt::CaseInsensitive ) == 0
 
  362               || index.data( Qt::UserRole + 1 ).toString().compare( parentPath, Qt::CaseInsensitive ) == 0 )
 
  370        if ( !thisParent.isValid() )
 
  372          QStandardItem *newParentItem = 
new QStandardItem( parentPath );
 
  373          newParentItem->setToolTip( parentPath );
 
  374          newParentItem->setSelectable( 
false );
 
  376            parentItem->appendRow( newParentItem );
 
  379          parentItem = newParentItem;
 
  391      parentItem->appendRow( item );
 
  392      const QModelIndex newIndex = 
mOptTreeModel->indexFromItem( item );
 
  405void QgsOptionsDialogBase::insertPage( 
const QString &title, 
const QString &tooltip, 
const QIcon &icon, QWidget *widget, 
const QString &before, 
const QStringList &path, 
const QString &key )
 
  411    if ( currentPage->objectName() == before )
 
  417        QListWidgetItem *item = 
new QListWidgetItem();
 
  418        item->setIcon( icon );
 
  419        item->setText( title );
 
  420        item->setToolTip( tooltip );
 
  425        QModelIndex sourceIndexBefore = 
mTreeProxyModel->pageNumberToSourceIndex( page );
 
  426        QList< QModelIndex > sourceBeforeIndices;
 
  427        while ( sourceIndexBefore.parent().isValid() )
 
  429          sourceBeforeIndices.insert( 0, sourceIndexBefore );
 
  430          sourceIndexBefore = sourceIndexBefore.parent();
 
  432        sourceBeforeIndices.insert( 0, sourceIndexBefore );
 
  434        QStringList parentPaths = path;
 
  436        QModelIndex parentIndex;
 
  437        QStandardItem *parentItem = 
nullptr;
 
  438        while ( !parentPaths.empty() )
 
  440          QString thisPath = parentPaths.takeFirst();
 
  441          QModelIndex sourceIndex = !sourceBeforeIndices.isEmpty() ? sourceBeforeIndices.takeFirst() : QModelIndex();
 
  443          if ( sourceIndex.data().toString().compare( thisPath, Qt::CaseInsensitive ) == 0
 
  444               || sourceIndex.data( Qt::UserRole + 1 ).toString().compare( thisPath, Qt::CaseInsensitive ) == 0 )
 
  446            parentIndex = sourceIndex;
 
  451            QStandardItem *newParentItem = 
new QStandardItem( thisPath );
 
  452            newParentItem->setToolTip( thisPath );
 
  453            newParentItem->setSelectable( 
false );
 
  454            if ( sourceIndex.isValid() )
 
  458                parentItem->insertRow( sourceIndex.row(), newParentItem );
 
  460                mOptTreeModel->insertRow( sourceIndex.row(), newParentItem );
 
  466                parentItem->appendRow( newParentItem );
 
  470            parentItem = newParentItem;
 
  474        QStandardItem *item = 
new QStandardItem( icon, title );
 
  475        item->setToolTip( tooltip );
 
  476        if ( !key.isEmpty() )
 
  478          item->setData( key );
 
  482          if ( sourceBeforeIndices.empty() )
 
  483            parentItem->appendRow( item );
 
  486            parentItem->insertRow( sourceBeforeIndices.at( 0 ).row(), item );
 
  501  addPage( title, tooltip, icon, widget, path );
 
  506  const int minimumTextLength = 3;
 
  523      if ( 
mOptListWidget->item( r )->text().contains( text, Qt::CaseInsensitive ) )
 
  529        mOptListWidget->setRowHidden( r, text.length() >= minimumTextLength );
 
  535      if ( rsw.first->searchHighlight( text.length() >= minimumTextLength ? text : QString() ) )
 
  543    QMap< int, bool > hiddenPages;
 
  546      hiddenPages.insert( r, text.length() >= minimumTextLength );
 
  549    std::function<void( 
const QModelIndex & )> traverseModel;
 
  551    traverseModel = [&]( 
const QModelIndex & parent )
 
  553      for ( 
int row = 0; row < 
mOptTreeModel->rowCount( parent ); ++row )
 
  555        const QModelIndex currentIndex = 
mOptTreeModel->index( row, 0, parent );
 
  556        if ( currentIndex.data().toString().contains( text, Qt::CaseInsensitive ) )
 
  558          hiddenPages.insert( 
mTreeProxyModel->sourceIndexToPageNumber( currentIndex ), false );
 
  560        traverseModel( currentIndex );
 
  563    traverseModel( QModelIndex() );
 
  567      if ( rsw.first->searchHighlight( text.length() >= minimumTextLength ? text : QString() ) )
 
  569        hiddenPages.insert( rsw.second, 
false );
 
  572    for ( 
auto it = hiddenPages.constBegin(); it != hiddenPages.constEnd(); ++it )
 
  577  if ( 
mOptTreeView && text.length() >= minimumTextLength )
 
  603    if ( !
mTreeProxyModel->filterAcceptsRow( currentSourceIndex.row(), currentSourceIndex.parent() ) )
 
  605      std::function<QModelIndex( 
const QModelIndex & )> traverseModel;
 
  606      traverseModel = [&]( 
const QModelIndex & parent ) -> QModelIndex
 
  610          const QModelIndex proxyIndex = 
mTreeProxyModel->index( row, 0, parent );
 
  611          const QModelIndex sourceIndex = 
mTreeProxyModel->mapToSource( proxyIndex );
 
  612          if ( 
mOptTreeModel->itemFromIndex( sourceIndex )->isSelectable() )
 
  618            QModelIndex res = traverseModel( proxyIndex );
 
  623        return QModelIndex();
 
  626      const QModelIndex firstVisibleSourceIndex = traverseModel( QModelIndex() );
 
  628      if ( firstVisibleSourceIndex.isValid() )
 
  654    const QList< QWidget * > widgets = 
mOptStackedWidget->widget( i )->findChildren<QWidget *>();
 
  655    for ( QWidget *widget : widgets )
 
  662        QHash<QWidget *, QgsOptionsDialogHighlightWidget *> customHighlightWidgets;
 
  669        if ( customHighlightWidgets.contains( widget ) )
 
  671          shw = customHighlightWidgets.value( widget );
 
  681        QgsDebugMsgLevel( QStringLiteral( 
"Registering: %1" ).arg( widget->objectName() ), 4 );
 
  695  res->setToolTip( tooltip );
 
  723  QDialog::showEvent( e );
 
  731  QDialog::paintEvent( e );
 
  738  if ( !itemText.isEmpty() )
 
  740    setWindowTitle( QStringLiteral( 
"%1 %2 %3" )
 
  742                    .arg( QChar( 0x2014 ) ) 
 
  759    if ( optView->maximumWidth() != 16777215 )
 
  760      optView->setMaximumWidth( 16777215 );
 
  764    int iconWidth = optView->iconSize().width();
 
  765    int snapToIconWidth = iconWidth + 32;
 
  768    mIconOnly = ( splitSizes.at( 0 ) <= snapToIconWidth );
 
  771    int newWidth = optView->verticalScrollBar()->isVisible() ? iconWidth + 22 : iconWidth + 9;
 
  772    bool diffWidth = optView->minimumWidth() != newWidth;
 
  775      optView->setMinimumWidth( newWidth );
 
  777    if ( 
mIconOnly && ( diffWidth || optView->width() != newWidth ) )
 
  779      splitSizes[1] = splitSizes.at( 1 ) - ( splitSizes.at( 0 ) - newWidth );
 
  780      splitSizes[0] = newWidth;
 
  827    if ( ( *it ).second == index )
 
  836  QMessageBox::warning( 
nullptr, tr( 
"Missing Objects" ),
 
  837                        tr( 
"Base options dialog could not be initialized.\n\n" 
  838                            "Missing some of the .ui template objects:\n" )
 
  839                        + 
" mOptionsListWidget,\n mOptionsStackedWidget,\n mOptionsSplitter,\n mOptionsListFrame",
 
  846QgsOptionsProxyModel::QgsOptionsProxyModel( QObject *parent )
 
  847  : QSortFilterProxyModel( parent )
 
  849  setDynamicSortFilter( 
true );
 
  852void QgsOptionsProxyModel::setPageHidden( 
int page, 
bool hidden )
 
  854  mHiddenPages[ page ] = hidden;
 
  858QModelIndex QgsOptionsProxyModel::pageNumberToSourceIndex( 
int page )
 const 
  860  QStandardItemModel *itemModel = qobject_cast< QStandardItemModel * >( sourceModel() );
 
  862    return QModelIndex();
 
  864  int pagesRemaining = page;
 
  865  std::function<QModelIndex( 
const QModelIndex & )> traversePages;
 
  868  traversePages = [&]( 
const QModelIndex & parent ) -> QModelIndex
 
  870    for ( 
int row = 0; row < itemModel->rowCount( parent ); ++row )
 
  872      const QModelIndex currentIndex = itemModel->index( row, 0, parent );
 
  873      if ( itemModel->itemFromIndex( currentIndex )->isSelectable() )
 
  875        if ( pagesRemaining == 0 )
 
  878        else pagesRemaining--;
 
  881      const QModelIndex res = traversePages( currentIndex );
 
  885    return QModelIndex();
 
  888  return traversePages( QModelIndex() );
 
  891int QgsOptionsProxyModel::sourceIndexToPageNumber( 
const QModelIndex &index )
 const 
  893  QStandardItemModel *itemModel = qobject_cast< QStandardItemModel * >( sourceModel() );
 
  899  std::function<int( 
const QModelIndex & )> traverseModel;
 
  902  traverseModel = [&]( 
const QModelIndex & parent ) -> 
int 
  904    for ( 
int row = 0; row < itemModel->rowCount( parent ); ++row )
 
  906      const QModelIndex currentIndex = itemModel->index( row, 0, parent );
 
  907      if ( currentIndex == index )
 
  910      if ( itemModel->itemFromIndex( currentIndex )->isSelectable() )
 
  913      const int res = traverseModel( currentIndex );
 
  920  return traverseModel( QModelIndex() );
 
  923bool QgsOptionsProxyModel::filterAcceptsRow( 
int source_row, 
const QModelIndex &source_parent )
 const 
  925  QStandardItemModel *itemModel = qobject_cast< QStandardItemModel * >( sourceModel() );
 
  929  const QModelIndex sourceIndex = sourceModel()->index( source_row, 0, source_parent );
 
  931  const int pageNumber = sourceIndexToPageNumber( sourceIndex );
 
  932  if ( !mHiddenPages.value( pageNumber, 
false ) )
 
  935  if ( sourceModel()->hasChildren( sourceIndex ) )
 
  938    for ( 
int row = 0; row < sourceModel()->rowCount( sourceIndex ); ++row )
 
  940      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)
Returns true if the specified variant should be considered a NULL value.
 
bool restoreGeometry(QWidget *widget, const QString &keyName)
Restore the wigget geometry from settings.
 
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window's toolbar icons.
 
int scaleIconSize(int standardSize)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly,...
 
void saveGeometry(QWidget *widget, const QString &keyName)
Save the wigget geometry into settings.
 
#define QgsDebugMsgLevel(str, level)