QGIS API Documentation  2.2.0-Valmiera
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgsoptionsdialogbase.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsoptionsdialogbase.cpp - base vertical tabs option dialog
3 
4  ---------------------
5  begin : March 24, 2013
6  copyright : (C) 2013 by Larry Shaffer
7  email : larrys at dakcarto dot com
8  ***************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  ***************************************************************************/
16 
17 #include "qgsoptionsdialogbase.h"
18 
19 #include <QDialog>
20 #include <QDialogButtonBox>
21 #include <QLayout>
22 #include <QListWidget>
23 #include <QMessageBox>
24 #include <QScrollBar>
25 #include <QSettings>
26 #include <QStackedWidget>
27 #include <QSplitter>
28 #include <QTimer>
29 
30 
31 QgsOptionsDialogBase::QgsOptionsDialogBase( QString settingsKey, QWidget* parent, Qt::WFlags fl )
32  : QDialog( parent, fl )
33  , mOptsKey( settingsKey )
34  , mInit( false )
35  , mDialogTitle( "" )
36 {
37 }
38 
40 {
41  if ( mInit )
42  {
43  QSettings settings;
44  settings.setValue( QString( "/Windows/%1/geometry" ).arg( mOptsKey ), saveGeometry() );
45  settings.setValue( QString( "/Windows/%1/splitState" ).arg( mOptsKey ), mOptSplitter->saveState() );
46  settings.setValue( QString( "/Windows/%1/tab" ).arg( mOptsKey ), mOptStackedWidget->currentIndex() );
47  }
48 }
49 
50 void QgsOptionsDialogBase::initOptionsBase( bool restoreUi, QString title )
51 {
52  // save dialog title so it can be used to be concatenated
53  // with category title in icon-only mode
54  if ( title.isEmpty() )
55  mDialogTitle = windowTitle();
56  else
57  mDialogTitle = title;
58 
59  // don't add to dialog margins
60  // redefine now, or those in inherited .ui file will be added
61  if ( layout() )
62  {
63  layout()->setContentsMargins( 0, 0, 0, 0 ); // Qt default spacing
64  }
65 
66  // start with copy of qgsoptionsdialog_template.ui to ensure existence of these objects
67  mOptListWidget = findChild<QListWidget*>( "mOptionsListWidget" );
68  QFrame* optionsFrame = findChild<QFrame*>( "mOptionsFrame" );
69  mOptStackedWidget = findChild<QStackedWidget*>( "mOptionsStackedWidget" );
70  mOptSplitter = findChild<QSplitter*>( "mOptionsSplitter" );
71  mOptButtonBox = findChild<QDialogButtonBox*>( "buttonBox" );
72  QFrame* buttonBoxFrame = findChild<QFrame*>( "mButtonBoxFrame" );
73 
74  if ( !mOptListWidget || !mOptStackedWidget || !mOptSplitter || !optionsFrame )
75  {
76  return;
77  }
78 
79  QSettings settings;
80  int size = settings.value( "/IconSize", 24 ).toInt();
81  // buffer size to match displayed icon size in toolbars, and expected geometry restore
82  // newWidth (above) may need adjusted if you adjust iconBuffer here
83  int iconBuffer = 4;
84  mOptListWidget->setIconSize( QSize( size + iconBuffer, size + iconBuffer ) );
85  mOptListWidget->setFrameStyle( QFrame::NoFrame );
86 
87  optionsFrame->layout()->setContentsMargins( 0, 3, 3, 3 );
88  QVBoxLayout* layout = static_cast<QVBoxLayout*>( optionsFrame->layout() );
89 
90  if ( buttonBoxFrame )
91  {
92  buttonBoxFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
93  layout->insertWidget( layout->count() + 1, buttonBoxFrame );
94  }
95  else
96  {
97  layout->insertWidget( layout->count() + 1, mOptButtonBox );
98  }
99 
100  if ( mOptButtonBox )
101  {
102  // enforce only one connection per signal, in case added in Qt Designer
103  disconnect( mOptButtonBox, SIGNAL( accepted() ), this, SLOT( accept() ) );
104  connect( mOptButtonBox, SIGNAL( accepted() ), this, SLOT( accept() ) );
105  disconnect( mOptButtonBox, SIGNAL( rejected() ), this, SLOT( reject() ) );
106  connect( mOptButtonBox, SIGNAL( rejected() ), this, SLOT( reject() ) );
107  }
108  connect( mOptSplitter, SIGNAL( splitterMoved( int, int ) ), this, SLOT( updateOptionsListVerticalTabs() ) );
109  connect( mOptStackedWidget, SIGNAL( currentChanged( int ) ), this, SLOT( optionsStackedWidget_CurrentChanged( int ) ) );
110  connect( mOptStackedWidget, SIGNAL( widgetRemoved( int ) ), this, SLOT( optionsStackedWidget_WidgetRemoved( int ) ) );
111 
112  mInit = true;
113 
114  if ( restoreUi )
116 }
117 
119 {
120  if ( !mInit )
121  {
122  return;
123  }
124 
125  if ( !title.isEmpty() )
126  {
127  mDialogTitle = title;
129  }
130 
131  // re-save original dialog title in case it was changed after dialog initialization
132  mDialogTitle = windowTitle();
133 
134  QSettings settings;
135  restoreGeometry( settings.value( QString( "/Windows/%1/geometry" ).arg( mOptsKey ) ).toByteArray() );
136  // mOptListWidget width is fixed to take up less space in QtDesigner
137  // revert it now unless the splitter's state hasn't been saved yet
138  mOptListWidget->setMaximumWidth(
139  settings.value( QString( "/Windows/%1/splitState" ).arg( mOptsKey ) ).isNull() ? 150 : 16777215 );
140  mOptSplitter->restoreState( settings.value( QString( "/Windows/%1/splitState" ).arg( mOptsKey ) ).toByteArray() );
141  int curIndx = settings.value( QString( "/Windows/%1/tab" ).arg( mOptsKey ), 0 ).toInt();
142 
143  // if the last used tab is out of range or not enabled display the first enabled one
144  if ( mOptStackedWidget->count() < ( curIndx + 1 )
145  || !mOptStackedWidget->widget( curIndx )->isEnabled() )
146  {
147  curIndx = 0;
148  for ( int i = 0; i < mOptStackedWidget->count(); i++ )
149  {
150  if ( mOptStackedWidget->widget( i )->isEnabled() )
151  {
152  curIndx = i;
153  break;
154  }
155  }
156  }
157 
158  if ( mOptStackedWidget->count() != 0 && mOptListWidget->count() != 0 )
159  {
160  mOptStackedWidget->setCurrentIndex( curIndx );
161  mOptListWidget->setCurrentRow( curIndx );
162  }
163 
164  // get rid of annoying outer focus rect on Mac
165  mOptListWidget->setAttribute( Qt::WA_MacShowFocusRect, false );
166 }
167 
168 void QgsOptionsDialogBase::showEvent( QShowEvent* e )
169 {
170  if ( mInit )
171  {
174  }
175  else
176  {
177  QTimer::singleShot( 0, this, SLOT( warnAboutMissingObjects() ) );
178  }
179 
180  QDialog::showEvent( e );
181 }
182 
183 void QgsOptionsDialogBase::paintEvent( QPaintEvent* e )
184 {
185  if ( mInit )
186  QTimer::singleShot( 0, this, SLOT( updateOptionsListVerticalTabs() ) );
187 
188  QDialog::paintEvent( e );
189 }
190 
192 {
193  QListWidgetItem *curitem = mOptListWidget->currentItem();
194  if ( curitem )
195  {
196  setWindowTitle( QString( "%1 | %2" ).arg( mDialogTitle ).arg( curitem->text() ) );
197  }
198  else
199  {
200  setWindowTitle( mDialogTitle );
201  }
202 }
203 
205 {
206  if ( !mInit )
207  return;
208 
209  if ( mOptListWidget->maximumWidth() != 16777215 )
210  mOptListWidget->setMaximumWidth( 16777215 );
211  // auto-resize splitter for vert scrollbar without covering icons in icon-only mode
212  // TODO: mOptListWidget has fixed 32px wide icons for now, allow user-defined
213  // Note: called on splitter resize and dialog paint event, so only update when necessary
214  int iconWidth = mOptListWidget->iconSize().width();
215  int snapToIconWidth = iconWidth + 32;
216 
217  QList<int> splitSizes = mOptSplitter->sizes();
218  mIconOnly = ( splitSizes.at( 0 ) <= snapToIconWidth );
219 
220  // iconBuffer (above) may need adjusted if you adjust iconWidth here
221  int newWidth = mOptListWidget->verticalScrollBar()->isVisible() ? iconWidth + 22 : iconWidth + 9;
222  bool diffWidth = mOptListWidget->minimumWidth() != newWidth;
223 
224  if ( diffWidth )
225  mOptListWidget->setMinimumWidth( newWidth );
226 
227  if ( mIconOnly && ( diffWidth || mOptListWidget->width() != newWidth ) )
228  {
229  splitSizes[1] = splitSizes.at( 1 ) - ( splitSizes.at( 0 ) - newWidth );
230  splitSizes[0] = newWidth;
231  mOptSplitter->setSizes( splitSizes );
232  }
233 
234  if ( mOptListWidget->wordWrap() && mIconOnly )
235  mOptListWidget->setWordWrap( false );
236  if ( !mOptListWidget->wordWrap() && !mIconOnly )
237  mOptListWidget->setWordWrap( true );
238 }
239 
241 {
242  mOptListWidget->blockSignals( true );
243  mOptListWidget->setCurrentRow( indx );
244  mOptListWidget->blockSignals( false );
245 
247 }
248 
250 {
251  // will need to take item first, if widgets are set for item in future
252  delete mOptListWidget->item( indx );
253 }
254 
256 {
257  QMessageBox::warning( 0, tr( "Missing objects" ),
258  tr( "Base options dialog could not be initialized.\n\n"
259  "Missing some of the .ui template objects:\n" )
260  + " mOptionsListWidget,\n mOptionsStackedWidget,\n mOptionsSplitter",
261  QMessageBox::Ok,
262  QMessageBox::Ok );
263 }