20#include <QDesktopServices>
28#include "moc_qgsjsoneditwidget.cpp"
30using namespace Qt::StringLiterals;
34 , mCopyValueAction( new QAction( tr(
"Copy Value" ), this ) )
35 , mCopyKeyAction( new QAction( tr(
"Copy Key" ), this ) )
41 mCodeEditorJson->setReadOnly(
true );
42 mCodeEditorJson->setHorizontalScrollBarPolicy( Qt::ScrollBarAsNeeded );
43 mCodeEditorJson->setVerticalScrollBarPolicy( Qt::ScrollBarAsNeeded );
44 mCodeEditorJson->indicatorDefine( QsciScintilla::PlainIndicator, SCINTILLA_UNDERLINE_INDICATOR_INDEX );
45 mCodeEditorJson->SendScintilla( QsciScintillaBase::SCI_SETINDICATORCURRENT, SCINTILLA_UNDERLINE_INDICATOR_INDEX );
46 mCodeEditorJson->SendScintilla( QsciScintillaBase::SCI_SETMOUSEDWELLTIME, 400 );
48 mTreeWidget->setContextMenuPolicy( Qt::ActionsContextMenu );
49 mTreeWidget->addAction( mCopyValueAction );
50 mTreeWidget->addAction( mCopyKeyAction );
52 connect( mTextToolButton, &QToolButton::clicked,
this, &QgsJsonEditWidget::textToolButtonClicked );
53 connect( mTreeToolButton, &QToolButton::clicked,
this, &QgsJsonEditWidget::treeToolButtonClicked );
55 connect( mCopyValueAction, &QAction::triggered,
this, &QgsJsonEditWidget::copyValueActionTriggered );
56 connect( mCopyKeyAction, &QAction::triggered,
this, &QgsJsonEditWidget::copyKeyActionTriggered );
58 connect( mCodeEditorJson, &QgsCodeEditorJson::textChanged,
this, &QgsJsonEditWidget::codeEditorJsonTextChanged );
61 connect( mCodeEditorJson, &QsciScintilla::indicatorClicked,
this, &QgsJsonEditWidget::codeEditorJsonIndicatorClicked );
62 connect( mCodeEditorJson, &QsciScintillaBase::SCN_DWELLSTART,
this, &QgsJsonEditWidget::codeEditorJsonDwellStart );
63 connect( mCodeEditorJson, &QsciScintillaBase::SCN_DWELLEND,
this, &QgsJsonEditWidget::codeEditorJsonDwellEnd );
68 return mCodeEditorJson;
74 mClickableLinkList.clear();
76 const QJsonDocument jsonDocument = QJsonDocument::fromJson( mJsonText.toUtf8() );
78 mCodeEditorJson->blockSignals(
true );
79 if ( jsonDocument.isNull() )
81 mCodeEditorJson->setText( mJsonText );
85 switch ( mFormatJsonMode )
88 mCodeEditorJson->setText( jsonDocument.toJson( QJsonDocument::Indented ) );
91 mCodeEditorJson->setText( jsonDocument.toJson( QJsonDocument::Compact ) );
94 mCodeEditorJson->setText( mJsonText );
98 mCodeEditorJson->blockSignals(
false );
100 refreshTreeView( jsonDocument );
114 mStackedWidget->setCurrentWidget( mStackedWidgetPageText );
115 mTextToolButton->setChecked(
true );
116 mTreeToolButton->setChecked(
false );
121 mStackedWidget->setCurrentWidget( mStackedWidgetPageTree );
122 mTreeToolButton->setChecked(
true );
123 mTextToolButton->setChecked(
false );
131 mFormatJsonMode = formatJson;
136 mControlsWidget->setVisible( visible );
139void QgsJsonEditWidget::textToolButtonClicked(
bool checked )
147void QgsJsonEditWidget::treeToolButtonClicked(
bool checked )
155void QgsJsonEditWidget::copyValueActionTriggered()
157 if ( !mTreeWidget->currentItem() )
160 const QJsonValue jsonValue = QJsonValue::fromVariant( mTreeWidget->currentItem()->data(
static_cast<int>( TreeWidgetColumn::Value ), Qt::UserRole ) );
162 switch ( jsonValue.type() )
164 case QJsonValue::Null:
165 case QJsonValue::Bool:
166 case QJsonValue::Double:
167 case QJsonValue::Undefined:
168 QApplication::clipboard()->setText( mTreeWidget->currentItem()->text(
static_cast<int>( TreeWidgetColumn::Value ) ) );
170 case QJsonValue::String:
171 QApplication::clipboard()->setText( jsonValue.toString() );
173 case QJsonValue::Array:
175 const QJsonDocument jsonDocument( jsonValue.toArray() );
176 QApplication::clipboard()->setText( jsonDocument.toJson() );
179 case QJsonValue::Object:
181 const QJsonDocument jsonDocument( jsonValue.toObject() );
182 QApplication::clipboard()->setText( jsonDocument.toJson() );
188void QgsJsonEditWidget::copyKeyActionTriggered()
190 if ( !mTreeWidget->currentItem() )
193 QApplication::clipboard()->setText( mTreeWidget->currentItem()->text(
static_cast<int>( TreeWidgetColumn::Key ) ) );
196void QgsJsonEditWidget::codeEditorJsonTextChanged()
198 mJsonText = mCodeEditorJson->text();
199 const QJsonDocument jsonDocument = QJsonDocument::fromJson( mJsonText.toUtf8() );
200 refreshTreeView( jsonDocument );
203void QgsJsonEditWidget::codeEditorJsonIndicatorClicked(
int line,
int index, Qt::KeyboardModifiers state )
205 if ( !state.testFlag( Qt::ControlModifier ) )
208 const int position = mCodeEditorJson->positionFromLineIndex( line, index );
209 const int clickableLinkListIndex = mCodeEditorJson->SendScintilla( QsciScintillaBase::SCI_INDICATORVALUEAT, SCINTILLA_UNDERLINE_INDICATOR_INDEX, position );
210 if ( clickableLinkListIndex <= 0 )
213 QDesktopServices::openUrl( mClickableLinkList.at( clickableLinkListIndex - 1 ) );
216void QgsJsonEditWidget::codeEditorJsonDwellStart(
int position,
int x,
int y )
221 const int clickableLinkListIndex = mCodeEditorJson->SendScintilla( QsciScintillaBase::SCI_INDICATORVALUEAT, SCINTILLA_UNDERLINE_INDICATOR_INDEX, position );
222 if ( clickableLinkListIndex <= 0 )
225 QToolTip::showText( QCursor::pos(), tr(
"%1\nCTRL + click to follow link" ).arg( mClickableLinkList.at( clickableLinkListIndex - 1 ) ) );
228void QgsJsonEditWidget::codeEditorJsonDwellEnd(
int position,
int x,
int y )
233 QToolTip::hideText();
236void QgsJsonEditWidget::refreshTreeView(
const QJsonDocument &jsonDocument )
238 mTreeWidget->clear();
240 if ( jsonDocument.isNull() )
243 mTextToolButton->setDisabled(
true );
244 mTreeToolButton->setDisabled(
true );
245 mTreeToolButton->setToolTip( tr(
"Invalid JSON, tree view not available" ) );
250 mTextToolButton->setEnabled(
true );
251 mTreeToolButton->setEnabled(
true );
252 mTreeToolButton->setToolTip( tr(
"Tree view" ) );
255 if ( jsonDocument.isObject() )
257 const QStringList keys = jsonDocument.object().keys();
258 for (
const QString &key : keys )
260 const QJsonValue jsonValue = jsonDocument.object().value( key );
261 QTreeWidgetItem *treeWidgetItem =
new QTreeWidgetItem( mTreeWidget, QStringList() << key );
262 treeWidgetItem->setFont( 0, monospaceFont() );
263 refreshTreeViewItem( treeWidgetItem, jsonValue );
264 mTreeWidget->addTopLevelItem( treeWidgetItem );
265 mTreeWidget->expandItem( treeWidgetItem );
268 else if ( jsonDocument.isArray() )
270 const QJsonArray array = jsonDocument.array();
271 const auto arraySize = array.size();
275 constexpr decltype( arraySize ) MAX_ELTS = 200;
278 if ( arraySize > MAX_ELTS )
279 mEnableUrlHighlighting =
false;
280 for (
auto index =
decltype( arraySize ) { 0 }; index < arraySize; index++ )
282 QTreeWidgetItem *treeWidgetItem =
new QTreeWidgetItem( mTreeWidget, QStringList() << QString::number( index ) );
283 treeWidgetItem->setFont( 0, monospaceFont() );
284 if ( arraySize <= MAX_ELTS || ( index < MAX_ELTS / 2 || index + MAX_ELTS / 2 > arraySize ) )
286 refreshTreeViewItem( treeWidgetItem, array.at( index ) );
287 mTreeWidget->addTopLevelItem( treeWidgetItem );
288 mTreeWidget->expandItem( treeWidgetItem );
290 else if ( index == MAX_ELTS / 2 )
292 index = arraySize - MAX_ELTS / 2;
293 refreshTreeViewItem( treeWidgetItem, tr(
"... truncated ..." ) );
294 mTreeWidget->addTopLevelItem( treeWidgetItem );
295 mTreeWidget->expandItem( treeWidgetItem );
300 mTreeWidget->resizeColumnToContents(
static_cast<int>( TreeWidgetColumn::Key ) );
303void QgsJsonEditWidget::refreshTreeViewItem( QTreeWidgetItem *treeWidgetItem,
const QJsonValue &jsonValue )
305 treeWidgetItem->setData(
static_cast<int>( TreeWidgetColumn::Value ), Qt::UserRole, jsonValue.toVariant() );
307 switch ( jsonValue.type() )
309 case QJsonValue::Null:
312 case QJsonValue::Bool:
315 case QJsonValue::Double:
318 case QJsonValue::String:
320 const QString jsonValueString = jsonValue.toString();
321 if ( !mEnableUrlHighlighting || QUrl( jsonValueString ).scheme().isEmpty() )
327 QLabel *label =
new QLabel( QString(
"<a href='%1'>%1</a>" ).arg( jsonValueString ) );
328 label->setOpenExternalLinks(
true );
329 label->setFont( monospaceFont() );
330 mTreeWidget->setItemWidget( treeWidgetItem,
static_cast<int>( TreeWidgetColumn::Value ), label );
332 mClickableLinkList.append( jsonValueString );
333 mCodeEditorJson->SendScintilla( QsciScintillaBase::SCI_SETINDICATORVALUE,
static_cast<int>( mClickableLinkList.size() ) );
334 mCodeEditorJson->SendScintilla( QsciScintillaBase::SCI_INDICATORFILLRANGE, mCodeEditorJson->text().indexOf( jsonValueString ), jsonValueString.size() );
338 case QJsonValue::Array:
340 const QJsonArray jsonArray = jsonValue.toArray();
341 const auto arraySize = jsonArray.size();
345 constexpr decltype( arraySize ) MAX_ELTS = 200;
348 if ( arraySize > MAX_ELTS )
349 mEnableUrlHighlighting =
false;
350 for (
auto index =
decltype( arraySize ) { 0 }; index < arraySize; index++ )
352 QTreeWidgetItem *treeWidgetItemChild =
new QTreeWidgetItem( treeWidgetItem, QStringList() << QString::number( index ) );
353 treeWidgetItemChild->setFont( 0, monospaceFont() );
354 if ( arraySize <= MAX_ELTS || ( index < MAX_ELTS / 2 || index + MAX_ELTS / 2 > arraySize ) )
356 refreshTreeViewItem( treeWidgetItemChild, jsonArray.at( index ) );
357 treeWidgetItem->addChild( treeWidgetItemChild );
358 treeWidgetItem->setExpanded(
true );
360 else if ( index == MAX_ELTS / 2 )
362 index = arraySize - MAX_ELTS / 2;
363 refreshTreeViewItem( treeWidgetItemChild, tr(
"... truncated ..." ) );
364 treeWidgetItem->addChild( treeWidgetItemChild );
365 treeWidgetItem->setExpanded(
true );
370 case QJsonValue::Object:
372 const QJsonObject jsonObject = jsonValue.toObject();
373 const QStringList keys = jsonObject.keys();
374 for (
const QString &key : keys )
376 QTreeWidgetItem *treeWidgetItemChild =
new QTreeWidgetItem( treeWidgetItem, QStringList() << key );
377 treeWidgetItemChild->setFont( 0, monospaceFont() );
378 refreshTreeViewItem( treeWidgetItemChild, jsonObject.value( key ) );
379 treeWidgetItem->addChild( treeWidgetItemChild );
380 treeWidgetItem->setExpanded(
true );
384 case QJsonValue::Undefined:
390void QgsJsonEditWidget::refreshTreeViewItemValue( QTreeWidgetItem *treeWidgetItem,
const QString &jsonValueString,
const QColor &textColor )
392 QLabel *label =
new QLabel( jsonValueString );
393 label->setFont( monospaceFont() );
395 if ( textColor.isValid() )
396 label->setStyleSheet( u
"color: %1;"_s.arg( textColor.name() ) );
397 mTreeWidget->setItemWidget( treeWidgetItem,
static_cast<int>( TreeWidgetColumn::Value ), label );
400QFont QgsJsonEditWidget::monospaceFont()
const
404 f.setPointSize( font().pointSize() );
@ DoubleQuote
Double quote color.
A JSON editor based on QScintilla2.
static QFont getMonospaceFont()
Returns the monospaced font to use for code editors.
static QColor color(QgsCodeEditorColorScheme::ColorRole role)
Returns the color to use in the editor for the specified role.