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, [
this]( 
const QItemSelection &, 
const QItemSelection & ) {
 
  167      const QModelIndexList selected = mOptTreeView->selectionModel()->selectedIndexes();
 
  168      if ( selected.isEmpty() )
 
  171      const QModelIndex index = mTreeProxyModel->mapToSource( selected.at( 0 ) );
 
  173      if ( !mOptTreeModel || !mOptTreeModel->itemFromIndex( index )->isSelectable() )
 
  176      mOptStackedWidget->setCurrentIndex( mTreeProxyModel->sourceIndexToPageNumber( index ) );
 
 
  214  if ( !title.isEmpty() )
 
  225  restoreGeometry( 
mSettings->value( QStringLiteral( 
"/Windows/%1/geometry" ).arg( 
mOptsKey ) ).toByteArray() );
 
  231    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 ) {
 
  565      for ( 
int row = 0; row < 
mOptTreeModel->rowCount( parent ); ++row )
 
  567        const QModelIndex currentIndex = 
mOptTreeModel->index( row, 0, parent );
 
  568        if ( currentIndex.data().toString().contains( text, Qt::CaseInsensitive ) )
 
  570          hiddenPages.insert( 
mTreeProxyModel->sourceIndexToPageNumber( currentIndex ), false );
 
  572        traverseModel( currentIndex );
 
  575    traverseModel( QModelIndex() );
 
  579      if ( rsw.first->searchHighlight( text.length() >= minimumTextLength ? text : QString() ) )
 
  581        hiddenPages.insert( rsw.second, 
false );
 
  584    for ( 
auto it = hiddenPages.constBegin(); it != hiddenPages.constEnd(); ++it )
 
  589  if ( 
mOptTreeView && text.length() >= minimumTextLength )
 
  615    if ( !
mTreeProxyModel->filterAcceptsRow( currentSourceIndex.row(), currentSourceIndex.parent() ) )
 
  617      std::function<QModelIndex( 
const QModelIndex & )> traverseModel;
 
  618      traverseModel = [&]( 
const QModelIndex &parent ) -> QModelIndex {
 
  621          const QModelIndex proxyIndex = 
mTreeProxyModel->index( row, 0, parent );
 
  622          const QModelIndex sourceIndex = 
mTreeProxyModel->mapToSource( proxyIndex );
 
  623          if ( 
mOptTreeModel->itemFromIndex( sourceIndex )->isSelectable() )
 
  629            QModelIndex res = traverseModel( proxyIndex );
 
  634        return QModelIndex();
 
  637      const QModelIndex firstVisibleSourceIndex = traverseModel( QModelIndex() );
 
  639      if ( firstVisibleSourceIndex.isValid() )
 
 
  665    const QList<QWidget *> widgets = 
mOptStackedWidget->widget( i )->findChildren<QWidget *>();
 
  666    for ( QWidget *widget : widgets )
 
  673        QHash<QWidget *, QgsOptionsDialogHighlightWidget *> customHighlightWidgets;
 
  680        if ( customHighlightWidgets.contains( widget ) )
 
  682          shw = customHighlightWidgets.value( widget );
 
  692        QgsDebugMsgLevel( QStringLiteral( 
"Registering: %1" ).arg( widget->objectName() ), 4 );
 
 
  706  res->setToolTip( tooltip );
 
 
  734  QDialog::showEvent( e );
 
 
  742  QDialog::paintEvent( e );
 
 
  750  if ( !itemText.isEmpty() )
 
  752    setWindowTitle( QStringLiteral( 
"%1 %2 %3" )
 
  754                      .arg( QChar( 0x2014 ) ) 
 
 
  771    if ( optView->maximumWidth() != 16777215 )
 
  772      optView->setMaximumWidth( 16777215 );
 
  776    int iconWidth = optView->iconSize().width();
 
  777    int snapToIconWidth = iconWidth + 32;
 
  780    mIconOnly = ( splitSizes.at( 0 ) <= snapToIconWidth );
 
  783    int newWidth = optView->verticalScrollBar()->isVisible() ? iconWidth + 22 : iconWidth + 9;
 
  784    bool diffWidth = optView->minimumWidth() != newWidth;
 
  787      optView->setMinimumWidth( newWidth );
 
  789    if ( 
mIconOnly && ( diffWidth || optView->width() != newWidth ) )
 
  791      splitSizes[1] = splitSizes.at( 1 ) - ( splitSizes.at( 0 ) - newWidth );
 
  792      splitSizes[0] = newWidth;
 
 
  839    if ( ( *it ).second == index )
 
 
  848  QMessageBox::warning( 
nullptr, tr( 
"Missing Objects" ), tr( 
"Base options dialog could not be initialized.\n\n" 
  849                                                              "Missing some of the .ui template objects:\n" )
 
  850                                                            + 
" mOptionsListWidget,\n mOptionsStackedWidget,\n mOptionsSplitter,\n mOptionsListFrame",
 
  851                        QMessageBox::Ok, QMessageBox::Ok );
 
 
  856QgsOptionsProxyModel::QgsOptionsProxyModel( QObject *parent )
 
  857  : QSortFilterProxyModel( parent )
 
  859  setDynamicSortFilter( 
true );
 
  862void QgsOptionsProxyModel::setPageHidden( 
int page, 
bool hidden )
 
  864  mHiddenPages[page] = hidden;
 
  868QModelIndex QgsOptionsProxyModel::pageNumberToSourceIndex( 
int page )
 const 
  870  QStandardItemModel *itemModel = qobject_cast<QStandardItemModel *>( sourceModel() );
 
  872    return QModelIndex();
 
  874  int pagesRemaining = page;
 
  875  std::function<QModelIndex( 
const QModelIndex & )> traversePages;
 
  878  traversePages = [&]( 
const QModelIndex &parent ) -> QModelIndex {
 
  879    for ( 
int row = 0; row < itemModel->rowCount( parent ); ++row )
 
  881      const QModelIndex currentIndex = itemModel->index( row, 0, parent );
 
  882      if ( itemModel->itemFromIndex( currentIndex )->isSelectable() )
 
  884        if ( pagesRemaining == 0 )
 
  891      const QModelIndex res = traversePages( currentIndex );
 
  895    return QModelIndex();
 
  898  return traversePages( QModelIndex() );
 
  901int QgsOptionsProxyModel::sourceIndexToPageNumber( 
const QModelIndex &index )
 const 
  903  QStandardItemModel *itemModel = qobject_cast<QStandardItemModel *>( sourceModel() );
 
  909  std::function<int( 
const QModelIndex & )> traverseModel;
 
  912  traverseModel = [&]( 
const QModelIndex &parent ) -> 
int {
 
  913    for ( 
int row = 0; row < itemModel->rowCount( parent ); ++row )
 
  915      const QModelIndex currentIndex = itemModel->index( row, 0, parent );
 
  916      if ( currentIndex == index )
 
  919      if ( itemModel->itemFromIndex( currentIndex )->isSelectable() )
 
  922      const int res = traverseModel( currentIndex );
 
  929  return traverseModel( QModelIndex() );
 
  932bool QgsOptionsProxyModel::filterAcceptsRow( 
int source_row, 
const QModelIndex &source_parent )
 const 
  934  QStandardItemModel *itemModel = qobject_cast<QStandardItemModel *>( sourceModel() );
 
  938  const QModelIndex sourceIndex = sourceModel()->index( source_row, 0, source_parent );
 
  940  const int pageNumber = sourceIndexToPageNumber( sourceIndex );
 
  941  if ( !mHiddenPages.value( pageNumber, 
false ) )
 
  944  if ( sourceModel()->hasChildren( sourceIndex ) )
 
  947    for ( 
int row = 0; row < sourceModel()->rowCount( sourceIndex ); ++row )
 
  949      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.
 
QList< QPair< QgsOptionsDialogHighlightWidget *, int > > mRegisteredSearchWidgets
 
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.
 
~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.
 
Stores settings for use within QGIS.
 
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)