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 & ) {
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.
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)