Skip to content
Permalink
Browse files
JSON edit widget tree view improvements
- Added context menu to copy value or key to clipboard
- Values are colored according to type like in text view
  • Loading branch information
domi4484 committed May 27, 2021
1 parent 0b511cc commit 64e686d0c53be9743103358b185e688d971a4b3b
@@ -9,6 +9,7 @@




class QgsJsonEditWidget : QWidget
{
%Docstring(signature="appended")
@@ -15,6 +15,7 @@

#include "qgsjsoneditwidget.h"

#include <QClipboard>
#include <QDesktopServices>
#include <QJsonArray>
#include <QLabel>
@@ -24,6 +25,8 @@

QgsJsonEditWidget::QgsJsonEditWidget( QWidget *parent )
: QWidget( parent )
, mCopyValueAction( tr( "Copy value" ) )
, mCopyKeyAction( tr( "Copy key" ) )
{
setupUi( this );

@@ -38,9 +41,16 @@ QgsJsonEditWidget::QgsJsonEditWidget( QWidget *parent )

mTreeWidget->setStyleSheet( QStringLiteral( "font-family: %1;" ).arg( QgsCodeEditor::getMonospaceFont().family() ) );

mTreeWidget->setContextMenuPolicy( Qt::ActionsContextMenu );
mTreeWidget->addAction( &mCopyValueAction );
mTreeWidget->addAction( &mCopyKeyAction );

connect( mTextToolButton, &QToolButton::clicked, this, &QgsJsonEditWidget::textToolButtonClicked );
connect( mTreeToolButton, &QToolButton::clicked, this, &QgsJsonEditWidget::treeToolButtonClicked );

connect( &mCopyValueAction, &QAction::triggered, this, &QgsJsonEditWidget::copyValueActionTriggered );
connect( &mCopyKeyAction, &QAction::triggered, this, &QgsJsonEditWidget::copyKeyActionTriggered );

connect( mCodeEditorJson, &QgsCodeEditorJson::textChanged, this, &QgsJsonEditWidget::codeEditorJsonTextChanged );
// Signal indicatorClicked is used because indicatorReleased has a bug in Scintilla and the keyboard modifier state
// parameter is not correct. Merge request was submittet to fix it: https://sourceforge.net/p/scintilla/code/merge-requests/26/
@@ -133,6 +143,47 @@ void QgsJsonEditWidget::treeToolButtonClicked( bool checked )
setView( View::Text );
}

void QgsJsonEditWidget::copyValueActionTriggered()
{
if ( !mTreeWidget->currentItem() )
return;

const QJsonValue jsonValue = QJsonValue::fromVariant( mTreeWidget->currentItem()->data( static_cast<int>( TreeWidgetColumn::Value ), Qt::UserRole ) );

switch ( jsonValue.type() )
{
case QJsonValue::Null:
case QJsonValue::Bool:
case QJsonValue::Double:
case QJsonValue::Undefined:
QApplication::clipboard()->setText( mTreeWidget->currentItem()->text( static_cast<int>( TreeWidgetColumn::Value ) ) );
break;
case QJsonValue::String:
QApplication::clipboard()->setText( jsonValue.toString() );
break;
case QJsonValue::Array:
{
const QJsonDocument jsonDocument( jsonValue.toArray() );
QApplication::clipboard()->setText( jsonDocument.toJson() );
}
break;
case QJsonValue::Object:
{
const QJsonDocument jsonDocument( jsonValue.toObject() );
QApplication::clipboard()->setText( jsonDocument.toJson() );
}
break;
}
}

void QgsJsonEditWidget::copyKeyActionTriggered()
{
if ( !mTreeWidget->currentItem() )
return;

QApplication::clipboard()->setText( mTreeWidget->currentItem()->text( static_cast<int>( TreeWidgetColumn::Key ) ) );
}

void QgsJsonEditWidget::codeEditorJsonTextChanged()
{
mJsonText = mCodeEditorJson->text();
@@ -204,7 +255,7 @@ void QgsJsonEditWidget::refreshTreeView( const QJsonDocument &jsonDocument )
{
const QJsonValue jsonValue = jsonDocument.object().value( key );
QTreeWidgetItem *treeWidgetItem = new QTreeWidgetItem( mTreeWidget, QStringList() << key );
refreshTreeViewItemValue( jsonValue, treeWidgetItem );
refreshTreeViewItem( treeWidgetItem, jsonValue );
mTreeWidget->addTopLevelItem( treeWidgetItem );
mTreeWidget->expandItem( treeWidgetItem );
}
@@ -214,7 +265,7 @@ void QgsJsonEditWidget::refreshTreeView( const QJsonDocument &jsonDocument )
for ( int index = 0; index < jsonDocument.array().size(); index++ )
{
QTreeWidgetItem *treeWidgetItem = new QTreeWidgetItem( mTreeWidget, QStringList() << QString::number( index ) );
refreshTreeViewItemValue( jsonDocument.array().at( index ), treeWidgetItem );
refreshTreeViewItem( treeWidgetItem, jsonDocument.array().at( index ) );
mTreeWidget->addTopLevelItem( treeWidgetItem );
mTreeWidget->expandItem( treeWidgetItem );
}
@@ -223,35 +274,41 @@ void QgsJsonEditWidget::refreshTreeView( const QJsonDocument &jsonDocument )
mTreeWidget->resizeColumnToContents( static_cast<int>( TreeWidgetColumn::Key ) );
}

void QgsJsonEditWidget::refreshTreeViewItemValue( const QJsonValue &jsonValue, QTreeWidgetItem *treeWidgetItemParent )
void QgsJsonEditWidget::refreshTreeViewItem( QTreeWidgetItem *treeWidgetItem, const QJsonValue &jsonValue )
{
treeWidgetItem->setData( static_cast<int>( TreeWidgetColumn::Value ), Qt::UserRole, jsonValue.toVariant() );

switch ( jsonValue.type() )
{
case QJsonValue::Null:
treeWidgetItemParent->setText( static_cast<int>( TreeWidgetColumn::Value ), QStringLiteral( "null" ) );
refreshTreeViewItemValue( treeWidgetItem,
QStringLiteral( "null" ),
QgsCodeEditor::color( QgsCodeEditorColorScheme::ColorRole::Keyword ) );
break;
case QJsonValue::Bool:
treeWidgetItemParent->setText( static_cast<int>( TreeWidgetColumn::Value ), jsonValue.toBool() ? QStringLiteral( "true" ) : QStringLiteral( "false" ) );
refreshTreeViewItemValue( treeWidgetItem,
jsonValue.toBool() ? QStringLiteral( "true" ) : QStringLiteral( "false" ),
QgsCodeEditor::color( QgsCodeEditorColorScheme::ColorRole::Keyword ) );
break;
case QJsonValue::Double:
treeWidgetItemParent->setText( static_cast<int>( TreeWidgetColumn::Value ), QString::number( jsonValue.toDouble() ) );
refreshTreeViewItemValue( treeWidgetItem,
QString::number( jsonValue.toDouble() ),
QgsCodeEditor::color( QgsCodeEditorColorScheme::ColorRole::Number ) );
break;
case QJsonValue::String:
{
const QString jsonValueString = jsonValue.toString();
if ( QUrl( jsonValueString ).scheme().isEmpty() )
{
treeWidgetItemParent->setText( static_cast<int>( TreeWidgetColumn::Value ), jsonValueString );
refreshTreeViewItemValue( treeWidgetItem,
jsonValueString,
QgsCodeEditor::color( QgsCodeEditorColorScheme::ColorRole::DoubleQuote ) );
}
else
{
QLabel *label = new QLabel( QString( "<a href='%1'>%1</a>" ).arg( jsonValueString ) );
mTreeWidget->setItemWidget( treeWidgetItemParent, static_cast<int>( TreeWidgetColumn::Value ), label );

connect( label, &QLabel::linkActivated, this, []( const QString & link )
{
QDesktopServices::openUrl( link );
} );
label->setOpenExternalLinks( true );
mTreeWidget->setItemWidget( treeWidgetItem, static_cast<int>( TreeWidgetColumn::Value ), label );

mClickableLinkList.append( jsonValueString );
mCodeEditorJson->SendScintilla( QsciScintillaBase::SCI_SETINDICATORVALUE, mClickableLinkList.size() );
@@ -266,10 +323,10 @@ void QgsJsonEditWidget::refreshTreeViewItemValue( const QJsonValue &jsonValue, Q
const QJsonArray jsonArray = jsonValue.toArray();
for ( int index = 0; index < jsonArray.size(); index++ )
{
QTreeWidgetItem *treeWidgetItem = new QTreeWidgetItem( treeWidgetItemParent, QStringList() << QString::number( index ) );
refreshTreeViewItemValue( jsonArray.at( index ), treeWidgetItem );
treeWidgetItemParent->addChild( treeWidgetItem );
treeWidgetItemParent->setExpanded( true );
QTreeWidgetItem *treeWidgetItemChild = new QTreeWidgetItem( treeWidgetItem, QStringList() << QString::number( index ) );
refreshTreeViewItem( treeWidgetItemChild, jsonArray.at( index ) );
treeWidgetItem->addChild( treeWidgetItemChild );
treeWidgetItem->setExpanded( true );
}
}
break;
@@ -279,15 +336,25 @@ void QgsJsonEditWidget::refreshTreeViewItemValue( const QJsonValue &jsonValue, Q
const QStringList keys = jsonObject.keys();
for ( const QString &key : keys )
{
QTreeWidgetItem *treeWidgetItem = new QTreeWidgetItem( treeWidgetItemParent, QStringList() << key );
refreshTreeViewItemValue( jsonObject.value( key ), treeWidgetItem );
treeWidgetItemParent->addChild( treeWidgetItem );
treeWidgetItemParent->setExpanded( true );
QTreeWidgetItem *treeWidgetItemChild = new QTreeWidgetItem( treeWidgetItem, QStringList() << key );
refreshTreeViewItem( treeWidgetItemChild, jsonObject.value( key ) );
treeWidgetItem->addChild( treeWidgetItemChild );
treeWidgetItem->setExpanded( true );
}
}
break;
case QJsonValue::Undefined:
treeWidgetItemParent->setText( static_cast<int>( TreeWidgetColumn::Value ), QStringLiteral( "Undefined value" ) );
refreshTreeViewItemValue( treeWidgetItem,
QStringLiteral( "Undefined value" ),
QgsCodeEditor::color( QgsCodeEditorColorScheme::ColorRole::DoubleQuote ) );
break;
}
}

void QgsJsonEditWidget::refreshTreeViewItemValue( QTreeWidgetItem *treeWidgetItem, const QString &jsonValueString, const QColor &textColor )
{
QLabel *label = new QLabel( jsonValueString );
if ( textColor.isValid() )
label->setStyleSheet( QStringLiteral( "color: %1;" ).arg( textColor.name() ) );
mTreeWidget->setItemWidget( treeWidgetItem, static_cast<int>( TreeWidgetColumn::Value ), label );
}
@@ -22,6 +22,8 @@
#include "qgis_sip.h"
#include "qgis_gui.h"

#include <QAction>

/**
* \ingroup gui
* \class QgsJsonEditWidget
@@ -87,6 +89,9 @@ class GUI_EXPORT QgsJsonEditWidget : public QWidget, private Ui::QgsJsonEditWidg
void textToolButtonClicked( bool checked );
void treeToolButtonClicked( bool checked );

void copyValueActionTriggered();
void copyKeyActionTriggered();

void codeEditorJsonTextChanged();
void codeEditorJsonIndicatorClicked( int line, int index, Qt::KeyboardModifiers state );
void codeEditorJsonDwellStart( int position, int x, int y );
@@ -103,13 +108,17 @@ class GUI_EXPORT QgsJsonEditWidget : public QWidget, private Ui::QgsJsonEditWidg
const int SCINTILLA_UNDERLINE_INDICATOR_INDEX = 15;

void refreshTreeView( const QJsonDocument &jsonDocument );
void refreshTreeViewItemValue( const QJsonValue &jsonValue, QTreeWidgetItem *treeWidgetItemParent );
void refreshTreeViewItem( QTreeWidgetItem *treeWidgetItemParent, const QJsonValue &jsonValue );
void refreshTreeViewItemValue( QTreeWidgetItem *treeWidgetItem, const QString &jsonValueString, const QColor &textColor );

QString mJsonText;

FormatJson mFormatJsonMode = FormatJson::Indented;

QStringList mClickableLinkList;

QAction mCopyValueAction;
QAction mCopyKeyAction;
};

#endif // QGSJSONEDITWIDGET_H

0 comments on commit 64e686d

Please sign in to comment.