Skip to content

Commit

Permalink
drad'n'drop improvents
Browse files Browse the repository at this point in the history
part 2

display the container editor in the right panel
this avoids opening a modal dialog

a new type of itemData has been added as WidgetType
to distinguish them in the available widgets from the containers in the form layout

fixes qgis#29063
  • Loading branch information
3nids committed Feb 12, 2020
1 parent 2770e6a commit 935dc28
Show file tree
Hide file tree
Showing 7 changed files with 312 additions and 84 deletions.
3 changes: 3 additions & 0 deletions src/app/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,8 @@ SET(QGIS_APP_SRCS
qgsmaptoolsvgannotation.cpp
qgsmaptooltextannotation.cpp

attributeformconfig/qgsattributeformcontaineredit.cpp

decorations/qgsdecorationitem.cpp
decorations/qgsdecorationtitle.cpp
decorations/qgsdecorationtitledialog.cpp
Expand Down Expand Up @@ -392,6 +394,7 @@ INCLUDE_DIRECTORIES(
${CMAKE_SOURCE_DIR}/external

${CMAKE_SOURCE_DIR}/src/app
${CMAKE_SOURCE_DIR}/src/app/attributeformconfig
${CMAKE_SOURCE_DIR}/src/app/decorations
${CMAKE_SOURCE_DIR}/src/app/labeling
${CMAKE_SOURCE_DIR}/src/app/layout
Expand Down
71 changes: 71 additions & 0 deletions src/app/attributeformconfig/qgsattributeformcontaineredit.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/***************************************************************************
qgsattributeformcontaineredit.cpp
---------------------
begin : February 2020
copyright : (C) 2020 Denis Rouzaud
email : denis@opengis.ch
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "qgsattributeformcontaineredit.h"
#include "ui_qgsattributeformcontaineredit.h"
#include "qgsattributesformproperties.h"


QgsAttributeFormContainerEdit::QgsAttributeFormContainerEdit( QTreeWidgetItem *item, QWidget *parent )
: QWidget( parent )
, mTreeItem( item )

{
setupUi( this );



const QgsAttributesFormProperties::DnDTreeItemData itemData = mTreeItem->data( 0, QgsAttributesFormProperties::DnDTreeRole ).value<QgsAttributesFormProperties::DnDTreeItemData>();
Q_ASSERT( itemData.type() == QgsAttributesFormProperties::DnDTreeItemData::Container );

if ( item->parent() )
{
// only top level items can be tabs
// i.e. it's always a group box if it's a nested container
mShowAsGroupBoxCheckBox->hide();
}

mTitleLineEdit->setText( itemData.name() );
mShowLabelCheckBox->setChecked( itemData.showLabel() );
mShowLabelCheckBox->setEnabled( itemData.showAsGroupBox() ); // show label makes sense for group box, not for tabs
mShowAsGroupBoxCheckBox->setChecked( itemData.showAsGroupBox() );

mControlVisibilityGroupBox->setChecked( itemData.visibilityExpression().enabled() );
mVisibilityExpressionWidget->setExpression( itemData.visibilityExpression()->expression() );
mColumnCountSpinBox->setValue( itemData.columnCount() );
mBackgroundColorButton->setColor( itemData.backgroundColor() );

// show label makes sense for group box, not for tabs
connect( mShowAsGroupBoxCheckBox, &QCheckBox::stateChanged, mShowLabelCheckBox, &QCheckBox::setEnabled );
}

void QgsAttributeFormContainerEdit::updateItemData()
{
QgsAttributesFormProperties::DnDTreeItemData itemData = mTreeItem->data( 0, QgsAttributesFormProperties::DnDTreeRole ).value<QgsAttributesFormProperties::DnDTreeItemData>();

itemData.setColumnCount( mColumnCountSpinBox->value() );
itemData.setShowAsGroupBox( mShowAsGroupBoxCheckBox->isVisible() ? mShowAsGroupBoxCheckBox->isChecked() : true );
itemData.setName( mTitleLineEdit->text() );
itemData.setShowLabel( mShowLabelCheckBox->isChecked() );
itemData.setBackgroundColor( mBackgroundColorButton->color() );

QgsOptionalExpression visibilityExpression;
visibilityExpression.setData( QgsExpression( mVisibilityExpressionWidget->expression() ) );
visibilityExpression.setEnabled( mControlVisibilityGroupBox->isChecked() );
itemData.setVisibilityExpression( visibilityExpression );

mTreeItem->setData( 0, QgsAttributesFormProperties::DnDTreeRole, itemData );
mTreeItem->setText( 0, itemData.name() );
}
45 changes: 45 additions & 0 deletions src/app/attributeformconfig/qgsattributeformcontaineredit.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/***************************************************************************
qgsattributeformcontaineredit.h
---------------------
begin : February 2020
copyright : (C) 2020 Denis Rouzaud
email : denis@opengis.ch
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#ifndef QGSATTRIBUTEFORMCONTAINEREDIT_H
#define QGSATTRIBUTEFORMCONTAINEREDIT_H

#include <QWidget>

#include "ui_qgsattributeformcontaineredit.h"

#include "qgis_app.h"

class QTreeWidgetItem;

/**
* Widget to edit a container (tab or group box) of a form configuration
*/
class APP_EXPORT QgsAttributeFormContainerEdit: public QWidget, private Ui_QgsAttributeFormContainerEdit
{
Q_OBJECT

public:
explicit QgsAttributeFormContainerEdit( QTreeWidgetItem *item, QWidget *parent = nullptr );


void updateItemData();


private:
QTreeWidgetItem *mTreeItem;
};

#endif // QGSATTRIBUTEFORMCONTAINEREDIT_H
131 changes: 52 additions & 79 deletions src/app/qgsattributesformproperties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include "qgsattributesformproperties.h"
#include "qgsattributetypedialog.h"
#include "qgsattributeformcontaineredit.h"
#include "qgsattributerelationedit.h"
#include "qgsattributesforminitcode.h"
#include "qgisapp.h"
Expand All @@ -25,6 +26,7 @@
#include "qgscolorbutton.h"
#include "qgscodeeditorhtml.h"


QgsAttributesFormProperties::QgsAttributesFormProperties( QgsVectorLayer *layer, QWidget *parent )
: QWidget( parent )
, mLayer( layer )
Expand Down Expand Up @@ -95,7 +97,7 @@ void QgsAttributesFormProperties::initAvailableWidgetsTree()

//load Fields

DnDTreeItemData catItemData = DnDTreeItemData( DnDTreeItemData::Container, QStringLiteral( "Fields" ), QStringLiteral( "Fields" ) );
DnDTreeItemData catItemData = DnDTreeItemData( DnDTreeItemData::WidgetType, QStringLiteral( "Fields" ), QStringLiteral( "Fields" ) );
QTreeWidgetItem *catitem = mAvailableWidgetsTree->addItem( mAvailableWidgetsTree->invisibleRootItem(), catItemData );

const QgsFields fields = mLayer->fields();
Expand All @@ -122,7 +124,7 @@ void QgsAttributesFormProperties::initAvailableWidgetsTree()
catitem->setExpanded( true );

//load Relations
catItemData = DnDTreeItemData( DnDTreeItemData::Container, QStringLiteral( "Relations" ), tr( "Relations" ) );
catItemData = DnDTreeItemData( DnDTreeItemData::WidgetType, QStringLiteral( "Relations" ), tr( "Relations" ) );
catitem = mAvailableWidgetsTree->addItem( mAvailableWidgetsTree->invisibleRootItem(), catItemData );

const QList<QgsRelation> relations = QgsProject::instance()->relationManager()->referencedRelations( mLayer );
Expand All @@ -141,7 +143,7 @@ void QgsAttributesFormProperties::initAvailableWidgetsTree()
catitem->setExpanded( true );

// QML/HTML widget
catItemData = DnDTreeItemData( DnDTreeItemData::Container, QStringLiteral( "Other" ), tr( "Other Widgets" ) );
catItemData = DnDTreeItemData( DnDTreeItemData::WidgetType, QStringLiteral( "Other" ), tr( "Other Widgets" ) );
catitem = mAvailableWidgetsTree->addItem( mAvailableWidgetsTree->invisibleRootItem(), catItemData );

DnDTreeItemData itemData = DnDTreeItemData( DnDTreeItemData::QmlWidget, QStringLiteral( "QmlWidget" ), tr( "QML Widget" ) );
Expand Down Expand Up @@ -406,6 +408,27 @@ void QgsAttributesFormProperties::storeAttributeRelationEdit()
}
}

void QgsAttributesFormProperties::storeAttributeContainerEdit()
{
if ( !mAttributeContainerEdit )
return;

mAttributeContainerEdit->updateItemData();
}

void QgsAttributesFormProperties::loadAttributeContainerEdit()
{
clearAttributeTypeFrame();

if ( mFormLayoutTree->selectedItems().count() != 1 )
return;

QTreeWidgetItem *currentItem = mFormLayoutTree->selectedItems().at( 0 );
mAttributeContainerEdit = new QgsAttributeFormContainerEdit( currentItem, this );
mAttributeTypeFrame->layout()->setMargin( 0 );
mAttributeTypeFrame->layout()->addWidget( mAttributeContainerEdit );
}

QgsAttributesFormProperties::RelationConfig QgsAttributesFormProperties::configForRelation( const QString &relationId )
{
QTreeWidgetItemIterator itemIt( mAvailableWidgetsTree );
Expand Down Expand Up @@ -510,22 +533,23 @@ QTreeWidgetItem *QgsAttributesFormProperties::loadAttributeEditorTreeItem( QgsAt
void QgsAttributesFormProperties::onAttributeSelectionChanged()
{
disconnect( mFormLayoutTree, &QTreeWidget::itemSelectionChanged, this, &QgsAttributesFormProperties::onFormLayoutSelectionChanged );
synchronizeDnDTrees( mAvailableWidgetsTree, mFormLayoutTree );
loadAttributeSpecificEditor( mAvailableWidgetsTree, mFormLayoutTree );
connect( mFormLayoutTree, &QTreeWidget::itemSelectionChanged, this, &QgsAttributesFormProperties::onFormLayoutSelectionChanged );
}

void QgsAttributesFormProperties::onFormLayoutSelectionChanged()
{
// when the selection changes in the DnD layout, sync the main tree
disconnect( mAvailableWidgetsTree, &QTreeWidget::itemSelectionChanged, this, &QgsAttributesFormProperties::onAttributeSelectionChanged );
synchronizeDnDTrees( mFormLayoutTree, mAvailableWidgetsTree );
loadAttributeSpecificEditor( mFormLayoutTree, mAvailableWidgetsTree );
connect( mAvailableWidgetsTree, &QTreeWidget::itemSelectionChanged, this, &QgsAttributesFormProperties::onAttributeSelectionChanged );
}

void QgsAttributesFormProperties::synchronizeDnDTrees( DnDTree *emitter, DnDTree *receiver )
void QgsAttributesFormProperties::loadAttributeSpecificEditor( DnDTree *emitter, DnDTree *receiver )
{
storeAttributeTypeDialog();
storeAttributeRelationEdit();
storeAttributeContainerEdit();

if ( emitter->selectedItems().count() != 1 )
{
Expand All @@ -550,6 +574,13 @@ void QgsAttributesFormProperties::synchronizeDnDTrees( DnDTree *emitter, DnDTree
break;
}
case DnDTreeItemData::Container:
{
receiver->clearSelection();
loadAttributeContainerEdit();
break;
}

case DnDTreeItemData::WidgetType:
case DnDTreeItemData::QmlWidget:
case DnDTreeItemData::HtmlWidget:
{
Expand All @@ -575,6 +606,12 @@ void QgsAttributesFormProperties::clearAttributeTypeFrame()
mAttributeRelationEdit->deleteLater();
mAttributeRelationEdit = nullptr;
}
if ( mAttributeContainerEdit )
{
mAttributeTypeFrame->layout()->removeWidget( mAttributeContainerEdit );
mAttributeContainerEdit->deleteLater();
mAttributeContainerEdit = nullptr;
}
}

void QgsAttributesFormProperties::onInvertSelectionButtonClicked( bool checked )
Expand Down Expand Up @@ -682,6 +719,9 @@ QgsAttributeEditorElement *QgsAttributesFormProperties::createAttributeEditorWid
break;
}

case DnDTreeItemData::WidgetType:
break;

}

widgetDef->setShowLabel( itemData.showLabel() );
Expand Down Expand Up @@ -754,7 +794,7 @@ void QgsAttributesFormProperties::pbnSelectEditForm_clicked()

void QgsAttributesFormProperties::apply()
{

storeAttributeContainerEdit();
storeAttributeTypeDialog();
storeAttributeRelationEdit();

Expand Down Expand Up @@ -941,6 +981,9 @@ QTreeWidgetItem *DnDTree::addItem( QTreeWidgetItem *parent, QgsAttributesFormPro
case QgsAttributesFormProperties::DnDTreeItemData::HtmlWidget:
//no icon for HtmlWidget
break;

case QgsAttributesFormProperties::DnDTreeItemData::WidgetType:
break;
}
}
newItem->setData( 0, QgsAttributesFormProperties::DnDTreeRole, data );
Expand Down Expand Up @@ -1099,78 +1142,8 @@ void DnDTree::onItemDoubleClicked( QTreeWidgetItem *item, int column )
switch ( itemData.type() )
{
case QgsAttributesFormProperties::DnDTreeItemData::Container:
{
QDialog dlg;
dlg.setObjectName( QLatin1String( "attributeFormPropertiesContainerDialog" ) );
dlg.setWindowTitle( tr( "Configure Container" ) );
QFormLayout *layout = new QFormLayout() ;
dlg.setLayout( layout );
layout->addRow( baseWidget );

QCheckBox *showAsGroupBox = nullptr;
QLineEdit *title = new QLineEdit( itemData.name() );
QSpinBox *columnCount = new QSpinBox();
QGroupBox *visibilityExpressionGroupBox = new QGroupBox( tr( "Control visibility by expression" ) );
visibilityExpressionGroupBox->setCheckable( true );
visibilityExpressionGroupBox->setChecked( itemData.visibilityExpression().enabled() );
visibilityExpressionGroupBox->setLayout( new QGridLayout );
QgsFieldExpressionWidget *visibilityExpressionWidget = new QgsFieldExpressionWidget;
visibilityExpressionWidget->setLayer( mLayer );
visibilityExpressionWidget->setExpressionDialogTitle( tr( "Visibility Expression" ) );
visibilityExpressionWidget->setExpression( itemData.visibilityExpression()->expression() );
visibilityExpressionGroupBox->layout()->addWidget( visibilityExpressionWidget );

columnCount->setRange( 1, 5 );
columnCount->setValue( itemData.columnCount() );

layout->addRow( tr( "Title" ), title );
layout->addRow( tr( "Number of columns" ), columnCount );
layout->addRow( visibilityExpressionGroupBox );

if ( !item->parent() )
{
showAsGroupBox = new QCheckBox( tr( "Show as group box" ) );
showAsGroupBox->setChecked( itemData.showAsGroupBox() );
layout->addRow( showAsGroupBox );
}

QgsCollapsibleGroupBox *styleGroupBox = new QgsCollapsibleGroupBox( tr( "Style" ), layout->widget() );
styleGroupBox->setObjectName( QLatin1String( "attributeFormPropertiesContainerStyle" ) );
QFormLayout *customizeGroupBoxLayout = new QFormLayout( styleGroupBox ) ;
QgsColorButton *backgroundColorButton = new QgsColorButton( styleGroupBox, tr( "Container Background Color" ) );
backgroundColorButton->setShowNull( true );
backgroundColorButton->setColor( itemData.backgroundColor() );
customizeGroupBoxLayout->addRow( new QLabel( tr( "Background color" ), styleGroupBox ),
backgroundColorButton );
styleGroupBox->setLayout( customizeGroupBoxLayout );
layout->addRow( styleGroupBox );

QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok
| QDialogButtonBox::Cancel );

connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );

layout->addWidget( buttonBox );

if ( dlg.exec() )
{
itemData.setColumnCount( columnCount->value() );
itemData.setShowAsGroupBox( showAsGroupBox ? showAsGroupBox->isChecked() : true );
itemData.setName( title->text() );
itemData.setShowLabel( showLabelCheckbox->isChecked() );
itemData.setBackgroundColor( backgroundColorButton->color() );

QgsOptionalExpression visibilityExpression;
visibilityExpression.setData( QgsExpression( visibilityExpressionWidget->expression() ) );
visibilityExpression.setEnabled( visibilityExpressionGroupBox->isChecked() );
itemData.setVisibilityExpression( visibilityExpression );

item->setData( 0, QgsAttributesFormProperties::DnDTreeRole, itemData );
item->setText( 0, title->text() );
}
}
break;
case QgsAttributesFormProperties::DnDTreeItemData::WidgetType:
break;

case QgsAttributesFormProperties::DnDTreeItemData::Relation:
{
Expand Down
Loading

0 comments on commit 935dc28

Please sign in to comment.