ResInsight/Fwk/AppFwk/cafUserInterface/cafPdmUiComboBoxEditor.cpp

497 lines
17 KiB
C++
Raw Permalink Normal View History

2012-06-26 09:10:41 -05:00
//##################################################################################################
//
// Custom Visualization Core library
// Copyright (C) 2011-2013 Ceetron AS
//
// This library may be used under the terms of either the GNU General Public License or
// the GNU Lesser General Public License as follows:
//
// GNU General Public License Usage
// This library 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 3 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU General Public License at <<http://www.gnu.org/licenses/gpl.html>>
// for more details.
//
// GNU Lesser General Public License Usage
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// See the GNU Lesser General Public License at <<http://www.gnu.org/licenses/lgpl-2.1.html>>
// for more details.
2012-06-26 09:10:41 -05:00
//
//##################################################################################################
#include "cafPdmUiComboBoxEditor.h"
#include "cafFactory.h"
#include "cafPdmField.h"
2012-06-26 09:10:41 -05:00
#include "cafPdmObject.h"
#include "cafPdmUiFieldEditorHandle.h"
#include "cafQShortenedLabel.h"
#include "cafUiAppearanceSettings.h"
#include "cafUiIconFactory.h"
2012-06-26 09:10:41 -05:00
#include <QApplication>
2012-06-26 09:10:41 -05:00
#include <QComboBox>
2019-10-10 06:33:57 -05:00
#include <QDebug>
2012-06-26 09:10:41 -05:00
#include <QLabel>
#include <QLineEdit>
2019-10-10 06:33:57 -05:00
#include <QListView>
#include <QWheelEvent>
2012-06-26 09:10:41 -05:00
namespace caf
{
2020-06-19 00:53:59 -05:00
CAF_PDM_UI_FIELD_EDITOR_SOURCE_INIT( PdmUiComboBoxEditor );
2012-06-26 09:10:41 -05:00
//--------------------------------------------------------------------------------------------------
2020-06-19 00:53:59 -05:00
///
2012-06-26 09:10:41 -05:00
//--------------------------------------------------------------------------------------------------
2020-06-19 00:53:59 -05:00
void PdmUiComboBoxEditor::configureAndUpdateUi( const QString& uiConfigName )
2012-06-26 09:10:41 -05:00
{
if ( !uiField() ) return;
2020-06-19 00:53:59 -05:00
if ( !m_label.isNull() )
2012-06-26 09:10:41 -05:00
{
2020-06-19 00:53:59 -05:00
PdmUiFieldEditorHandle::updateLabelFromField( m_label, uiConfigName );
2012-06-26 09:10:41 -05:00
}
// Handle attributes
2020-06-19 00:53:59 -05:00
caf::PdmUiObjectHandle* uiObject = uiObj( uiField()->fieldHandle()->ownerObject() );
if ( uiObject )
{
2020-06-19 00:53:59 -05:00
uiObject->editorAttribute( uiField()->fieldHandle(), uiConfigName, &m_attributes );
}
2020-06-19 00:53:59 -05:00
if ( !m_comboBox.isNull() )
{
2020-06-19 00:53:59 -05:00
m_comboBox->setEnabled( !uiField()->isUiReadOnly( uiConfigName ) );
m_comboBox->setToolTip( uiField()->uiToolTip( uiConfigName ) );
QList<PdmOptionItemInfo> options = uiField()->valueOptions();
2020-06-19 00:53:59 -05:00
m_comboBox->blockSignals( true );
m_comboBox->clear();
2020-06-19 00:53:59 -05:00
QListView* listView = dynamic_cast<QListView*>( m_comboBox->view() );
if ( listView )
2019-10-10 06:33:57 -05:00
{
2020-06-19 00:53:59 -05:00
listView->setSpacing( 2 );
2019-10-10 06:33:57 -05:00
}
2020-06-19 00:53:59 -05:00
if ( !options.isEmpty() )
{
2020-06-19 00:53:59 -05:00
for ( const auto& option : options )
{
auto icon = option.icon();
2020-06-19 00:53:59 -05:00
if ( icon )
m_comboBox->addItem( *icon, option.optionUiText() );
else
2020-06-19 00:53:59 -05:00
m_comboBox->addItem( option.optionUiText() );
m_comboBox->setIconSize( m_attributes.iconSize );
}
2020-06-19 00:53:59 -05:00
m_comboBox->setCurrentIndex( uiField()->uiValue().toInt() );
}
else
{
2020-06-19 00:53:59 -05:00
m_comboBox->addItem( uiField()->uiValue().toString() );
m_comboBox->setCurrentIndex( 0 );
}
2020-06-19 00:53:59 -05:00
if ( m_attributes.adjustWidthToContents )
{
2020-06-19 00:53:59 -05:00
m_comboBox->setSizeAdjustPolicy( QComboBox::AdjustToContents );
}
2020-06-19 00:53:59 -05:00
else if ( m_attributes.minimumContentsLength > 0 )
{
m_comboBox->setSizeAdjustPolicy( QComboBox::AdjustToContents );
2020-06-19 00:53:59 -05:00
m_comboBox->setMinimumContentsLength( m_attributes.minimumContentsLength );
// Make sure the popup adjusts to the content even if the widget itself doesn't
QFont font = m_comboBox->view()->font();
2020-06-19 00:53:59 -05:00
int maxTextWidth = 0;
bool labelsElided = false;
2020-06-19 00:53:59 -05:00
for ( const PdmOptionItemInfo& option : options )
{
QString label = option.optionUiText();
2020-06-19 00:53:59 -05:00
if ( label.size() > m_attributes.maximumMenuContentsLength )
{
2020-06-19 00:53:59 -05:00
label.resize( m_attributes.maximumMenuContentsLength );
labelsElided = true;
}
2020-06-19 00:53:59 -05:00
maxTextWidth = std::max( maxTextWidth, QFontMetrics( font ).boundingRect( label ).width() );
}
int marginWidth = m_comboBox->view()->contentsMargins().left() + m_comboBox->view()->contentsMargins().right();
2020-06-19 00:53:59 -05:00
m_comboBox->view()->setMinimumWidth( maxTextWidth + marginWidth );
m_comboBox->view()->setTextElideMode( labelsElided ? Qt::ElideMiddle : Qt::ElideNone );
}
2020-06-19 00:53:59 -05:00
if ( m_attributes.enableEditableContent )
{
2020-06-19 00:53:59 -05:00
m_comboBox->setEditable( true );
if ( !m_attributes.enableAutoComplete )
{
m_comboBox->setCompleter( nullptr );
}
2020-06-19 00:53:59 -05:00
m_comboBox->lineEdit()->setPlaceholderText( m_attributes.placeholderText );
}
if ( m_attributes.notifyWhenTextIsEdited )
{
connect( m_comboBox,
SIGNAL( editTextChanged( const QString& ) ),
this,
SLOT( slotEditTextChanged( const QString& ) ) );
if ( m_interactiveEditText == m_comboBox->lineEdit()->text() && m_interactiveEditCursorPosition > -1 )
{
m_comboBox->lineEdit()->setCursorPosition( m_interactiveEditCursorPosition );
m_comboBox->lineEdit()->deselect();
}
}
2020-06-19 00:53:59 -05:00
if ( m_attributes.minimumWidth != -1 )
{
2020-06-19 00:53:59 -05:00
m_comboBox->setMinimumWidth( m_attributes.minimumWidth );
}
2020-06-19 00:53:59 -05:00
m_comboBox->blockSignals( false );
}
2020-06-19 00:53:59 -05:00
if ( !m_layout.isNull() )
{
2020-06-19 00:53:59 -05:00
if ( m_attributes.showPreviousAndNextButtons )
{
2020-06-19 00:53:59 -05:00
if ( m_previousItemButton.isNull() )
2018-06-11 05:39:26 -05:00
{
2020-06-19 00:53:59 -05:00
m_previousItemButton = new QToolButton( m_placeholder );
connect( m_previousItemButton, SIGNAL( clicked() ), this, SLOT( slotPreviousButtonPressed() ) );
2020-06-19 00:53:59 -05:00
m_previousItemButton->setToolTip( "Previous" );
2018-06-11 05:39:26 -05:00
}
2020-06-19 00:53:59 -05:00
if ( m_nextItemButton.isNull() )
2018-06-11 05:39:26 -05:00
{
2020-06-19 00:53:59 -05:00
m_nextItemButton = new QToolButton( m_placeholder );
connect( m_nextItemButton, SIGNAL( clicked() ), this, SLOT( slotNextButtonPressed() ) );
2020-06-19 00:53:59 -05:00
m_nextItemButton->setToolTip( "Next" );
2018-06-11 05:39:26 -05:00
}
2020-06-19 00:53:59 -05:00
m_layout->insertWidget( 1, m_previousItemButton );
m_layout->insertWidget( 2, m_nextItemButton );
2018-06-11 05:39:26 -05:00
{
QIcon toolButtonIcon;
if ( !m_attributes.previousIcon.isNull() )
{
toolButtonIcon = m_attributes.previousIcon;
}
else
{
toolButtonIcon = UiIconFactory::stepUpIcon();
}
if ( m_comboBox->count() == 0 || m_comboBox->currentIndex() <= 0 )
{
QIcon disabledIcon( toolButtonIcon.pixmap( 16, 16, QIcon::Disabled ) );
m_previousItemButton->setIcon( disabledIcon );
}
else
{
m_previousItemButton->setIcon( toolButtonIcon );
}
2018-06-11 05:39:26 -05:00
}
2018-06-11 05:39:26 -05:00
{
QIcon toolButtonIcon;
if ( !m_attributes.nextIcon.isNull() )
{
toolButtonIcon = m_attributes.nextIcon;
}
else
{
toolButtonIcon = UiIconFactory::stepDownIcon();
}
if ( m_comboBox->count() == 0 || m_comboBox->currentIndex() >= m_comboBox->count() - 1 )
{
QIcon disabledIcon( toolButtonIcon.pixmap( 16, 16, QIcon::Disabled ) );
m_nextItemButton->setIcon( disabledIcon );
}
else
{
m_nextItemButton->setIcon( toolButtonIcon );
}
2018-06-11 05:39:26 -05:00
}
2018-06-11 05:39:26 -05:00
// Update button texts
2020-06-19 00:53:59 -05:00
if ( !m_attributes.nextButtonText.isEmpty() )
2018-06-11 05:39:26 -05:00
{
2020-06-19 00:53:59 -05:00
m_nextItemButton->setToolTip( m_attributes.nextButtonText );
2018-06-11 05:39:26 -05:00
}
2020-06-19 00:53:59 -05:00
if ( !m_attributes.prevButtonText.isEmpty() )
2018-06-11 05:39:26 -05:00
{
2020-06-19 00:53:59 -05:00
m_previousItemButton->setToolTip( m_attributes.prevButtonText );
2018-06-11 05:39:26 -05:00
}
}
2018-06-11 05:39:26 -05:00
else
{
2020-06-19 00:53:59 -05:00
if ( m_previousItemButton )
2018-06-11 05:39:26 -05:00
{
2020-06-19 00:53:59 -05:00
m_layout->removeWidget( m_previousItemButton );
2018-06-11 05:39:26 -05:00
m_previousItemButton->deleteLater();
}
2020-06-19 00:53:59 -05:00
if ( m_nextItemButton )
2018-06-11 05:39:26 -05:00
{
2020-06-19 00:53:59 -05:00
m_layout->removeWidget( m_nextItemButton );
2018-06-11 05:39:26 -05:00
m_nextItemButton->deleteLater();
}
}
}
if ( uiField()->isAutoValueEnabled() )
{
QString highlightColor = UiAppearanceSettings::instance()->autoValueEditorColor();
m_comboBox->setStyleSheet( QString( "QComboBox {background-color: %1;}" ).arg( highlightColor ) );
}
else
{
m_comboBox->setStyleSheet( "" );
}
if ( uiField()->isAutoValueSupported() )
{
auto icon = UiIconFactory::createTwoStateChainIcon();
m_autoValueToolButton->setIcon( icon );
m_autoValueToolButton->setChecked( uiField()->isAutoValueEnabled() );
QString tooltipText = uiField()->isAutoValueEnabled() ? UiAppearanceSettings::globaleValueButtonText()
: UiAppearanceSettings::localValueButtonText();
m_autoValueToolButton->setToolTip( tooltipText );
m_layout->insertWidget( 3, m_autoValueToolButton );
m_autoValueToolButton->show();
}
else
{
m_layout->removeWidget( m_autoValueToolButton );
m_autoValueToolButton->hide();
}
2012-06-26 09:10:41 -05:00
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QMargins PdmUiComboBoxEditor::calculateLabelContentMargins() const
{
QSize editorSize = m_comboBox->sizeHint();
QSize labelSize = m_label->sizeHint();
2020-06-19 00:53:59 -05:00
int heightDiff = editorSize.height() - labelSize.height();
QMargins contentMargins = m_label->contentsMargins();
2020-06-19 00:53:59 -05:00
if ( heightDiff > 0 )
{
2020-06-19 00:53:59 -05:00
contentMargins.setTop( contentMargins.top() + heightDiff / 2 );
contentMargins.setBottom( contentMargins.bottom() + heightDiff / 2 );
}
return contentMargins;
}
//--------------------------------------------------------------------------------------------------
// Special class used to prevent a combo box to steal focus when scrolling
// the QScrollArea using the mouse wheel
//
// Based on
// http://stackoverflow.com/questions/5821802/qspinbox-inside-a-qscrollarea-how-to-prevent-spin-box-from-stealing-focus-when
//--------------------------------------------------------------------------------------------------
class CustomQComboBox : public QComboBox
{
public:
2020-06-19 00:53:59 -05:00
explicit CustomQComboBox( QWidget* parent = nullptr )
: QComboBox( parent )
{
}
//--------------------------------------------------------------------------------------------------
2020-06-19 00:53:59 -05:00
///
//--------------------------------------------------------------------------------------------------
2020-06-19 00:53:59 -05:00
void wheelEvent( QWheelEvent* e ) override
{
2020-06-19 00:53:59 -05:00
if ( hasFocus() )
{
2020-06-19 00:53:59 -05:00
QComboBox::wheelEvent( e );
}
else
{
// Ignore the event to make sure event is handled by another widget
e->ignore();
}
}
protected:
//--------------------------------------------------------------------------------------------------
2020-06-19 00:53:59 -05:00
///
//--------------------------------------------------------------------------------------------------
2020-06-19 00:53:59 -05:00
void focusInEvent( QFocusEvent* e ) override
{
2020-06-19 00:53:59 -05:00
setFocusPolicy( Qt::WheelFocus );
QComboBox::focusInEvent( e );
}
//--------------------------------------------------------------------------------------------------
2020-06-19 00:53:59 -05:00
///
//--------------------------------------------------------------------------------------------------
2020-06-19 00:53:59 -05:00
void focusOutEvent( QFocusEvent* e ) override
{
2020-06-19 00:53:59 -05:00
setFocusPolicy( Qt::StrongFocus );
QComboBox::focusOutEvent( e );
}
};
2012-06-26 09:10:41 -05:00
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
PdmUiComboBoxEditor::PdmUiComboBoxEditor()
: m_interactiveEditCursorPosition( -1 )
{
}
2012-06-26 09:10:41 -05:00
//--------------------------------------------------------------------------------------------------
2020-06-19 00:53:59 -05:00
///
2012-06-26 09:10:41 -05:00
//--------------------------------------------------------------------------------------------------
2020-06-19 00:53:59 -05:00
QWidget* PdmUiComboBoxEditor::createEditorWidget( QWidget* parent )
2012-06-26 09:10:41 -05:00
{
2020-06-19 00:53:59 -05:00
m_comboBox = new CustomQComboBox( parent );
m_comboBox->setFocusPolicy( Qt::StrongFocus );
2020-06-19 00:53:59 -05:00
m_placeholder = new QWidget( parent );
2020-06-19 00:53:59 -05:00
m_layout = new QHBoxLayout( m_placeholder );
m_layout->setContentsMargins( 0, 0, 0, 0 );
m_layout->setSpacing( 0 );
m_layout->addWidget( m_comboBox );
2020-06-19 00:53:59 -05:00
connect( m_comboBox, SIGNAL( activated( int ) ), this, SLOT( slotIndexActivated( int ) ) );
m_autoValueToolButton = new QToolButton( m_placeholder );
m_autoValueToolButton->setCheckable( true );
m_autoValueToolButton->setToolButtonStyle( Qt::ToolButtonIconOnly );
connect( m_autoValueToolButton, SIGNAL( clicked() ), this, SLOT( slotApplyAutoValue() ) );
// Forward focus event to combo box editor
m_placeholder->setFocusProxy( m_comboBox );
return m_placeholder;
2012-06-26 09:10:41 -05:00
}
//--------------------------------------------------------------------------------------------------
2020-06-19 00:53:59 -05:00
///
2012-06-26 09:10:41 -05:00
//--------------------------------------------------------------------------------------------------
2020-06-19 00:53:59 -05:00
QWidget* PdmUiComboBoxEditor::createLabelWidget( QWidget* parent )
2012-06-26 09:10:41 -05:00
{
2020-06-19 00:53:59 -05:00
m_label = new QShortenedLabel( parent );
2012-06-26 09:10:41 -05:00
return m_label;
}
//--------------------------------------------------------------------------------------------------
2020-06-19 00:53:59 -05:00
///
2012-06-26 09:10:41 -05:00
//--------------------------------------------------------------------------------------------------
2020-06-19 00:53:59 -05:00
void PdmUiComboBoxEditor::slotIndexActivated( int index )
2012-06-26 09:10:41 -05:00
{
if ( !uiField() ) return;
uiField()->enableAutoValue( false );
2020-06-19 00:53:59 -05:00
if ( m_attributes.enableEditableContent )
{
// Use the text directly, as the item text could be entered directly by the user
2012-06-26 09:10:41 -05:00
2020-06-19 00:53:59 -05:00
auto text = m_comboBox->itemText( index );
this->setValueToField( text );
}
else
{
// Use index as data carrier to PDM field
// The index will be used as a lookup in a list of option items
QVariant v;
v = index;
2020-06-19 00:53:59 -05:00
QVariant uintValue( v.toUInt() );
this->setValueToField( uintValue );
}
2012-06-26 09:10:41 -05:00
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiComboBoxEditor::slotEditTextChanged( const QString& text )
{
if ( !uiField() ) return;
if ( text == m_interactiveEditText ) return;
uiField()->enableAutoValue( false );
m_interactiveEditText = text;
m_interactiveEditCursorPosition = m_comboBox->lineEdit()->cursorPosition();
this->setValueToField( text );
}
//--------------------------------------------------------------------------------------------------
2020-06-19 00:53:59 -05:00
///
//--------------------------------------------------------------------------------------------------
void PdmUiComboBoxEditor::slotNextButtonPressed()
{
int indexCandidate = m_comboBox->currentIndex() + 1;
2020-06-19 00:53:59 -05:00
if ( indexCandidate < m_comboBox->count() )
{
2020-06-19 00:53:59 -05:00
slotIndexActivated( indexCandidate );
}
}
//--------------------------------------------------------------------------------------------------
2020-06-19 00:53:59 -05:00
///
//--------------------------------------------------------------------------------------------------
void PdmUiComboBoxEditor::slotPreviousButtonPressed()
{
int indexCandidate = m_comboBox->currentIndex() - 1;
2020-06-19 00:53:59 -05:00
if ( indexCandidate > -1 && indexCandidate < m_comboBox->count() )
{
2020-06-19 00:53:59 -05:00
slotIndexActivated( indexCandidate );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void PdmUiComboBoxEditor::slotApplyAutoValue()
{
if ( !uiField() ) return;
bool enable = m_autoValueToolButton->isChecked();
uiField()->enableAutoValue( enable );
configureAndUpdateUi( "" );
}
2012-06-26 09:10:41 -05:00
} // end namespace caf