| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,169 @@ | ||
| /*************************************************************************** | ||
| qgsoptionsdialogbase.cpp - base vertical tabs option dialog | ||
| --------------------- | ||
| begin : March 24, 2013 | ||
| copyright : (C) 2013 by Larry Shaffer | ||
| email : larrys at dakcarto dot com | ||
| *************************************************************************** | ||
| * * | ||
| * This program is free software; you can redistribute it and/or modify * | ||
| * it under the terms of the GNU General Public License as published by * | ||
| * the Free Software Foundation; either version 2 of the License, or * | ||
| * (at your option) any later version. * | ||
| * * | ||
| ***************************************************************************/ | ||
|
|
||
| #include "qgsoptionsdialogbase.h" | ||
|
|
||
| #include <QDialog> | ||
| #include <QDialogButtonBox> | ||
| #include <QListWidget> | ||
| #include <QMessageBox> | ||
| #include <QScrollBar> | ||
| #include <QSettings> | ||
| #include <QStackedWidget> | ||
| #include <QSplitter> | ||
| #include <QTimer> | ||
|
|
||
|
|
||
| QgsOptionsDialogBase::QgsOptionsDialogBase( QString settingsKey, QWidget* parent, Qt::WFlags fl ) | ||
| : QDialog( parent, fl ), mOptsKey( settingsKey ), mInit( false ) | ||
| { | ||
| } | ||
|
|
||
| QgsOptionsDialogBase::~QgsOptionsDialogBase() | ||
| { | ||
| if ( mInit ) | ||
| { | ||
| QSettings settings; | ||
| settings.setValue( QString( "/Windows/%1/geometry" ).arg( mOptsKey ), saveGeometry() ); | ||
| settings.setValue( QString( "/Windows/%1/splitState" ).arg( mOptsKey ), mOptSplitter->saveState() ); | ||
| settings.setValue( QString( "/Windows/%1/tab" ).arg( mOptsKey ), mOptStackedWidget->currentIndex() ); | ||
| } | ||
| } | ||
|
|
||
| void QgsOptionsDialogBase::initOptionsBase( bool restoreUi ) | ||
| { | ||
| // start with copy of qgsoptionsdialog_template.ui to ensure existence of these objects | ||
| mOptListWidget = findChild<QListWidget*>( "mOptionsListWidget" ); | ||
| mOptStackedWidget = findChild<QStackedWidget*>( "mOptionsStackedWidget" ); | ||
| mOptSplitter = findChild<QSplitter*>( "mOptionsSplitter" ); | ||
| mOptButtonBox = findChild<QDialogButtonBox*>( "buttonBox" ); | ||
|
|
||
| if ( !mOptListWidget || !mOptStackedWidget || !mOptSplitter ) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| if ( mOptButtonBox ) | ||
| { | ||
| // enforce only one connection per signal, in case added in Qt Designer | ||
| disconnect( mOptButtonBox, SIGNAL( accepted() ), this, SLOT( accept() ) ); | ||
| connect( mOptButtonBox, SIGNAL( accepted() ), this, SLOT( accept() ) ); | ||
| disconnect( mOptButtonBox, SIGNAL( rejected() ), this, SLOT( reject() ) ); | ||
| connect( mOptButtonBox, SIGNAL( rejected() ), this, SLOT( reject() ) ); | ||
| } | ||
| connect( mOptSplitter, SIGNAL( splitterMoved( int, int ) ), this, SLOT( updateOptionsListVerticalTabs() ) ); | ||
| connect( mOptStackedWidget, SIGNAL( currentChanged( int ) ), this, SLOT( optionsStackedWidget_CurrentChanged( int ) ) ); | ||
|
|
||
| if ( restoreUi ) | ||
| restoreOptionsBaseUi(); | ||
|
|
||
| mInit = true; | ||
| } | ||
|
|
||
| void QgsOptionsDialogBase::restoreOptionsBaseUi() | ||
| { | ||
| if ( !mInit ) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| QSettings settings; | ||
| restoreGeometry( settings.value( QString( "/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( | ||
| settings.value( QString( "/Windows/%1/splitState" ).arg( mOptsKey ) ).isNull() ? 150 : 16777215 ); | ||
| mOptSplitter->restoreState( settings.value( QString( "/Windows/%1/splitState" ).arg( mOptsKey ) ).toByteArray() ); | ||
| int curIndx = settings.value( QString( "/Windows/%1/tab" ).arg( mOptsKey ), 0 ).toInt(); | ||
| mOptStackedWidget->setCurrentIndex( curIndx ); | ||
| mOptListWidget->setCurrentRow( curIndx ); | ||
|
|
||
| // get rid of annoying outer focus rect on Mac | ||
| mOptListWidget->setAttribute( Qt::WA_MacShowFocusRect, false ); | ||
| } | ||
|
|
||
| void QgsOptionsDialogBase::showEvent( QShowEvent* e ) | ||
| { | ||
| if ( mInit ) | ||
| { | ||
| updateOptionsListVerticalTabs(); | ||
| } | ||
| else | ||
| { | ||
| QTimer::singleShot( 0, this, SLOT( warnAboutMissingObjects() ) ); | ||
| } | ||
|
|
||
| QDialog::showEvent( e ); | ||
| } | ||
|
|
||
| void QgsOptionsDialogBase::paintEvent( QPaintEvent* e ) | ||
| { | ||
| if ( mInit ) | ||
| QTimer::singleShot( 0, this, SLOT( updateOptionsListVerticalTabs() ) ); | ||
|
|
||
| QDialog::paintEvent( e ); | ||
| } | ||
|
|
||
| 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(); | ||
| bool iconOnly = ( splitSizes.at( 0 ) <= snapToIconWidth ); | ||
|
|
||
| int newWidth = mOptListWidget->verticalScrollBar()->isVisible() ? iconWidth + 26 : iconWidth + 12; | ||
| bool diffWidth = mOptListWidget->minimumWidth() != newWidth; | ||
|
|
||
| if ( diffWidth ) | ||
| mOptListWidget->setMinimumWidth( newWidth ); | ||
|
|
||
| if ( iconOnly && ( diffWidth || mOptListWidget->width() != newWidth ) ) | ||
| { | ||
| splitSizes[1] = splitSizes.at( 1 ) - ( splitSizes.at( 0 ) - newWidth ); | ||
| splitSizes[0] = newWidth; | ||
| mOptSplitter->setSizes( splitSizes ); | ||
| } | ||
| if ( mOptListWidget->wordWrap() && iconOnly ) | ||
| mOptListWidget->setWordWrap( false ); | ||
| if ( !mOptListWidget->wordWrap() && !iconOnly ) | ||
| mOptListWidget->setWordWrap( true ); | ||
| } | ||
|
|
||
| void QgsOptionsDialogBase::optionsStackedWidget_CurrentChanged( int indx ) | ||
| { | ||
| mOptListWidget->blockSignals( true ); | ||
| mOptListWidget->setCurrentRow( indx ); | ||
| mOptListWidget->blockSignals( false ); | ||
| } | ||
|
|
||
| void QgsOptionsDialogBase::warnAboutMissingObjects() | ||
| { | ||
| QMessageBox::warning( 0, tr( "Missing objects" ), | ||
| tr( "Base options dialog could not be initialized.\n\n" | ||
| "Missing some of the .ui template objects:\n" ) | ||
| + " mOptionsListWidget,\n mOptionsStackedWidget,\n mOptionsSplitter", | ||
| QMessageBox::Ok, | ||
| QMessageBox::Ok ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| /*************************************************************************** | ||
| qgsoptionsdialogbase.h - base vertical tabs option dialog | ||
| --------------------- | ||
| begin : March 24, 2013 | ||
| copyright : (C) 2013 by Larry Shaffer | ||
| email : larrys at dakcarto dot com | ||
| *************************************************************************** | ||
| * * | ||
| * This program is free software; you can redistribute it and/or modify * | ||
| * it under the terms of the GNU General Public License as published by * | ||
| * the Free Software Foundation; either version 2 of the License, or * | ||
| * (at your option) any later version. * | ||
| * * | ||
| ***************************************************************************/ | ||
|
|
||
| #ifndef QGSOPTIONSDIALOGBASE_H | ||
| #define QGSOPTIONSDIALOGBASE_H | ||
|
|
||
| #include "qgisgui.h" | ||
|
|
||
| #include <QDialog> | ||
|
|
||
| class QDialogButtonBox; | ||
| class QListWidget; | ||
| class QStackedWidget; | ||
| class QSplitter; | ||
|
|
||
| /** \ingroup gui | ||
| * \class QgsOptionsDialogBase | ||
| * A base dialog for options and properties dialogs that offers vertical tabs. | ||
| * It handles saving/restoring of geometry, splitter and current tab states, | ||
| * switching vertical tabs between icon/text to icon-only modes (splitter collapsed to left), | ||
| * and connecting QDialogButtonBox's accepted/rejected signals to dialog's accept/reject slots | ||
| * | ||
| * To use: | ||
| * 1) Start with copy of qgsoptionsdialog_template.ui and build options/properties dialog. | ||
| * 2) In source file for dialog, inherit this class instead of QDialog, then in constructor: | ||
| * ... | ||
| * setupUi( this ); // set up .ui file objects | ||
| * initOptionsBase( false ); // set up this class to use .ui objects, optionally restoring base ui | ||
| * ... | ||
| * restoreOptionsBaseUi(); // restore the base ui with initOptionsBase or use this later on | ||
| * @note added in 1.9 | ||
| */ | ||
|
|
||
| class GUI_EXPORT QgsOptionsDialogBase : public QDialog | ||
| { | ||
| Q_OBJECT | ||
|
|
||
| public: | ||
| /** Constructor | ||
| * @param settingsKey QSettings subgroup key for saving/restore ui states, e.g. "ProjectProperties". | ||
| */ | ||
| QgsOptionsDialogBase( QString settingsKey, QWidget* parent = 0, Qt::WFlags fl = 0 ); | ||
| ~QgsOptionsDialogBase(); | ||
|
|
||
| /** Set up the base ui connections for vertical tabs. | ||
| * @param restoreUi Whether to restore the base ui at this time. | ||
| */ | ||
| void initOptionsBase( bool restoreUi = true ); | ||
|
|
||
| /** Restore the base ui. | ||
| * Sometimes useful to do at end of subclass's constructor. | ||
| */ | ||
| void restoreOptionsBaseUi(); | ||
|
|
||
| protected slots: | ||
| void updateOptionsListVerticalTabs(); | ||
| void optionsStackedWidget_CurrentChanged( int indx ); | ||
| void warnAboutMissingObjects(); | ||
|
|
||
| protected: | ||
| void showEvent( QShowEvent* e ); | ||
| void paintEvent( QPaintEvent* e ); | ||
|
|
||
| QString mOptsKey; | ||
| bool mInit; | ||
| QListWidget* mOptListWidget; | ||
| QStackedWidget* mOptStackedWidget; | ||
| QSplitter* mOptSplitter; | ||
| QDialogButtonBox* mOptButtonBox; | ||
| }; | ||
|
|
||
| #endif // QGSOPTIONSDIALOGBASE_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,234 @@ | ||
| <?xml version="1.0" encoding="UTF-8"?> | ||
| <ui version="4.0"> | ||
| <class>QgsOpstionDialogTemplate</class> | ||
| <widget class="QDialog" name="QgsOpstionDialogTemplate"> | ||
| <property name="geometry"> | ||
| <rect> | ||
| <x>0</x> | ||
| <y>0</y> | ||
| <width>827</width> | ||
| <height>759</height> | ||
| </rect> | ||
| </property> | ||
| <property name="minimumSize"> | ||
| <size> | ||
| <width>700</width> | ||
| <height>0</height> | ||
| </size> | ||
| </property> | ||
| <property name="windowTitle"> | ||
| <string>Options Dialog Template</string> | ||
| </property> | ||
| <layout class="QVBoxLayout" name="verticalLayout"> | ||
| <item> | ||
| <widget class="QSplitter" name="mOptionsSplitter"> | ||
| <property name="orientation"> | ||
| <enum>Qt::Horizontal</enum> | ||
| </property> | ||
| <property name="childrenCollapsible"> | ||
| <bool>false</bool> | ||
| </property> | ||
| <widget class="QFrame" name="mOptionsListFrame"> | ||
| <property name="minimumSize"> | ||
| <size> | ||
| <width>0</width> | ||
| <height>0</height> | ||
| </size> | ||
| </property> | ||
| <property name="frameShape"> | ||
| <enum>QFrame::NoFrame</enum> | ||
| </property> | ||
| <property name="frameShadow"> | ||
| <enum>QFrame::Raised</enum> | ||
| </property> | ||
| <layout class="QVBoxLayout" name="verticalLayout_2"> | ||
| <property name="margin"> | ||
| <number>0</number> | ||
| </property> | ||
| <item> | ||
| <widget class="QListWidget" name="mOptionsListWidget"> | ||
| <property name="minimumSize"> | ||
| <size> | ||
| <width>58</width> | ||
| <height>0</height> | ||
| </size> | ||
| </property> | ||
| <property name="maximumSize"> | ||
| <size> | ||
| <width>150</width> | ||
| <height>16777215</height> | ||
| </size> | ||
| </property> | ||
| <property name="horizontalScrollBarPolicy"> | ||
| <enum>Qt::ScrollBarAlwaysOff</enum> | ||
| </property> | ||
| <property name="editTriggers"> | ||
| <set>QAbstractItemView::NoEditTriggers</set> | ||
| </property> | ||
| <property name="iconSize"> | ||
| <size> | ||
| <width>32</width> | ||
| <height>32</height> | ||
| </size> | ||
| </property> | ||
| <property name="textElideMode"> | ||
| <enum>Qt::ElideNone</enum> | ||
| </property> | ||
| <property name="resizeMode"> | ||
| <enum>QListView::Adjust</enum> | ||
| </property> | ||
| <property name="wordWrap"> | ||
| <bool>true</bool> | ||
| </property> | ||
| </widget> | ||
| </item> | ||
| </layout> | ||
| </widget> | ||
| <widget class="QFrame" name="mOptionsFrame"> | ||
| <property name="sizePolicy"> | ||
| <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> | ||
| <horstretch>1</horstretch> | ||
| <verstretch>0</verstretch> | ||
| </sizepolicy> | ||
| </property> | ||
| <property name="frameShape"> | ||
| <enum>QFrame::NoFrame</enum> | ||
| </property> | ||
| <property name="frameShadow"> | ||
| <enum>QFrame::Raised</enum> | ||
| </property> | ||
| <layout class="QVBoxLayout" name="verticalLayout_3"> | ||
| <property name="margin"> | ||
| <number>0</number> | ||
| </property> | ||
| <item> | ||
| <widget class="QStackedWidget" name="mOptionsStackedWidget"> | ||
| <property name="sizePolicy"> | ||
| <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> | ||
| <horstretch>0</horstretch> | ||
| <verstretch>0</verstretch> | ||
| </sizepolicy> | ||
| </property> | ||
| <property name="currentIndex"> | ||
| <number>0</number> | ||
| </property> | ||
| <widget class="QWidget" name="mOptsPage_01"> | ||
| <layout class="QVBoxLayout" name="verticalLayout_14"> | ||
| <property name="margin"> | ||
| <number>0</number> | ||
| </property> | ||
| <item> | ||
| <widget class="QLabel" name="label"> | ||
| <property name="styleSheet"> | ||
| <string notr="true">font-weight:bold;</string> | ||
| </property> | ||
| <property name="text"> | ||
| <string>Section</string> | ||
| </property> | ||
| </widget> | ||
| </item> | ||
| <item> | ||
| <widget class="QScrollArea" name="scrollArea"> | ||
| <property name="frameShape"> | ||
| <enum>QFrame::NoFrame</enum> | ||
| </property> | ||
| <property name="widgetResizable"> | ||
| <bool>true</bool> | ||
| </property> | ||
| <widget class="QWidget" name="scrollAreaWidgetContents"> | ||
| <property name="geometry"> | ||
| <rect> | ||
| <x>0</x> | ||
| <y>0</y> | ||
| <width>646</width> | ||
| <height>669</height> | ||
| </rect> | ||
| </property> | ||
| <layout class="QVBoxLayout" name="verticalLayout_13"> | ||
| <item> | ||
| <widget class="QGroupBox" name="groupBox"> | ||
| <property name="title"> | ||
| <string>GroupBox</string> | ||
| </property> | ||
| </widget> | ||
| </item> | ||
| <item> | ||
| <spacer name="verticalSpacer"> | ||
| <property name="orientation"> | ||
| <enum>Qt::Vertical</enum> | ||
| </property> | ||
| <property name="sizeHint" stdset="0"> | ||
| <size> | ||
| <width>20</width> | ||
| <height>40</height> | ||
| </size> | ||
| </property> | ||
| </spacer> | ||
| </item> | ||
| </layout> | ||
| </widget> | ||
| </widget> | ||
| </item> | ||
| </layout> | ||
| </widget> | ||
| </widget> | ||
| </item> | ||
| </layout> | ||
| </widget> | ||
| </widget> | ||
| </item> | ||
| <item> | ||
| <widget class="QFrame" name="mButtonBoxFrame"> | ||
| <property name="sizePolicy"> | ||
| <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> | ||
| <horstretch>0</horstretch> | ||
| <verstretch>0</verstretch> | ||
| </sizepolicy> | ||
| </property> | ||
| <property name="frameShape"> | ||
| <enum>QFrame::NoFrame</enum> | ||
| </property> | ||
| <property name="frameShadow"> | ||
| <enum>QFrame::Raised</enum> | ||
| </property> | ||
| <layout class="QHBoxLayout" name="horizontalLayout"> | ||
| <property name="margin"> | ||
| <number>0</number> | ||
| </property> | ||
| <item> | ||
| <widget class="QDialogButtonBox" name="buttonBox"> | ||
| <property name="orientation"> | ||
| <enum>Qt::Horizontal</enum> | ||
| </property> | ||
| <property name="standardButtons"> | ||
| <set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Help|QDialogButtonBox::Ok</set> | ||
| </property> | ||
| </widget> | ||
| </item> | ||
| </layout> | ||
| </widget> | ||
| </item> | ||
| </layout> | ||
| </widget> | ||
| <resources> | ||
| <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>86</x> | ||
| <y>325</y> | ||
| </hint> | ||
| <hint type="destinationlabel"> | ||
| <x>794</x> | ||
| <y>14</y> | ||
| </hint> | ||
| </hints> | ||
| </connection> | ||
| </connections> | ||
| </ui> |