diff --git a/libs/gtkutil/nonmodal.h b/libs/gtkutil/nonmodal.h index 692b8b53..29f7d53a 100644 --- a/libs/gtkutil/nonmodal.h +++ b/libs/gtkutil/nonmodal.h @@ -39,8 +39,8 @@ public: // triggered on enter & focus out; need to track editing state, as nonedited triggers this too QObject::connect( this, &QLineEdit::editingFinished, [this](){ if( m_editing ){ - m_apply(); m_editing = false; + m_apply(); } clearFocus(); } ); @@ -80,6 +80,7 @@ public: void setCallbacks( const Callback& apply, const Callback& cancel ){ m_apply = apply; m_cancel = cancel; + QObject::connect( lineEdit(), &QLineEdit::textEdited, [this](){ m_editing = true; } ); // triggered on enter & focus out; need to track editing state, as nonedited triggers this too QObject::connect( this, &QAbstractSpinBox::editingFinished, [this](){ if( m_editing ){ @@ -88,9 +89,6 @@ public: } clearFocus(); } ); - QObject::connect( lineEdit(), &QLineEdit::textEdited, [this](){ - m_editing = true; - } ); } bool event( QEvent *event ) override { if( event->type() == QEvent::ShortcutOverride ){ diff --git a/radiant/entityinspector.cpp b/radiant/entityinspector.cpp index b3882e99..4e679f54 100644 --- a/radiant/entityinspector.cpp +++ b/radiant/entityinspector.cpp @@ -51,6 +51,7 @@ #include #include #include +#include #include "gtkutil/combobox.h" #include "os/path.h" @@ -108,6 +109,44 @@ void Scene_EntitySetKeyValue_Selected_Undoable( const char* key, const char* val Scene_EntitySetKeyValue_Selected( key, value ); } + +class KeyValueValidator : public QValidator +{ + QWidget *m_parent; +public: + KeyValueValidator( QWidget *parent ) : QValidator( parent ), m_parent( parent ){ + } + QValidator::State validate( QString& input, int &pos ) const override { + auto it = std::remove_if( input.begin(), input.end(), []( QChar c ){ + return strchr( "\n\r\"", c.toLatin1() ) != nullptr; + } ); + if( it != input.end() ){ + input.chop( std::distance( it, input.end() ) ); + QToolTip::showText( m_parent->mapToGlobal( m_parent->rect().bottomLeft() ), "No newlines & quotes are allowed in entity key values.", m_parent ); + } + return QValidator::State::Acceptable; + } +}; + +class KeyNameValidator : public QValidator +{ + QWidget *m_parent; +public: + KeyNameValidator( QWidget *parent ) : QValidator( parent ), m_parent( parent ){ + } + QValidator::State validate( QString& input, int &pos ) const override { + auto it = std::remove_if( input.begin(), input.end(), []( QChar c ){ + return strchr( " \n\r\t\v\"", c.toLatin1() ) != nullptr; + } ); + if( it != input.end() ){ + input.chop( std::distance( it, input.end() ) ); + QToolTip::showText( m_parent->mapToGlobal( m_parent->rect().bottomLeft() ), "No spaces, newlines, tabs, quotes are allowed in entity key names.", m_parent ); + } + return QValidator::State::Acceptable; + } +}; + + class EntityAttribute { public: @@ -155,6 +194,7 @@ public: StringAttribute( const char* key ) : m_key( key ), m_entry( new NonModalEntry( ApplyCaller( *this ), UpdateCaller( *this ) ) ){ + m_entry->setValidator( new KeyValueValidator( m_entry ) ); } virtual ~StringAttribute() = default; QWidget* getWidget() const override { @@ -207,6 +247,7 @@ public: ColorAttribute( const char* key ) : m_key( key ), m_entry( new NonModalEntry( ApplyCaller( *this ), UpdateCaller( *this ) ) ){ + m_entry->setValidator( new KeyValueValidator( m_entry ) ); auto button = m_entry->addAction( QApplication::style()->standardIcon( QStyle::SP_ArrowRight ), QLineEdit::ActionPosition::TrailingPosition ); QObject::connect( button, &QAction::triggered, [this](){ browse(); } ); } @@ -245,6 +286,7 @@ public: ModelAttribute( const char* key ) : m_key( key ), m_entry( new NonModalEntry( ApplyCaller( *this ), UpdateCaller( *this ) ) ){ + m_entry->setValidator( new KeyValueValidator( m_entry ) ); auto button = m_entry->addAction( QApplication::style()->standardIcon( QStyle::SP_DialogOpenButton ), QLineEdit::ActionPosition::TrailingPosition ); QObject::connect( button, &QAction::triggered, [this](){ browse(); } ); } @@ -308,6 +350,7 @@ public: SoundAttribute( const char* key ) : m_key( key ), m_entry( new NonModalEntry( ApplyCaller( *this ), UpdateCaller( *this ) ) ){ + m_entry->setValidator( new KeyValueValidator( m_entry ) ); auto button = m_entry->addAction( QApplication::style()->standardIcon( QStyle::SP_MediaVolume ), QLineEdit::ActionPosition::TrailingPosition ); QObject::connect( button, &QAction::triggered, [this](){ browse(); } ); } @@ -1049,15 +1092,6 @@ void EntityInspector_applyKeyValue(){ // return; // } - // RR2DO2: we don't want spaces and special symbols in entity keys - if ( std::any_of( key.cbegin(), key.cend(), []( const char c ){ return strchr( " \n\r\t\v\"", c ) != nullptr; } ) ) { - qt_MessageBox( g_entityKeyEntry->window(), "No spaces, newlines, tabs, quotes are allowed in entity key names." ); - return; - } - if ( std::any_of( value.cbegin(), value.cend(), []( const char c ){ return strchr( "\n\r\"", c ) != nullptr; } ) ) { - qt_MessageBox( g_entityKeyEntry->window(), "No newlines & quotes are allowed in entity key values." ); - return; - } // avoid empty key name; empty value is okay: deletes key if( key.isEmpty() ) return; @@ -1247,12 +1281,14 @@ QWidget* EntityInspector_constructWindow( QWidget* toplevel ){ auto line = g_entityKeyEntry = new LineEdit; grid->addWidget( line, 0, 1 ); QObject::connect( line, &QLineEdit::returnPressed, [](){ g_entityValueEntry->setFocus(); g_entityValueEntry->selectAll(); } ); + line->setValidator( new KeyNameValidator( line ) ); } { auto line = g_entityValueEntry = new LineEdit; grid->addWidget( line, 1, 1 ); QObject::connect( line, &QLineEdit::returnPressed, [](){ EntityInspector_applyKeyValue(); } ); + line->setValidator( new KeyValueValidator( line ) ); } /* select by key/value buttons */ {