~ubuntu-branches/ubuntu/trusty/qgis/trusty

« back to all changes in this revision

Viewing changes to src/app/qgslabeldialog.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Johan Van de Wauw
  • Date: 2010-07-11 20:23:24 UTC
  • mfrom: (3.1.4 squeeze)
  • Revision ID: james.westby@ubuntu.com-20100711202324-5ktghxa7hracohmr
Tags: 1.4.0+12730-3ubuntu1
* Merge from Debian unstable (LP: #540941).
* Fix compilation issues with QT 4.7
* Add build-depends on libqt4-webkit-dev 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************************
 
2
                         qgslabeldialog.cpp  -  render vector labels
 
3
                             -------------------
 
4
    begin                : August 2004
 
5
    copyright            : (C) 2004 by Radim Blazek & Tim Sutton
 
6
    email                : blazek@itc.it
 
7
 ***************************************************************************/
 
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
/* $Id$ */
 
17
#include "qgslabeldialog.h"
 
18
#include "qgsfield.h"
 
19
#include "qgslabel.h"
 
20
#include "qgslabelattributes.h"
 
21
 
 
22
#include <QColorDialog>
 
23
#include <QFontDialog>
 
24
#include <QTabWidget>
 
25
#include "qgslogger.h"
 
26
 
 
27
 
 
28
const int PIXMAP_WIDTH = 200;
 
29
const int PIXMAP_HEIGHT = 20;
 
30
 
 
31
QgsLabelDialog::QgsLabelDialog( QgsLabel *label,  QWidget *parent )
 
32
    : QWidget( parent ),
 
33
    mLabel( label ),
 
34
    mFontColor( Qt::black ),
 
35
    mBufferColor( Qt::black ),
 
36
    mFont( "Helvetica" )
 
37
{
 
38
  setupUi( this );
 
39
  QgsDebugMsg( "entering." );
 
40
 
 
41
  Q_ASSERT( label );
 
42
 
 
43
  init();
 
44
 
 
45
  connect( btnDefaultFont, SIGNAL( clicked() ),
 
46
           this, SLOT( changeFont() ) );
 
47
  connect( pbnDefaultBufferColor_2, SIGNAL( clicked() ),
 
48
           this, SLOT( changeBufferColor() ) );
 
49
  connect( pbnDefaultFontColor, SIGNAL( clicked() ),
 
50
           this, SLOT( changeFontColor() ) );
 
51
}
 
52
 
 
53
 
 
54
void QgsLabelDialog::init( )
 
55
{
 
56
  QgsDebugMsg( "entering." );
 
57
 
 
58
  QgsLabelAttributes * myLabelAttributes = mLabel->labelAttributes();
 
59
  //populate a string list with all the field names which will be used to set up the
 
60
  //data bound combos
 
61
  QgsFieldMap& myFieldsMap = mLabel->fields();
 
62
  QStringList myFieldStringList;
 
63
  myFieldStringList.append( "" );
 
64
  for ( QgsFieldMap::iterator it = myFieldsMap.begin(); it != myFieldsMap.end(); ++it )
 
65
  {
 
66
    myFieldStringList.append( it->name() );
 
67
  }
 
68
  //
 
69
  //now set all the combos that need field lists using the string list
 
70
  //
 
71
  cboLabelField->clear();
 
72
  cboLabelField->addItems( myFieldStringList );
 
73
  cboLabelField->setCurrentIndex( itemNoForField( mLabel->labelField( QgsLabel::Text ), myFieldStringList ) );
 
74
 
 
75
  cboFontField->clear();
 
76
  cboFontField->addItems( myFieldStringList );
 
77
  cboFontField->setCurrentIndex( itemNoForField( mLabel->labelField( QgsLabel::Family ), myFieldStringList ) );
 
78
 
 
79
  cboBoldField->clear();
 
80
  cboBoldField->addItems( myFieldStringList );
 
81
  cboBoldField->setCurrentIndex( itemNoForField( mLabel->labelField( QgsLabel::Bold ), myFieldStringList ) );
 
82
 
 
83
 
 
84
  cboItalicField->clear();
 
85
  cboItalicField->addItems( myFieldStringList );
 
86
  cboItalicField->setCurrentIndex( itemNoForField( mLabel->labelField( QgsLabel::Italic ), myFieldStringList ) );
 
87
 
 
88
  cboUnderlineField->clear();
 
89
  cboUnderlineField->addItems( myFieldStringList );
 
90
  cboUnderlineField->setCurrentIndex( itemNoForField( mLabel->labelField( QgsLabel::Underline ), myFieldStringList ) );
 
91
 
 
92
  cboFontSizeField->clear();
 
93
  cboFontSizeField->addItems( myFieldStringList );
 
94
  cboFontSizeField->setCurrentIndex( itemNoForField( mLabel->labelField( QgsLabel::Size ), myFieldStringList ) );
 
95
 
 
96
  cboFontSizeTypeField->clear();
 
97
  cboFontSizeTypeField->addItems( myFieldStringList );
 
98
  cboFontSizeTypeField->setCurrentIndex( itemNoForField( mLabel->labelField( QgsLabel::SizeType ), myFieldStringList ) );
 
99
 
 
100
#if 0
 
101
  cboFontTransparencyField->clear();
 
102
  cboFontTransparencyField->addItems( myFieldStringList );
 
103
  cboFontTransparencyField->setCurrentIndex( itemNoForField( mLabel->labelField( QgsLabel::FontTransparency ), myFieldStringList ) );
 
104
#endif
 
105
 
 
106
  cboFontColorField->clear();
 
107
  cboFontColorField->addItems( myFieldStringList );
 
108
  cboFontColorField->setCurrentIndex( itemNoForField( mLabel->labelField( QgsLabel::Color ), myFieldStringList ) );
 
109
 
 
110
 
 
111
  cboBufferSizeField->clear();
 
112
  cboBufferSizeField->addItems( myFieldStringList );
 
113
  cboBufferSizeField->setCurrentIndex( itemNoForField( mLabel->labelField( QgsLabel::BufferSize ), myFieldStringList ) );
 
114
 
 
115
  cboBufferTransparencyField->clear();
 
116
  cboBufferTransparencyField->addItems( myFieldStringList );
 
117
  //cboBufferTransparencyField->setCurrentIndex(itemNoForField(mLabel->labelField(QgsLabel::BufferTransparency),myFieldStringList));
 
118
 
 
119
  cboXCoordinateField->clear();
 
120
  cboXCoordinateField->addItems( myFieldStringList );
 
121
  cboXCoordinateField->setCurrentIndex( itemNoForField( mLabel->labelField( QgsLabel::XCoordinate ), myFieldStringList ) );
 
122
 
 
123
  cboYCoordinateField->clear();
 
124
  cboYCoordinateField->addItems( myFieldStringList );
 
125
  cboYCoordinateField->setCurrentIndex( itemNoForField( mLabel->labelField( QgsLabel::YCoordinate ), myFieldStringList ) );
 
126
 
 
127
  cboXOffsetField->clear();
 
128
  cboXOffsetField->addItems( myFieldStringList );
 
129
  cboXOffsetField->setCurrentIndex( itemNoForField( mLabel->labelField( QgsLabel::XOffset ), myFieldStringList ) );
 
130
 
 
131
  cboYOffsetField->clear();
 
132
  cboYOffsetField->addItems( myFieldStringList );
 
133
  cboYOffsetField->setCurrentIndex( itemNoForField( mLabel->labelField( QgsLabel::YOffset ), myFieldStringList ) );
 
134
 
 
135
  cboAlignmentField->clear();
 
136
  cboAlignmentField->addItems( myFieldStringList );
 
137
  cboAlignmentField->setCurrentIndex( itemNoForField( mLabel->labelField( QgsLabel::Alignment ), myFieldStringList ) );
 
138
 
 
139
  cboAngleField->clear();
 
140
  cboAngleField->addItems( myFieldStringList );
 
141
  cboAngleField->setCurrentIndex( itemNoForField( mLabel->labelField( QgsLabel::Angle ), myFieldStringList ) );
 
142
 
 
143
  // set up the scale based layer visibility stuff....
 
144
  chkUseScaleDependentRendering->setChecked( mLabel->scaleBasedVisibility() );
 
145
  spinMinimumScale->setValue(( int )mLabel->minScale() );
 
146
  spinMaximumScale->setValue(( int )mLabel->maxScale() );
 
147
 
 
148
  //
 
149
  //set the non-databound fields up now
 
150
  //
 
151
  leDefaultLabel->setText( myLabelAttributes->text() );
 
152
  mFont.setFamily( myLabelAttributes->family() );
 
153
  if ( myLabelAttributes->sizeIsSet() )
 
154
  {
 
155
    mFont.setPointSizeF( myLabelAttributes->size() );
 
156
 
 
157
    int myTypeInt = myLabelAttributes->sizeType();
 
158
    if ( myTypeInt == QgsLabelAttributes::PointUnits )
 
159
    {
 
160
      radioFontSizeUnitsPoints->setChecked( true );
 
161
    }
 
162
    else //assume map units is checked
 
163
    {
 
164
      radioFontSizeUnitsMap->setChecked( true );
 
165
    }
 
166
  }
 
167
  else //defaults for when no size has been set
 
168
  {
 
169
    mFont.setPointSizeF( myLabelAttributes->size() );
 
170
    radioFontSizeUnitsPoints->setChecked( true );
 
171
  }
 
172
 
 
173
  spinFontSize->setValue( myLabelAttributes->size() );
 
174
 
 
175
  if ( myLabelAttributes->boldIsSet() )
 
176
  {
 
177
    mFont.setBold( myLabelAttributes->bold() );
 
178
  }
 
179
  else
 
180
  {
 
181
    mFont.setBold( false );
 
182
  }
 
183
  if ( myLabelAttributes->italicIsSet() )
 
184
  {
 
185
    mFont.setItalic( myLabelAttributes->italic() );
 
186
  }
 
187
  else
 
188
  {
 
189
    mFont.setItalic( false );
 
190
  }
 
191
  if ( myLabelAttributes->underlineIsSet() )
 
192
  {
 
193
    mFont.setUnderline( myLabelAttributes->underline() );
 
194
  }
 
195
  else
 
196
  {
 
197
    mFont.setUnderline( false );
 
198
  }
 
199
 
 
200
  mFontColor = myLabelAttributes->color();
 
201
 
 
202
  if ( myLabelAttributes->offsetIsSet() )
 
203
  {
 
204
    int myTypeInt = myLabelAttributes->offsetType();
 
205
    if ( myTypeInt == QgsLabelAttributes::PointUnits )
 
206
    {
 
207
      radioOffsetUnitsPoints->setChecked( true );
 
208
    }
 
209
    else
 
210
    {
 
211
      radioOffsetUnitsMap->setChecked( true );
 
212
    }
 
213
    spinXOffset->setValue( myLabelAttributes->xOffset() );
 
214
    spinYOffset->setValue( myLabelAttributes->yOffset() );
 
215
  }
 
216
  else //defaults for when no offset is defined
 
217
  {
 
218
    spinXOffset->setValue( 0 );
 
219
    spinYOffset->setValue( 0 );
 
220
  }
 
221
  spinAngle->setRange( -1, 360 );
 
222
  spinAngle->setSpecialValueText( tr( "Auto" ) );
 
223
  if ( myLabelAttributes->angleIsAuto() )
 
224
  {
 
225
    spinAngle->setValue( -1 );
 
226
  }
 
227
  else
 
228
  {
 
229
    spinAngle->setValue( static_cast<int>( myLabelAttributes->angle() ) );
 
230
  }
 
231
 
 
232
  //the values here may seem a bit counterintuitive - basically everything
 
233
  //is the reverse of the way you think it should be...
 
234
  //TODO investigate in QgsLabel why this needs to be the case
 
235
  //TODO add support for corners (e.g. bottom right) to xml serialiser
 
236
 
 
237
  if ( myLabelAttributes->alignment() == ( Qt::AlignRight | Qt::AlignBottom ) ) radioAboveLeft->setChecked( true )   ;
 
238
  if ( myLabelAttributes->alignment() == ( Qt::AlignRight | Qt::AlignTop ) ) radioBelowLeft->setChecked( true )   ;
 
239
  if ( myLabelAttributes->alignment() == ( Qt::AlignLeft  | Qt::AlignBottom ) ) radioAboveRight->setChecked( true )  ;
 
240
  if ( myLabelAttributes->alignment() == ( Qt::AlignLeft  | Qt::AlignTop ) ) radioBelowRight->setChecked( true )  ;
 
241
  if ( myLabelAttributes->alignment() == ( Qt::AlignRight | Qt::AlignVCenter ) ) radioLeft->setChecked( true )        ;
 
242
  if ( myLabelAttributes->alignment() == ( Qt::AlignLeft  | Qt::AlignVCenter ) ) radioRight->setChecked( true )       ;
 
243
  if ( myLabelAttributes->alignment() == ( Qt::AlignBottom | Qt::AlignHCenter ) ) radioAbove->setChecked( true )       ;
 
244
  if ( myLabelAttributes->alignment() == ( Qt::AlignTop   | Qt::AlignHCenter ) ) radioBelow->setChecked( true )       ;
 
245
  if ( myLabelAttributes->alignment() == Qt::AlignCenter ) radioOver->setChecked( true )        ;
 
246
 
 
247
  mBufferColor = myLabelAttributes->bufferColor();
 
248
  //note that it could be that buffer properties are set, but the bufer is disabled
 
249
  if ( myLabelAttributes->bufferSizeIsSet() )
 
250
  {
 
251
    int myTypeInt = myLabelAttributes->bufferSizeType();
 
252
    if ( myTypeInt == QgsLabelAttributes::PointUnits )
 
253
    {
 
254
      radioBufferUnitsPoints->setChecked( true );
 
255
    }
 
256
    else
 
257
    {
 
258
      radioBufferUnitsMap->setChecked( true );
 
259
    }
 
260
    spinBufferSize->setValue( myLabelAttributes->bufferSize() );
 
261
  }
 
262
  else //defaults for when no offset is defined
 
263
  {
 
264
    spinBufferSize->setValue( 1 );
 
265
  }
 
266
  //set the state of the multiline enabled checkbox
 
267
  chkUseMultiline->setChecked( myLabelAttributes->multilineEnabled() );
 
268
  //set the state of the buffer enabled checkbox
 
269
  chkUseBuffer->setChecked( myLabelAttributes->bufferEnabled() );
 
270
 
 
271
  //NOTE: do we need this line too? TS
 
272
  spinBufferSize->setValue( myLabelAttributes->bufferSize() );
 
273
  //TODO - transparency attributes for buffers
 
274
 
 
275
}
 
276
 
 
277
 
 
278
 
 
279
void QgsLabelDialog::changeFont( void )
 
280
{
 
281
  QgsDebugMsg( "entering." );
 
282
 
 
283
  qreal fontSize = mFont.pointSizeF();
 
284
  bool resultFlag;
 
285
#if defined(Q_WS_MAC) && QT_VERSION >= 0x040500 && !defined(__LP64__)
 
286
  // Native Mac dialog works only for 64 bit Cocoa (observed in Qt 4.5.2, probably a Qt bug)
 
287
  mFont = QFontDialog::getFont( &resultFlag, mFont, this, QString(), QFontDialog::DontUseNativeDialog );
 
288
#else
 
289
  mFont = QFontDialog::getFont( &resultFlag, mFont, this );
 
290
#endif
 
291
  if ( resultFlag )
 
292
  {
 
293
    if ( mFont.pointSizeF() != fontSize )
 
294
    {
 
295
      // font is set to the font the user selected
 
296
      spinFontSize->setValue( mFont.pointSizeF() );
 
297
    }
 
298
  }
 
299
  else
 
300
  {
 
301
    // the user cancelled the dialog; font is set to the initial
 
302
    // value, in this case Helvetica [Cronyx], 10
 
303
  }
 
304
  lblSample->setFont( mFont );
 
305
}
 
306
 
 
307
void QgsLabelDialog::changeFontColor( void )
 
308
{
 
309
  QgsDebugMsg( "entering." );
 
310
 
 
311
  mFontColor = QColorDialog::getColor( mFontColor );
 
312
  QPalette palette = lblSample->palette();
 
313
  palette.setColor( lblSample->foregroundRole(), mFontColor );
 
314
  lblSample->setPalette( palette );
 
315
}
 
316
 
 
317
void QgsLabelDialog::changeBufferColor( void )
 
318
{
 
319
  QgsDebugMsg( "entering." );
 
320
 
 
321
  mBufferColor = QColorDialog::getColor( mBufferColor );
 
322
  QPalette palette = lblSample->palette();
 
323
  palette.setColor( lblSample->backgroundRole(), mBufferColor );
 
324
  lblSample->setPalette( palette );
 
325
}
 
326
 
 
327
 
 
328
int QgsLabelDialog::itemNoForField( QString theFieldName, QStringList theFieldList )
 
329
{
 
330
  int myItemInt = 0;
 
331
  for ( QStringList::Iterator it = theFieldList.begin(); it != theFieldList.end(); ++it )
 
332
  {
 
333
    if ( theFieldName == *it ) return myItemInt;
 
334
    ++myItemInt;
 
335
  }
 
336
  //if no matches assume first item in list is blank and return that
 
337
  return 0;
 
338
}
 
339
 
 
340
QgsLabelDialog::~QgsLabelDialog()
 
341
{
 
342
  QgsDebugMsg( "entering." );
 
343
}
 
344
 
 
345
void QgsLabelDialog::apply()
 
346
{
 
347
  QgsDebugMsg( "entering." );
 
348
 
 
349
  //set the label props that are NOT bound to a field in the attributes tbl
 
350
  //All of these are set in the labelAttributes member of the layer
 
351
  QgsLabelAttributes * myLabelAttributes = mLabel->labelAttributes();
 
352
  myLabelAttributes->setText( leDefaultLabel->text() );
 
353
  myLabelAttributes->setFamily( mFont.family() );
 
354
  int myTypeInt = 0;
 
355
  if ( radioFontSizeUnitsPoints->isChecked() )
 
356
  {
 
357
    myTypeInt = QgsLabelAttributes::PointUnits;
 
358
  }
 
359
  else //assume map units is checked
 
360
  {
 
361
    myTypeInt = QgsLabelAttributes::MapUnits;
 
362
  }
 
363
  myLabelAttributes->setSize( mFont.pointSizeF(), myTypeInt );
 
364
  myLabelAttributes->setBold( mFont.bold() );
 
365
  myLabelAttributes->setItalic( mFont.italic() );
 
366
  myLabelAttributes->setUnderline( mFont.underline() );
 
367
  myLabelAttributes->setColor( mFontColor );
 
368
  myTypeInt = 0;
 
369
  if ( radioOffsetUnitsPoints->isChecked() )
 
370
  {
 
371
    myTypeInt = QgsLabelAttributes::PointUnits;
 
372
  }
 
373
  else
 
374
  {
 
375
    myTypeInt = QgsLabelAttributes::MapUnits;
 
376
  }
 
377
  myLabelAttributes->setOffset( spinXOffset->value(), spinYOffset->value(), myTypeInt );
 
378
  myLabelAttributes->setAutoAngle( spinAngle->value() == -1 );
 
379
  myLabelAttributes->setAngle( spinAngle->value() );
 
380
 
 
381
  //the values here may seem a bit counterintuitive - basically everything
 
382
  //is the reverse of the way you think it should be...
 
383
  //TODO investigate in QgsLabel why this needs to be the case
 
384
  if ( radioAboveLeft->isChecked() )   myLabelAttributes->setAlignment( Qt::AlignRight | Qt::AlignBottom );
 
385
  if ( radioBelowLeft->isChecked() )   myLabelAttributes->setAlignment( Qt::AlignRight | Qt::AlignTop );
 
386
  if ( radioAboveRight->isChecked() )  myLabelAttributes->setAlignment( Qt::AlignLeft  | Qt::AlignBottom );
 
387
  if ( radioBelowRight->isChecked() )  myLabelAttributes->setAlignment( Qt::AlignLeft  | Qt::AlignTop );
 
388
  if ( radioLeft->isChecked() )        myLabelAttributes->setAlignment( Qt::AlignRight | Qt::AlignVCenter );
 
389
  if ( radioRight->isChecked() )       myLabelAttributes->setAlignment( Qt::AlignLeft  | Qt::AlignVCenter );
 
390
  if ( radioAbove->isChecked() )       myLabelAttributes->setAlignment( Qt::AlignBottom | Qt::AlignHCenter );
 
391
  if ( radioBelow->isChecked() )       myLabelAttributes->setAlignment( Qt::AlignTop   | Qt::AlignHCenter );
 
392
  if ( radioOver->isChecked() )        myLabelAttributes->setAlignment( Qt::AlignCenter );
 
393
 
 
394
  myLabelAttributes->setMultilineEnabled( chkUseMultiline->isChecked() );
 
395
  myLabelAttributes->setBufferEnabled( chkUseBuffer->isChecked() );
 
396
  myLabelAttributes->setBufferColor( mBufferColor );
 
397
  myTypeInt = 0;
 
398
  if ( radioBufferUnitsPoints->isChecked() )
 
399
  {
 
400
    myTypeInt = QgsLabelAttributes::PointUnits;
 
401
  }
 
402
  else
 
403
  {
 
404
    myTypeInt = QgsLabelAttributes::MapUnits;
 
405
  }
 
406
  myLabelAttributes->setBufferSize( spinBufferSize->value(), myTypeInt );
 
407
  //TODO - transparency attributes for buffers
 
408
 
 
409
  //set the label props that are data bound to a field in the attributes tbl
 
410
  mLabel->setLabelField( QgsLabel::Text,  fieldIndexFromName( cboLabelField->currentText() ) );
 
411
  mLabel->setLabelField( QgsLabel::Family, fieldIndexFromName( cboFontField->currentText() ) );
 
412
  mLabel->setLabelField( QgsLabel::Bold,  fieldIndexFromName( cboBoldField->currentText() ) );
 
413
  mLabel->setLabelField( QgsLabel::Italic,  fieldIndexFromName( cboItalicField->currentText() ) );
 
414
  mLabel->setLabelField( QgsLabel::Underline,  fieldIndexFromName( cboUnderlineField->currentText() ) );
 
415
  mLabel->setLabelField( QgsLabel::Size,  fieldIndexFromName( cboFontSizeField->currentText() ) );
 
416
  mLabel->setLabelField( QgsLabel::SizeType,  fieldIndexFromName( cboFontSizeTypeField->currentText() ) );
 
417
  mLabel->setLabelField( QgsLabel::Color,  fieldIndexFromName( cboFontColorField->currentText() ) );
 
418
  mLabel->setLabelField( QgsLabel::BufferSize,  fieldIndexFromName( cboBufferSizeField->currentText() ) );
 
419
  //mLabel->setLabelField( QgsLabel::BufferTransparency,  cboBufferTransparencyField->currentText() );
 
420
  mLabel->setLabelField( QgsLabel::XCoordinate,  fieldIndexFromName( cboXCoordinateField->currentText() ) );
 
421
  mLabel->setLabelField( QgsLabel::YCoordinate,  fieldIndexFromName( cboYCoordinateField->currentText() ) );
 
422
  mLabel->setLabelField( QgsLabel::XOffset,  fieldIndexFromName( cboXOffsetField->currentText() ) );
 
423
  mLabel->setLabelField( QgsLabel::YOffset,  fieldIndexFromName( cboYOffsetField->currentText() ) );
 
424
  mLabel->setLabelField( QgsLabel::Alignment,  fieldIndexFromName( cboAlignmentField->currentText() ) );
 
425
  mLabel->setLabelField( QgsLabel::Angle,  fieldIndexFromName( cboAngleField->currentText() ) );
 
426
 
 
427
  // set up the scale based layer visibility stuff....
 
428
  mLabel->setScaleBasedVisibility( chkUseScaleDependentRendering->isChecked() );
 
429
  mLabel->setMinScale( spinMinimumScale->value() );
 
430
  mLabel->setMaxScale( spinMaximumScale->value() );
 
431
}
 
432
 
 
433
int QgsLabelDialog::fieldIndexFromName( QString name )
 
434
{
 
435
  const QgsFieldMap& fields = mLabel->fields();
 
436
  for ( QgsFieldMap::const_iterator it = fields.begin(); it != fields.end(); ++it )
 
437
  {
 
438
    if ( it->name() == name )
 
439
      return it.key();
 
440
  }
 
441
  return -1;
 
442
}