1 /***************************************************************************
2                          qgslayoutmarkerwidget.cpp
3                          --------------------------
4     begin                : April 2020
5     copyright            : (C) 2020 by Nyall Dawson
6     email                : nyall dot dawson at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 #include "qgslayoutmarkerwidget.h"
19 #include "qgsstyle.h"
20 #include "qgslayoutitemmarker.h"
21 #include "qgslayout.h"
22 #include "qgslayoutundostack.h"
23 #include "qgsvectorlayer.h"
24 #include "qgslayoutitemmap.h"
25 #include "qgsmarkersymbol.h"
26 
QgsLayoutMarkerWidget(QgsLayoutItemMarker * marker)27 QgsLayoutMarkerWidget::QgsLayoutMarkerWidget( QgsLayoutItemMarker *marker )
28   : QgsLayoutItemBaseWidget( nullptr, marker )
29   , mMarker( marker )
30 {
31   Q_ASSERT( mMarker );
32 
33   setupUi( this );
34   setPanelTitle( tr( "Marker Properties" ) );
35 
36   //add widget for general composer item properties
37   mItemPropertiesWidget = new QgsLayoutItemPropertiesWidget( this, marker );
38   mItemPropertiesWidget->showFrameGroup( false );
39   mainLayout->addWidget( mItemPropertiesWidget );
40 
41   blockAllSignals( true );
42 
43   mShapeStyleButton->setSymbolType( Qgis::SymbolType::Marker );
44 
45   blockAllSignals( false );
46 
47   connect( mMarker, &QgsLayoutObject::changed, this, &QgsLayoutMarkerWidget::setGuiElementValues );
48   mShapeStyleButton->registerExpressionContextGenerator( mMarker );
49 
50   connect( mShapeStyleButton, &QgsSymbolButton::changed, this, &QgsLayoutMarkerWidget::symbolChanged );
51 
52   connect( mRotationFromMapCheckBox, &QCheckBox::stateChanged, this, &QgsLayoutMarkerWidget::rotationFromMapCheckBoxChanged );
53   connect( mNorthOffsetSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutMarkerWidget::northOffsetSpinBoxChanged );
54   connect( mNorthTypeComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLayoutMarkerWidget::northTypeComboBoxChanged );
55 
56   mNorthTypeComboBox->blockSignals( true );
57   mNorthTypeComboBox->addItem( tr( "Grid North" ), QgsLayoutNorthArrowHandler::GridNorth );
58   mNorthTypeComboBox->addItem( tr( "True North" ), QgsLayoutNorthArrowHandler::TrueNorth );
59   mNorthTypeComboBox->blockSignals( false );
60   mNorthOffsetSpinBox->setClearValue( 0.0 );
61 
62   mShapeStyleButton->setLayer( coverageLayer() );
63   if ( mMarker->layout() )
64   {
65     connect( &mMarker->layout()->reportContext(), &QgsLayoutReportContext::layerChanged, mShapeStyleButton, &QgsSymbolButton::setLayer );
66     mMapComboBox->setCurrentLayout( mMarker->layout() );
67     mMapComboBox->setItemType( QgsLayoutItemRegistry::LayoutMap );
68     connect( mMapComboBox, &QgsLayoutItemComboBox::itemChanged, this, &QgsLayoutMarkerWidget::mapChanged );
69   }
70 
71   setGuiElementValues();
72 }
73 
setMasterLayout(QgsMasterLayoutInterface * masterLayout)74 void QgsLayoutMarkerWidget::setMasterLayout( QgsMasterLayoutInterface *masterLayout )
75 {
76   if ( mItemPropertiesWidget )
77     mItemPropertiesWidget->setMasterLayout( masterLayout );
78 }
79 
setNewItem(QgsLayoutItem * item)80 bool QgsLayoutMarkerWidget::setNewItem( QgsLayoutItem *item )
81 {
82   if ( item->type() != QgsLayoutItemRegistry::LayoutShape )
83     return false;
84 
85   if ( mMarker )
86   {
87     disconnect( mMarker, &QgsLayoutObject::changed, this, &QgsLayoutMarkerWidget::setGuiElementValues );
88   }
89 
90   mMarker = qobject_cast< QgsLayoutItemMarker * >( item );
91   mItemPropertiesWidget->setItem( mMarker );
92 
93   if ( mMarker )
94   {
95     connect( mMarker, &QgsLayoutObject::changed, this, &QgsLayoutMarkerWidget::setGuiElementValues );
96     mShapeStyleButton->registerExpressionContextGenerator( mMarker );
97   }
98 
99   setGuiElementValues();
100 
101   return true;
102 }
103 
blockAllSignals(bool block)104 void QgsLayoutMarkerWidget::blockAllSignals( bool block )
105 {
106   mShapeStyleButton->blockSignals( block );
107   mMapComboBox->blockSignals( block );
108   mRotationFromMapCheckBox->blockSignals( block );
109   mNorthTypeComboBox->blockSignals( block );
110   mNorthOffsetSpinBox->blockSignals( block );
111 }
112 
setGuiElementValues()113 void QgsLayoutMarkerWidget::setGuiElementValues()
114 {
115   if ( !mMarker )
116   {
117     return;
118   }
119 
120   blockAllSignals( true );
121 
122   mShapeStyleButton->setSymbol( mMarker->symbol()->clone() );
123 
124   mMapComboBox->setItem( mMarker->linkedMap() );
125   if ( mMarker->linkedMap() )
126   {
127     mRotationFromMapCheckBox->setCheckState( Qt::Checked );
128     mMapComboBox->setEnabled( true );
129     mNorthTypeComboBox->setEnabled( true );
130     mNorthOffsetSpinBox->setEnabled( true );
131   }
132   else
133   {
134     mRotationFromMapCheckBox->setCheckState( Qt::Unchecked );
135     mMapComboBox->setEnabled( false );
136     mNorthTypeComboBox->setEnabled( false );
137     mNorthOffsetSpinBox->setEnabled( false );
138   }
139   mNorthTypeComboBox->setCurrentIndex( mNorthTypeComboBox->findData( mMarker->northMode() ) );
140   mNorthOffsetSpinBox->setValue( mMarker->northOffset() );
141 
142   blockAllSignals( false );
143 }
144 
symbolChanged()145 void QgsLayoutMarkerWidget::symbolChanged()
146 {
147   if ( !mMarker )
148     return;
149 
150   mMarker->layout()->undoStack()->beginCommand( mMarker, tr( "Change Marker Symbol" ), QgsLayoutItem::UndoShapeStyle );
151   mMarker->setSymbol( mShapeStyleButton->clonedSymbol<QgsMarkerSymbol>() );
152   mMarker->layout()->undoStack()->endCommand();
153 }
154 
rotationFromMapCheckBoxChanged(int state)155 void QgsLayoutMarkerWidget::rotationFromMapCheckBoxChanged( int state )
156 {
157   if ( !mMarker )
158   {
159     return;
160   }
161 
162   mMarker->beginCommand( tr( "Toggle Rotation Sync" ) );
163   if ( state == Qt::Unchecked )
164   {
165     mMarker->setLinkedMap( nullptr );
166     mMapComboBox->setEnabled( false );
167     mNorthTypeComboBox->setEnabled( false );
168     mNorthOffsetSpinBox->setEnabled( false );
169   }
170   else
171   {
172     QgsLayoutItemMap *map = qobject_cast< QgsLayoutItemMap * >( mMapComboBox->currentItem() );
173     mMarker->setLinkedMap( map );
174     mNorthTypeComboBox->setEnabled( true );
175     mNorthOffsetSpinBox->setEnabled( true );
176     mMapComboBox->setEnabled( true );
177   }
178   mMarker->endCommand();
179 }
180 
mapChanged(QgsLayoutItem * item)181 void QgsLayoutMarkerWidget::mapChanged( QgsLayoutItem *item )
182 {
183   if ( !mMarker )
184   {
185     return;
186   }
187 
188   const QgsLayout *layout = mMarker->layout();
189   if ( !layout )
190   {
191     return;
192   }
193 
194   QgsLayoutItemMap *map = qobject_cast< QgsLayoutItemMap *>( item );
195   if ( !map )
196   {
197     return;
198   }
199 
200   mMarker->beginCommand( tr( "Change Rotation Map" ) );
201   mMarker->setLinkedMap( map );
202   mMarker->update();
203   mMarker->endCommand();
204 }
205 
northOffsetSpinBoxChanged(double d)206 void QgsLayoutMarkerWidget::northOffsetSpinBoxChanged( double d )
207 {
208   mMarker->beginCommand( tr( "Change Marker North Offset" ), QgsLayoutItem::UndoPictureNorthOffset );
209   mMarker->setNorthOffset( d );
210   mMarker->endCommand();
211   mMarker->update();
212 }
213 
northTypeComboBoxChanged(int index)214 void QgsLayoutMarkerWidget::northTypeComboBoxChanged( int index )
215 {
216   mMarker->beginCommand( tr( "Change Marker North Mode" ) );
217   mMarker->setNorthMode( static_cast< QgsLayoutNorthArrowHandler::NorthMode >( mNorthTypeComboBox->itemData( index ).toInt() ) );
218   mMarker->endCommand();
219   mMarker->update();
220 }
221