QskInputManager introduced

This commit is contained in:
Uwe Rathmann 2018-06-01 12:00:31 +02:00
parent 221b573287
commit 186b18587b
4 changed files with 241 additions and 83 deletions

View File

@ -4,8 +4,7 @@
*****************************************************************************/ *****************************************************************************/
#include "QskInputContext.h" #include "QskInputContext.h"
#include "QskInputPanel.h" #include "QskInputManager.h"
#include "QskInputEngine.h"
#include "QskLinearBox.h" #include "QskLinearBox.h"
#include "QskDialog.h" #include "QskDialog.h"
@ -69,22 +68,19 @@ class QskInputContext::PrivateData
public: public:
// item receiving the input // item receiving the input
QPointer< QQuickItem > inputItem; QPointer< QQuickItem > inputItem;
QPointer< QskInputPanel > inputPanel;
// popup or window embedding the panel // popup or window embedding the panel
QskPopup* inputPopup = nullptr; QskPopup* inputPopup = nullptr;
QskWindow* inputWindow = nullptr; QskWindow* inputWindow = nullptr;
QskInputEngine* engine = nullptr; QskInputManager* inputManager = nullptr;
bool isPredictorDirty = true;
}; };
QskInputContext::QskInputContext(): QskInputContext::QskInputContext():
m_data( new PrivateData() ) m_data( new PrivateData() )
{ {
setObjectName( "InputContext" ); setObjectName( "InputContext" );
m_data->engine = new QskInputEngine( this ); m_data->inputManager = new QskInputManager( this );
} }
QskInputContext::~QskInputContext() QskInputContext::~QskInputContext()
@ -96,25 +92,22 @@ QQuickItem* QskInputContext::inputItem() const
return m_data->inputItem; return m_data->inputItem;
} }
QskInputPanel* QskInputContext::inputPanel() const QskControl* QskInputContext::inputPanel() const
{ {
if ( m_data->inputPanel == nullptr ) auto panel = m_data->inputManager->panel( true );
{
auto that = const_cast< QskInputContext* >( this );
auto panel = new QskInputPanel(); if ( panel->parent() != this )
panel->setParent( that ); {
panel->setParent( const_cast< QskInputContext* >( this ) );
connect( panel, &QQuickItem::visibleChanged, connect( panel, &QQuickItem::visibleChanged,
this, &QskInputContext::activeChanged ); this, &QskInputContext::activeChanged, Qt::UniqueConnection );
connect( panel, &QskControl::localeChanged, connect( panel, &QskControl::localeChanged,
this, &QskInputContext::updateLocale ); this, [] { qskSendToPlatformContext( QEvent::LocaleChange ); } );
m_data->inputPanel = panel;
} }
return m_data->inputPanel; return panel;
} }
void QskInputContext::update( Qt::InputMethodQueries queries ) void QskInputContext::update( Qt::InputMethodQueries queries )
@ -131,8 +124,7 @@ void QskInputContext::update( Qt::InputMethodQueries queries )
} }
} }
if ( auto panel = inputPanel() ) m_data->inputManager->processInputMethodQueries( queries );
panel->processInputMethodQueries( queries );
} }
QRectF QskInputContext::panelRect() const QRectF QskInputContext::panelRect() const
@ -143,7 +135,7 @@ QRectF QskInputContext::panelRect() const
return QRectF(); return QRectF();
} }
QskPopup* QskInputContext::createEmbeddingPopup( QskInputPanel* panel ) QskPopup* QskInputContext::createEmbeddingPopup( QskControl* panel )
{ {
auto popup = new QskPopup(); auto popup = new QskPopup();
@ -154,24 +146,35 @@ QskPopup* QskInputContext::createEmbeddingPopup( QskInputPanel* panel )
auto box = new QskLinearBox( popup ); auto box = new QskLinearBox( popup );
box->addItem( panel ); box->addItem( panel );
/* const auto alignment =
When the panel has an input proxy ( usually a local text input ) m_data->inputManager->panelAlignment() & Qt::AlignVertical_Mask;
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();
popup->setOverlay( hasInputProxy ); popup->setOverlay( alignment == Qt::AlignVCenter );
if ( hasInputProxy ) switch( alignment )
{
case Qt::AlignTop:
{
box->setExtraSpacingAt( Qt::BottomEdge | Qt::LeftEdge | Qt::RightEdge );
break;
}
case Qt::AlignVCenter:
{
box->setMargins( QMarginsF( 5, 5, 5, 5 ) ); box->setMargins( QMarginsF( 5, 5, 5, 5 ) );
else break;
}
case Qt::AlignBottom:
default:
{
box->setExtraSpacingAt( Qt::TopEdge | Qt::LeftEdge | Qt::RightEdge ); box->setExtraSpacingAt( Qt::TopEdge | Qt::LeftEdge | Qt::RightEdge );
}
}
return popup; return popup;
} }
QskWindow* QskInputContext::createEmbeddingWindow( QskInputPanel* panel ) QskWindow* QskInputContext::createEmbeddingWindow( QskControl* panel )
{ {
auto window = new QskWindow(); auto window = new QskWindow();
@ -259,11 +262,7 @@ void QskInputContext::showPanel()
} }
} }
updatePredictor(); m_data->inputManager->attachInputItem( m_data->inputItem );
panel->setLocale( locale() );
panel->attachInputItem( m_data->inputItem );
panel->setEngine( m_data->engine );
} }
void QskInputContext::hidePanel() void QskInputContext::hidePanel()
@ -285,17 +284,13 @@ void QskInputContext::hidePanel()
#endif #endif
} }
if ( auto panel = inputPanel() ) if ( auto panel = m_data->inputManager->panel( false ) )
{
panel->setParentItem( nullptr ); panel->setParentItem( nullptr );
panel->attachInputItem( nullptr );
panel->setEngine( nullptr ); m_data->inputManager->attachInputItem( nullptr );
}
if ( m_data->inputPopup ) if ( m_data->inputPopup )
{
m_data->inputPopup->deleteLater(); m_data->inputPopup->deleteLater();
}
if ( m_data->inputWindow ) if ( m_data->inputWindow )
{ {
@ -341,28 +336,6 @@ QLocale QskInputContext::locale() const
return QLocale(); 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 ) void QskInputContext::setFocusObject( QObject* focusObject )
{ {
if ( m_data->inputItem == nullptr || m_data->inputItem == focusObject ) if ( m_data->inputItem == nullptr || m_data->inputItem == focusObject )

View File

@ -12,7 +12,8 @@
#include <memory> #include <memory>
class QskTextPredictor; class QskTextPredictor;
class QskInputPanel; class QskControl;
class QskInputManager;
class QskPopup; class QskPopup;
class QskWindow; class QskWindow;
class QQuickItem; class QQuickItem;
@ -27,19 +28,23 @@ public:
QskInputContext(); QskInputContext();
virtual ~QskInputContext(); virtual ~QskInputContext();
virtual QRectF panelRect() const; void setManager( QskInputManager* );
QskInputManager manager();
virtual void setActive( bool ); QRectF panelRect() const;
virtual bool isActive() const;
virtual QLocale locale() const; void setActive( bool );
bool isActive() const;
virtual QQuickItem* inputItem() const; QLocale locale() const;
virtual QskInputPanel* inputPanel() const;
QQuickItem* inputItem() const;
static QskInputContext* instance(); static QskInputContext* instance();
static void setInstance( QskInputContext* ); static void setInstance( QskInputContext* );
virtual QskTextPredictor* textPredictor( const QLocale& ) const;
Q_SIGNALS: Q_SIGNALS:
void activeChanged(); void activeChanged();
void panelRectChanged(); void panelRectChanged();
@ -47,13 +52,13 @@ Q_SIGNALS:
protected: protected:
virtual bool eventFilter( QObject*, QEvent* ) override; virtual bool eventFilter( QObject*, QEvent* ) override;
virtual QskPopup* createEmbeddingPopup( QskInputPanel* ); virtual QskPopup* createEmbeddingPopup( QskControl* );
virtual QskWindow* createEmbeddingWindow( QskInputPanel* ); virtual QskWindow* createEmbeddingWindow( QskControl* );
virtual void showPanel(); virtual void showPanel();
virtual void hidePanel(); virtual void hidePanel();
virtual QskTextPredictor* textPredictor( const QLocale& ) const; QskControl* inputPanel() const;
private: private:
friend class QskPlatformInputContext; friend class QskPlatformInputContext;
@ -64,12 +69,8 @@ private:
virtual void processClickAt( int cursorPosition ); virtual void processClickAt( int cursorPosition );
virtual void commitPrediction( bool ); virtual void commitPrediction( bool );
void updateLocale();
void updatePredictor();
class PrivateData; class PrivateData;
std::unique_ptr< PrivateData > m_data; std::unique_ptr< PrivateData > m_data;
}; };
#endif #endif

View File

@ -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 <QPointer>
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 ) );
}
}

View File

@ -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 <QObject>
#include <memory>
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