PageRenderTime 45ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/src/gui/attributetable/qgsfieldconditionalformatwidget.cpp

http://github.com/qgis/Quantum-GIS
C++ | 422 lines | 342 code | 58 blank | 22 comment | 26 complexity | 9aba6d7c32ae696d80a7eafdd40574b5 MD5 | raw file
Possible License(s): LGPL-2.0, GPL-3.0, GPL-2.0, CC-BY-SA-3.0, MIT, 0BSD, BSD-3-Clause
  1. /***************************************************************************
  2. qgsfieldconditionalformatwidget.cpp
  3. ---------------------
  4. begin : August 2015
  5. copyright : (C) 2015 by Nathan Woodrow
  6. email : woodrow dot nathan at gmail dot com
  7. ***************************************************************************
  8. * *
  9. * This program is free software; you can redistribute it and/or modify *
  10. * it under the terms of the GNU General Public License as published by *
  11. * the Free Software Foundation; either version 2 of the License, or *
  12. * (at your option) any later version. *
  13. * *
  14. ***************************************************************************/
  15. #include "qgsfieldconditionalformatwidget.h"
  16. #include "qgsexpressionbuilderdialog.h"
  17. #include "qgssymbol.h"
  18. #include "qgssymbolselectordialog.h"
  19. #include "qgssymbollayerutils.h"
  20. #include "qgsstyle.h"
  21. #include "qgsvectorlayer.h"
  22. #include "qgsexpressioncontextutils.h"
  23. #include "qgsguiutils.h"
  24. //
  25. // QgsFieldConditionalFormatWidget
  26. //
  27. QgsFieldConditionalFormatWidget::QgsFieldConditionalFormatWidget( QWidget *parent )
  28. : QgsPanelWidget( parent )
  29. {
  30. setupUi( this );
  31. setPanelTitle( tr( "Conditional Styles" ) );
  32. connect( mFieldCombo, &QgsFieldComboBox::fieldChanged, this, &QgsFieldConditionalFormatWidget::fieldChanged );
  33. connect( fieldRadio, &QAbstractButton::clicked, this, &QgsFieldConditionalFormatWidget::reloadStyles );
  34. connect( rowRadio, &QAbstractButton::clicked, this, &QgsFieldConditionalFormatWidget::reloadStyles );
  35. connect( mNewButton, &QAbstractButton::clicked, this, &QgsFieldConditionalFormatWidget::addNewRule );
  36. connect( listView, &QAbstractItemView::clicked, this, &QgsFieldConditionalFormatWidget::ruleClicked );
  37. mModel = new QStandardItemModel( listView );
  38. listView->setModel( mModel );
  39. connect( fieldRadio, &QRadioButton::toggled, mFieldCombo, &QWidget::setEnabled );
  40. mPresets = defaultPresets();
  41. }
  42. void QgsFieldConditionalFormatWidget::setLayer( QgsVectorLayer *layer )
  43. {
  44. mLayer = layer;
  45. mFieldCombo->setLayer( layer );
  46. mFieldCombo->setCurrentIndex( 0 );
  47. fieldChanged( mFieldCombo->currentField() );
  48. }
  49. void QgsFieldConditionalFormatWidget::ruleClicked( const QModelIndex &index )
  50. {
  51. QList<QgsConditionalStyle> styles = getStyles();
  52. QgsConditionalStyle style = styles.at( index.row() );
  53. editStyle( index.row(), style );
  54. }
  55. void QgsFieldConditionalFormatWidget::editStyle( int editIndex, const QgsConditionalStyle &style )
  56. {
  57. mEditIndex = editIndex;
  58. mEditing = editIndex >= 0;
  59. mPanelHandled = false;
  60. QgsEditConditionalFormatRuleWidget *ruleWidget = new QgsEditConditionalFormatRuleWidget();
  61. ruleWidget->setLayer( mLayer );
  62. ruleWidget->setPresets( mPresets );
  63. ruleWidget->loadStyle( style );
  64. ruleWidget->setDockMode( true );
  65. if ( fieldRadio->isChecked() && style.rule().isEmpty() )
  66. {
  67. ruleWidget->setRule( QStringLiteral( "@value " ) );
  68. }
  69. connect( ruleWidget, &QgsEditConditionalFormatRuleWidget::panelAccepted, this, [ = ]
  70. {
  71. if ( mPanelHandled )
  72. {
  73. // already handled the result of the panel, and the panel is being dismissed as a result
  74. // of an already dealt with action
  75. return;
  76. }
  77. QList<QgsConditionalStyle> styles = getStyles();
  78. if ( mEditing )
  79. {
  80. styles.replace( mEditIndex, ruleWidget->currentStyle() );
  81. }
  82. else
  83. {
  84. styles.append( ruleWidget->currentStyle() );
  85. }
  86. QString fieldName;
  87. if ( fieldRadio->isChecked() )
  88. {
  89. fieldName = mFieldCombo->currentField();
  90. mLayer->conditionalStyles()->setFieldStyles( fieldName, styles );
  91. }
  92. if ( rowRadio->isChecked() )
  93. {
  94. mLayer->conditionalStyles()->setRowStyles( styles );
  95. }
  96. reloadStyles();
  97. emit rulesUpdated( fieldName );
  98. } );
  99. connect( ruleWidget, &QgsEditConditionalFormatRuleWidget::ruleSaved, this, [ = ]
  100. {
  101. ruleWidget->acceptPanel();
  102. } );
  103. connect( ruleWidget, &QgsEditConditionalFormatRuleWidget::canceled, this, [ = ]
  104. {
  105. mPanelHandled = true;
  106. ruleWidget->acceptPanel();
  107. } );
  108. connect( ruleWidget, &QgsEditConditionalFormatRuleWidget::ruleDeleted, this, [ = ]
  109. {
  110. deleteCurrentRule();
  111. mPanelHandled = true;
  112. ruleWidget->acceptPanel();
  113. } );
  114. showPanel( ruleWidget );
  115. }
  116. void QgsFieldConditionalFormatWidget::loadStyle( const QgsConditionalStyle & )
  117. {
  118. }
  119. QList<QgsConditionalStyle> QgsFieldConditionalFormatWidget::getStyles()
  120. {
  121. QList<QgsConditionalStyle> styles;
  122. if ( fieldRadio->isChecked() )
  123. {
  124. styles = mLayer->conditionalStyles()->fieldStyles( mFieldCombo->currentField() );
  125. }
  126. if ( rowRadio->isChecked() )
  127. {
  128. styles = mLayer->conditionalStyles()->rowStyles();
  129. }
  130. return styles;
  131. }
  132. void QgsFieldConditionalFormatWidget::addNewRule()
  133. {
  134. editStyle( -1, QgsConditionalStyle() );
  135. }
  136. void QgsFieldConditionalFormatWidget::reset()
  137. {
  138. }
  139. void QgsFieldConditionalFormatWidget::setPresets( const QList<QgsConditionalStyle> &styles )
  140. {
  141. mPresets = styles;
  142. }
  143. QList<QgsConditionalStyle> QgsFieldConditionalFormatWidget::defaultPresets()
  144. {
  145. QList<QgsConditionalStyle> styles;
  146. QgsConditionalStyle style = QgsConditionalStyle();
  147. style.setBackgroundColor( QColor( 154, 216, 113 ) );
  148. styles.append( style );
  149. style = QgsConditionalStyle();
  150. style.setBackgroundColor( QColor( 251, 193, 78 ) );
  151. styles.append( style );
  152. style = QgsConditionalStyle();
  153. style.setBackgroundColor( QColor( 251, 154, 153 ) );
  154. styles.append( style );
  155. style = QgsConditionalStyle();
  156. style.setTextColor( QColor( 154, 216, 113 ) );
  157. styles.append( style );
  158. style = QgsConditionalStyle();
  159. style.setTextColor( QColor( 251, 193, 78 ) );
  160. styles.append( style );
  161. style = QgsConditionalStyle();
  162. style.setTextColor( QColor( 251, 154, 153 ) );
  163. styles.append( style );
  164. return styles;
  165. }
  166. void QgsFieldConditionalFormatWidget::reloadStyles()
  167. {
  168. mModel->clear();
  169. const auto constGetStyles = getStyles();
  170. #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
  171. const QSize size( Qgis::UI_SCALE_FACTOR * fontMetrics().width( 'X' ) * 10, Qgis::UI_SCALE_FACTOR * fontMetrics().height() * 2 );
  172. #else
  173. const QSize size( Qgis::UI_SCALE_FACTOR * fontMetrics().horizontalAdvance( 'X' ) * 10, Qgis::UI_SCALE_FACTOR * fontMetrics().height() * 2 );
  174. #endif
  175. listView->setIconSize( size );
  176. for ( const QgsConditionalStyle &style : constGetStyles )
  177. {
  178. QStandardItem *item = new QStandardItem( style.displayText() );
  179. item->setIcon( QIcon( style.renderPreview( size ) ) );
  180. mModel->appendRow( item );
  181. }
  182. }
  183. void QgsFieldConditionalFormatWidget::fieldChanged( const QString &fieldName )
  184. {
  185. Q_UNUSED( fieldName )
  186. reloadStyles();
  187. }
  188. void QgsFieldConditionalFormatWidget::deleteCurrentRule()
  189. {
  190. if ( !mEditing )
  191. return;
  192. QList<QgsConditionalStyle> styles = getStyles();
  193. styles.removeAt( mEditIndex );
  194. QString fieldName;
  195. if ( fieldRadio->isChecked() )
  196. {
  197. fieldName = mFieldCombo->currentField();
  198. mLayer->conditionalStyles()->setFieldStyles( fieldName, styles );
  199. }
  200. if ( rowRadio->isChecked() )
  201. {
  202. mLayer->conditionalStyles()->setRowStyles( styles );
  203. }
  204. reloadStyles();
  205. emit rulesUpdated( fieldName );
  206. }
  207. void QgsFieldConditionalFormatWidget::viewRules()
  208. {
  209. }
  210. //
  211. // QgsEditConditionalFormatRuleWidget
  212. //
  213. QgsEditConditionalFormatRuleWidget::QgsEditConditionalFormatRuleWidget( QWidget *parent )
  214. : QgsPanelWidget( parent )
  215. {
  216. setupUi( this );
  217. setPanelTitle( tr( "Edit Rule" ) );
  218. btnBackgroundColor->setColor( QColor() );
  219. btnTextColor->setColor( QColor() );
  220. checkIcon->setChecked( false );
  221. btnChangeIcon->setIcon( QIcon() );
  222. btnBackgroundColor->setToNoColor();
  223. btnTextColor->setToNoColor();
  224. mFontBoldBtn->setChecked( false );
  225. mFontItalicBtn->setChecked( false );
  226. mFontStrikethroughBtn->setChecked( false );
  227. mFontUnderlineBtn->setChecked( false );
  228. const int buttonSize = QgsGuiUtils::scaleIconSize( 24 );
  229. mFontUnderlineBtn->setMinimumSize( buttonSize, buttonSize );
  230. mFontUnderlineBtn->setMaximumSize( buttonSize, buttonSize );
  231. mFontStrikethroughBtn->setMinimumSize( buttonSize, buttonSize );
  232. mFontStrikethroughBtn->setMaximumSize( buttonSize, buttonSize );
  233. mFontBoldBtn->setMinimumSize( buttonSize, buttonSize );
  234. mFontBoldBtn->setMaximumSize( buttonSize, buttonSize );
  235. mFontItalicBtn->setMinimumSize( buttonSize, buttonSize );
  236. mFontItalicBtn->setMaximumSize( buttonSize, buttonSize );
  237. connect( mSaveRule, &QAbstractButton::clicked, this, &QgsEditConditionalFormatRuleWidget::ruleSaved );
  238. connect( mCancelButton, &QAbstractButton::clicked, this, &QgsEditConditionalFormatRuleWidget::canceled );
  239. connect( mDeleteButton, &QAbstractButton::clicked, this, &QgsEditConditionalFormatRuleWidget::ruleDeleted );
  240. connect( btnBuildExpression, &QAbstractButton::clicked, this, &QgsEditConditionalFormatRuleWidget::setExpression );
  241. connect( mPresetsList, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsEditConditionalFormatRuleWidget::presetSet );
  242. btnBackgroundColor->setAllowOpacity( true );
  243. btnBackgroundColor->setShowNoColor( true );
  244. btnTextColor->setAllowOpacity( true );
  245. btnTextColor->setShowNoColor( true );
  246. mPresetsModel = new QStandardItemModel( mPresetsList );
  247. mPresetsList->setModel( mPresetsModel );
  248. btnChangeIcon->setSymbolType( QgsSymbol::Marker );
  249. btnChangeIcon->setSymbol( QgsSymbol::defaultSymbol( QgsWkbTypes::PointGeometry ) );
  250. connect( checkIcon, &QCheckBox::toggled, btnChangeIcon, &QWidget::setEnabled );
  251. }
  252. void QgsEditConditionalFormatRuleWidget::setLayer( QgsVectorLayer *layer )
  253. {
  254. mLayer = layer;
  255. }
  256. void QgsEditConditionalFormatRuleWidget::loadStyle( const QgsConditionalStyle &style )
  257. {
  258. mRuleEdit->setText( style.rule() );
  259. mNameEdit->setText( style.name() );
  260. setFormattingFromStyle( style );
  261. }
  262. QgsConditionalStyle QgsEditConditionalFormatRuleWidget::currentStyle() const
  263. {
  264. QgsConditionalStyle style;
  265. style.setRule( mRuleEdit->text() );
  266. style.setName( mNameEdit->text() );
  267. QColor backColor = btnBackgroundColor->color();
  268. QColor fontColor = btnTextColor->color();
  269. QFont font = mFontFamilyCmbBx->currentFont();
  270. font.setBold( mFontBoldBtn->isChecked() );
  271. font.setItalic( mFontItalicBtn->isChecked() );
  272. font.setStrikeOut( mFontStrikethroughBtn->isChecked() );
  273. font.setUnderline( mFontUnderlineBtn->isChecked() );
  274. style.setFont( font );
  275. style.setBackgroundColor( backColor );
  276. style.setTextColor( fontColor );
  277. if ( checkIcon->isChecked() )
  278. {
  279. style.setSymbol( btnChangeIcon->clonedSymbol< QgsMarkerSymbol >() );
  280. }
  281. else
  282. {
  283. style.setSymbol( nullptr );
  284. }
  285. return style;
  286. }
  287. void QgsEditConditionalFormatRuleWidget::setExpression()
  288. {
  289. QgsExpressionContext context( QgsExpressionContextUtils::globalProjectLayerScopes( mLayer ) );
  290. context.lastScope()->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "value" ), 0, true ) );
  291. context.setHighlightedVariables( QStringList() << QStringLiteral( "value" ) );
  292. QgsExpressionBuilderDialog dlg( mLayer, mRuleEdit->text(), this, QStringLiteral( "generic" ), context );
  293. dlg.setWindowTitle( tr( "Conditional Style Rule Expression" ) );
  294. if ( dlg.exec() )
  295. {
  296. QString expression = dlg.expressionBuilder()->expressionText();
  297. mRuleEdit->setText( expression );
  298. }
  299. }
  300. void QgsEditConditionalFormatRuleWidget::presetSet( int index )
  301. {
  302. if ( index == -1 || mPresets.isEmpty() )
  303. return;
  304. const int styleIndex = mPresetsList->currentData( Qt::UserRole + 1 ).toInt();
  305. QgsConditionalStyle style = mPresets.at( styleIndex );
  306. setFormattingFromStyle( style );
  307. }
  308. void QgsEditConditionalFormatRuleWidget::setFormattingFromStyle( const QgsConditionalStyle &style )
  309. {
  310. btnBackgroundColor->setColor( style.backgroundColor() );
  311. btnTextColor->setColor( style.textColor() );
  312. if ( style.symbol() )
  313. {
  314. btnChangeIcon->setSymbol( style.symbol()->clone() );
  315. checkIcon->setChecked( true );
  316. }
  317. else
  318. {
  319. checkIcon->setChecked( false );
  320. }
  321. QFont font = style.font();
  322. mFontBoldBtn->setChecked( font.bold() );
  323. mFontItalicBtn->setChecked( font.italic() );
  324. mFontStrikethroughBtn->setChecked( font.strikeOut() );
  325. mFontUnderlineBtn->setChecked( font.underline() );
  326. mFontFamilyCmbBx->setCurrentFont( font );
  327. }
  328. void QgsEditConditionalFormatRuleWidget::setPresets( const QList<QgsConditionalStyle> &styles )
  329. {
  330. mPresets.clear();
  331. mPresetsModel->clear();
  332. QStandardItem *item = new QStandardItem( QString() );
  333. mPresetsModel->appendRow( item );
  334. int i = 0;
  335. for ( const QgsConditionalStyle &style : styles )
  336. {
  337. if ( style.isValid() )
  338. {
  339. QStandardItem *item = new QStandardItem( QStringLiteral( "abc - 123" ) );
  340. if ( style.validBackgroundColor() )
  341. item->setBackground( style.backgroundColor() );
  342. if ( style.validTextColor() )
  343. item->setForeground( style.textColor() );
  344. if ( style.symbol() )
  345. item->setIcon( style.icon() );
  346. item->setFont( style.font() );
  347. item->setData( i, Qt::UserRole + 1 );
  348. mPresetsModel->appendRow( item );
  349. mPresets.append( style );
  350. i++;
  351. }
  352. }
  353. mPresetsList->setCurrentIndex( 0 );
  354. }
  355. void QgsEditConditionalFormatRuleWidget::setRule( const QString &rule )
  356. {
  357. mRuleEdit->setText( rule );
  358. }
  359. bool QgsEditConditionalFormatRuleWidget::isCustomSet()
  360. {
  361. return ( btnBackgroundColor->color().isValid()
  362. || btnTextColor->color().isValid()
  363. || mFontButtons->checkedId() != -1 );
  364. }