From 186b18587be1fb1d0b9be31c0b1d48f906d9641a Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Fri, 1 Jun 2018 12:00:31 +0200 Subject: [PATCH] QskInputManager introduced --- src/inputpanel/QskInputContext.cpp | 111 +++++++++-------------- src/inputpanel/QskInputContext.h | 29 +++--- src/inputpanel/QskInputManager.cpp | 138 +++++++++++++++++++++++++++++ src/inputpanel/QskInputManager.h | 46 ++++++++++ 4 files changed, 241 insertions(+), 83 deletions(-) create mode 100644 src/inputpanel/QskInputManager.cpp create mode 100644 src/inputpanel/QskInputManager.h diff --git a/src/inputpanel/QskInputContext.cpp b/src/inputpanel/QskInputContext.cpp index b1f84019..c841a398 100644 --- a/src/inputpanel/QskInputContext.cpp +++ b/src/inputpanel/QskInputContext.cpp @@ -4,8 +4,7 @@ *****************************************************************************/ #include "QskInputContext.h" -#include "QskInputPanel.h" -#include "QskInputEngine.h" +#include "QskInputManager.h" #include "QskLinearBox.h" #include "QskDialog.h" @@ -69,22 +68,19 @@ class QskInputContext::PrivateData public: // item receiving the input QPointer< QQuickItem > inputItem; - QPointer< QskInputPanel > inputPanel; // popup or window embedding the panel QskPopup* inputPopup = nullptr; QskWindow* inputWindow = nullptr; - QskInputEngine* engine = nullptr; - - bool isPredictorDirty = true; + QskInputManager* inputManager = nullptr; }; QskInputContext::QskInputContext(): m_data( new PrivateData() ) { setObjectName( "InputContext" ); - m_data->engine = new QskInputEngine( this ); + m_data->inputManager = new QskInputManager( this ); } QskInputContext::~QskInputContext() @@ -96,25 +92,22 @@ QQuickItem* QskInputContext::inputItem() const return m_data->inputItem; } -QskInputPanel* QskInputContext::inputPanel() const +QskControl* QskInputContext::inputPanel() const { - if ( m_data->inputPanel == nullptr ) - { - auto that = const_cast< QskInputContext* >( this ); + auto panel = m_data->inputManager->panel( true ); - auto panel = new QskInputPanel(); - panel->setParent( that ); + if ( panel->parent() != this ) + { + panel->setParent( const_cast< QskInputContext* >( this ) ); connect( panel, &QQuickItem::visibleChanged, - this, &QskInputContext::activeChanged ); - - connect( panel, &QskControl::localeChanged, - this, &QskInputContext::updateLocale ); + this, &QskInputContext::activeChanged, Qt::UniqueConnection ); - m_data->inputPanel = panel; + connect( panel, &QskControl::localeChanged, + this, [] { qskSendToPlatformContext( QEvent::LocaleChange ); } ); } - return m_data->inputPanel; + return panel; } void QskInputContext::update( Qt::InputMethodQueries queries ) @@ -131,8 +124,7 @@ void QskInputContext::update( Qt::InputMethodQueries queries ) } } - if ( auto panel = inputPanel() ) - panel->processInputMethodQueries( queries ); + m_data->inputManager->processInputMethodQueries( queries ); } QRectF QskInputContext::panelRect() const @@ -143,7 +135,7 @@ QRectF QskInputContext::panelRect() const return QRectF(); } -QskPopup* QskInputContext::createEmbeddingPopup( QskInputPanel* panel ) +QskPopup* QskInputContext::createEmbeddingPopup( QskControl* panel ) { auto popup = new QskPopup(); @@ -154,24 +146,35 @@ QskPopup* QskInputContext::createEmbeddingPopup( QskInputPanel* panel ) auto box = new QskLinearBox( popup ); box->addItem( panel ); - /* - When the panel has an input proxy ( usually a local text input ) - we don't need to see the input item and display the overlay - and align in the center of the window. - */ - const bool hasInputProxy = panel->hasInputProxy(); + const auto alignment = + m_data->inputManager->panelAlignment() & Qt::AlignVertical_Mask; - popup->setOverlay( hasInputProxy ); + popup->setOverlay( alignment == Qt::AlignVCenter ); - if ( hasInputProxy ) - box->setMargins( QMarginsF( 5, 5, 5, 5 ) ); - else - box->setExtraSpacingAt( Qt::TopEdge | Qt::LeftEdge | Qt::RightEdge ); + switch( alignment ) + { + case Qt::AlignTop: + { + box->setExtraSpacingAt( Qt::BottomEdge | Qt::LeftEdge | Qt::RightEdge ); + break; + } + case Qt::AlignVCenter: + { + box->setMargins( QMarginsF( 5, 5, 5, 5 ) ); + break; + } + + case Qt::AlignBottom: + default: + { + box->setExtraSpacingAt( Qt::TopEdge | Qt::LeftEdge | Qt::RightEdge ); + } + } return popup; } -QskWindow* QskInputContext::createEmbeddingWindow( QskInputPanel* panel ) +QskWindow* QskInputContext::createEmbeddingWindow( QskControl* panel ) { auto window = new QskWindow(); @@ -254,16 +257,12 @@ void QskInputContext::showPanel() popup->setVisible( true ); popup->installEventFilter( this ); } - + m_data->inputPopup = popup; } } - updatePredictor(); - - panel->setLocale( locale() ); - panel->attachInputItem( m_data->inputItem ); - panel->setEngine( m_data->engine ); + m_data->inputManager->attachInputItem( m_data->inputItem ); } void QskInputContext::hidePanel() @@ -285,17 +284,13 @@ void QskInputContext::hidePanel() #endif } - if ( auto panel = inputPanel() ) - { + if ( auto panel = m_data->inputManager->panel( false ) ) panel->setParentItem( nullptr ); - panel->attachInputItem( nullptr ); - panel->setEngine( nullptr ); - } + + m_data->inputManager->attachInputItem( nullptr ); if ( m_data->inputPopup ) - { m_data->inputPopup->deleteLater(); - } if ( m_data->inputWindow ) { @@ -341,28 +336,6 @@ QLocale QskInputContext::locale() const return QLocale(); } -void QskInputContext::updateLocale() -{ - m_data->isPredictorDirty = true; - - if ( isActive() ) - updatePredictor(); - - qskSendToPlatformContext( QEvent::LocaleChange ); -} - -void QskInputContext::updatePredictor() -{ - if ( m_data->isPredictorDirty ) - { - if ( m_data->engine ) - { - m_data->engine->setPredictor( textPredictor( locale() ) ); - m_data->isPredictorDirty = false; - } - } -} - void QskInputContext::setFocusObject( QObject* focusObject ) { if ( m_data->inputItem == nullptr || m_data->inputItem == focusObject ) diff --git a/src/inputpanel/QskInputContext.h b/src/inputpanel/QskInputContext.h index 431d1e33..724ea0a3 100644 --- a/src/inputpanel/QskInputContext.h +++ b/src/inputpanel/QskInputContext.h @@ -12,7 +12,8 @@ #include class QskTextPredictor; -class QskInputPanel; +class QskControl; +class QskInputManager; class QskPopup; class QskWindow; class QQuickItem; @@ -27,19 +28,23 @@ public: QskInputContext(); virtual ~QskInputContext(); - virtual QRectF panelRect() const; + void setManager( QskInputManager* ); + QskInputManager manager(); - virtual void setActive( bool ); - virtual bool isActive() const; + QRectF panelRect() const; - virtual QLocale locale() const; + void setActive( bool ); + bool isActive() const; - virtual QQuickItem* inputItem() const; - virtual QskInputPanel* inputPanel() const; + QLocale locale() const; + + QQuickItem* inputItem() const; static QskInputContext* instance(); static void setInstance( QskInputContext* ); + virtual QskTextPredictor* textPredictor( const QLocale& ) const; + Q_SIGNALS: void activeChanged(); void panelRectChanged(); @@ -47,13 +52,13 @@ Q_SIGNALS: protected: virtual bool eventFilter( QObject*, QEvent* ) override; - virtual QskPopup* createEmbeddingPopup( QskInputPanel* ); - virtual QskWindow* createEmbeddingWindow( QskInputPanel* ); + virtual QskPopup* createEmbeddingPopup( QskControl* ); + virtual QskWindow* createEmbeddingWindow( QskControl* ); virtual void showPanel(); virtual void hidePanel(); - virtual QskTextPredictor* textPredictor( const QLocale& ) const; + QskControl* inputPanel() const; private: friend class QskPlatformInputContext; @@ -64,12 +69,8 @@ private: virtual void processClickAt( int cursorPosition ); virtual void commitPrediction( bool ); - void updateLocale(); - void updatePredictor(); - class PrivateData; std::unique_ptr< PrivateData > m_data; }; - #endif diff --git a/src/inputpanel/QskInputManager.cpp b/src/inputpanel/QskInputManager.cpp new file mode 100644 index 00000000..72a5fe5f --- /dev/null +++ b/src/inputpanel/QskInputManager.cpp @@ -0,0 +1,138 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the QSkinny License, Version 1.0 + *****************************************************************************/ + +#include "QskInputManager.h" +#include "QskInputPanel.h" +#include "QskInputEngine.h" +#include "QskInputContext.h" +#include + +class QskInputManager::PrivateData +{ +public: + QPointer< QskInputEngine > engine; + QPointer< QskControl > panel; + + QLocale predictorLocale; +}; + +QskInputManager::QskInputManager( QObject* parent ): + Inherited( parent ), + m_data( new PrivateData() ) +{ +} + +QskInputManager::~QskInputManager() +{ +} + +void QskInputManager::attachInputItem( QQuickItem* item ) +{ + auto panel = qobject_cast< QskInputPanel* >( m_data->panel ); + if ( panel == nullptr ) + return; + + if ( item ) + { + auto context = QskInputContext::instance(); + const auto locale = context->locale(); + + updateEngine( locale ); + + panel->setEngine( m_data->engine ); + panel->setLocale( locale ); + panel->attachInputItem( item ); + } + else + { + panel->setEngine( nullptr ); + panel->attachInputItem( nullptr ); + } +} + +void QskInputManager::processInputMethodQueries( + Qt::InputMethodQueries queries ) +{ + if ( auto panel = qobject_cast< QskInputPanel* >( m_data->panel ) ) + panel->processInputMethodQueries( queries ); +} + +QskControl* QskInputManager::panel( bool doCreate ) +{ + if ( m_data->panel == nullptr && doCreate ) + { + m_data->panel = createPanel(); + + connect( m_data->panel, &QskControl::localeChanged, + this, &QskInputManager::updatePredictor, Qt::UniqueConnection ); + } + + return m_data->panel; +} + +Qt::Alignment QskInputManager::panelAlignment() const +{ + if ( auto panel = qobject_cast< QskInputPanel* >( m_data->panel ) ) + { + if ( panel->hasInputProxy() ) + { + /* + When the panel has an input proxy we don't need to see + the input item and can put the panel in the center + */ + + return Qt::AlignVCenter; + } + } + + return Qt::AlignBottom; +} + +QskControl* QskInputManager::createPanel() +{ + return new QskInputPanel(); +} + +QskInputEngine* QskInputManager::createEngine() +{ + return new QskInputEngine(); +} + +void QskInputManager::updateEngine( const QLocale& locale ) +{ + auto context = QskInputContext::instance(); + + if ( m_data->engine == nullptr) + { + auto engine = createEngine(); + if ( engine->parent() == nullptr ) + engine->setParent( this ); + + m_data->predictorLocale = locale; + engine->setPredictor( context->textPredictor( locale ) ); + + m_data->engine = engine; + } + else + { + if ( m_data->predictorLocale != locale ) + { + m_data->predictorLocale = locale; + m_data->engine->setPredictor( context->textPredictor( locale ) ); + } + } +} + +void QskInputManager::updatePredictor() +{ + if ( m_data->panel && m_data->engine ) + { + auto context = QskInputContext::instance(); + const auto locale = context->locale(); + + if ( m_data->predictorLocale != locale ) + m_data->engine->setPredictor( context->textPredictor( locale ) ); + } +} diff --git a/src/inputpanel/QskInputManager.h b/src/inputpanel/QskInputManager.h new file mode 100644 index 00000000..fbbcb907 --- /dev/null +++ b/src/inputpanel/QskInputManager.h @@ -0,0 +1,46 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the QSkinny License, Version 1.0 + *****************************************************************************/ + +#ifndef QSK_INPUT_MANAGER_H +#define QSK_INPUT_MANAGER_H + +#include "QskGlobal.h" +#include +#include + +class QskInputEngine; +class QskControl; +class QQuickItem; +class QLocale; + +class QSK_EXPORT QskInputManager : public QObject +{ + Q_OBJECT + + using Inherited = QObject; + +public: + QskInputManager( QObject* parent = nullptr ); + virtual ~QskInputManager() override; + + virtual void attachInputItem( QQuickItem* ); + virtual void processInputMethodQueries( Qt::InputMethodQueries ); + + QskControl* panel( bool doCreate ); + virtual Qt::Alignment panelAlignment() const; + +protected: + virtual QskControl* createPanel(); + virtual QskInputEngine* createEngine(); + + void updatePredictor(); + void updateEngine( const QLocale& ); + +private: + class PrivateData; + std::unique_ptr< PrivateData > m_data; +}; + +#endif