ToolbarsAndUserLevel/fr

From OOo4Kids

Jump to: navigation, search

OOo4Kids

Barres d'outils qui dépendent du niveau de l'utilisateur


À propos du code proposé dans cette page : tous les changements par rapport au code original d'OpenOffice.org ayant servi de base, et fournis dans cette page, sont :

  • sous Licence LGPL v3 ( et vous pouvez-le redistribuer et / ou le modifier selon les termes de la licence GNU Lesser General Public License telle que publiée par la Free Software Foundation)
  • Copyright Eric Bachard November 2009


Introduction

Ci-dessous, vous trouverez une description technique de l'implémentation de la fonctionnalité : Barres d'outils qui dépendent du niveau de l'utilisateur. Il est ainsi question de code source (C++), de la couche graphique, côté interface utilisateur, dite "layout", de l'implémentation UNO du gestionnaire de la couche graphique, de la gestion des barres d'outils dans sfx2 (workwin), et de quelques autres points techniques comme la notion de shell graphique, et la lecture du niveau de l'utilisateur à l'aide du gestionnaire de configuration (config manager) . Nous supposons que le lecteur possède les bases nécessaires pour lire et comprendre le contenu de ce qui est exposé.

Les pré-requis pour lire cet article sont encore à définir, mais si certaines notions ne vous sont pas familières, nous vous invitons à consulter le wiki d'OpenOffice.org pour compléter vos connaissances, afin de pouvoir lire cet article dans les meilleures conditions possibles.


Objectifs

Cette fonctionnalité est couplée à Choix du niveau de l'utilisateur dans les préférences, et vise d'avoir une barre principale d'outils par niveau , dans les applications :

  • Writer;
  • Calc;
  • Draw;
  • Impress;
  • Math;
  • Chart.

Pour chaque application citée ci-dessus, le même nom de barre d'outils sera utilisé, avec l'idée d'avoir, comme barre visible, soit :

  • standardbar ( niveau Expert).
  • ou average ( niveau Moyen ).
  • ou encore beginner ( niveau Débutant).

La règle : Parmi les barres d'outils précédentes, une seule doit être visible à la fois.


Specifications

Le besoin a été décrit à la page Idées et suggestions de ce wiki.

Comportement attendu : lorsque l'utilisateur modifie le niveau d'utilisateur en cliquant sur le bouton radio ( cliquer sur l'image pour aggrandir), la barre d'outils principale change immédiatement.



Writer (par exemple)

Comme proposé, l'idée est d'avoir une barre d'outil par niveau d'utilisateur.

La proposition concerne pour l'instant Writer seulement, mais la fonctionnalité peut immédiatement être étendue aux autres applications (en attente de participation des enseignants ... ).

Niveau débutant

Pour enfants, entre 8 et 9 ans :

Image:Barre_cycle2.png

Niveau moyen

Pour enfants entre 10 et 11 ans :

Image:Barre_cycle3.png


Niveau Expert

Enfants au delà de 11 ans :

Image:Barre_standard.png


Dans le Code

Traduction en cours

-> Les changements concernant OOo4Kids sont protégés par des #ifdef OOo4Kids ... #endif


Modules concernés

En fait, la fonctionnalité possède deux faces distinctes, présentées ci-dessous :

  • afficher une fenêtre, puis retrouver la bonne barre d'outils, appeler le Layout manager, lui demander d'afficher la barre correctemet : sfx2, et la classe SfxWorkWindow sont concernés.
  • Lorsqu'on change le niveau de l'utilisateur courant : le layout manager, svx, et la boîte de dialogues ( optgdlg.cxx ) sont concernés (par exemple pour le rafriachissement )

Enfin: vérifier la possibilité d'ajouter les barres d'outils (à confirmer).

Ce n'est PAS la solution définitive car : sc, sfx2, svx, svx utilisent le même code pour lire/écrire le niveau de l'utilisateur dans le fichier Common.xcu, et une factorisation, ainsi qu'un nettoyage de code seront nécessaires prochainement. Une meilleurs solution pourrait consister à créer une classe permettant de lire écrire dans Common.xcu dans l'un des modules comme tools ou configmgr, mais cela demande quelque attention et réflexion. Probablement après la 1.0



Module svx

Les parties suivantes doivent être modifiées dans le fichier optgdlg.cxx (placé dans svx/source/cui) :

  • define static OUStrings, pour simplifier le code.
static const OUString sULConfigSrvc( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.configuration.ConfigurationProvider" ) );
static const OUString sULAccessSrvc( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.configuration.ConfigurationUpdateAccess" ) );
static const OUString sULaNode( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Office.Common/Misc" ) );
static const OUString sULPropertyName( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UserLevel" ) ) );

Autres chaînes utiles :

/* adapt the toolbars to the level */

static const OUString aLayoutManagerPropName( RTL_CONSTASCII_USTRINGPARAM( "LayoutManager" ) );

// The alignment bar
// static const OUString sAlignmentToolbarTypeName( RTL_CONSTASCII_USTRINGPARAM( "private:resource/toolbar/alignmentbar" ) );
// The standard toolbar
static const OUString sStandardbarToolbarTypeName( RTL_CONSTASCII_USTRINGPARAM( "private:resource/toolbar/standardbar" ) );
// The beginner toolbar (every application has its own)
static const OUString sBeginnerbarToolbarTypeName( RTL_CONSTASCII_USTRINGPARAM( "private:resource/toolbar/beginner" ) );
// The average toolbar (every application has its own)
static const OUString sAveragebarToolbarTypeName( RTL_CONSTASCII_USTRINGPARAM( "private:resource/toolbar/average" ) );


  • définir la méthode statique setToolbarState() : instancier un Layout manager, puis ajouter ( requestElement(theToolbar) ) ou enlever (destroyElement(theToolbar) ) une barre d'outils donnée.

static short setToolbarState( const OUString sSetAToolbarTypeName, bool isTrue )
{
    try
    {
        // avoids a crash if ever the user opens the prefs while the start center is the current view
        if ( ! (SfxViewFrame::Current()) )
            return -1;
        
        Reference< XPropertySet > xPropSet( SfxViewFrame::Current()->GetFrame()->GetFrameInterface(), UNO_QUERY );
        Reference< XLayoutManager > xLayoutManager;

        if ( xPropSet.is() )
        {
            Any aValue = xPropSet->getPropertyValue( aLayoutManagerPropName );
            aValue >>= xLayoutManager;
        }

        if ( !xLayoutManager.is() )
            return -1;
        else
        {
            xLayoutManager->lock();

            if ( isTrue )
                xLayoutManager->requestElement( sSetAToolbarTypeName );
            else
                xLayoutManager->destroyElement( sSetAToolbarTypeName );

            // should refresh, but does not when showElement() is used
            xLayoutManager->unlock();
        }
    }
    catch( Exception& )
    {
    }
    return 0;
}


  • initialisation de la barre d'outils dans le constructeur de l'instance de OfaMiscTabPage : demande de retrouver le niveau de l'utilisateur en lisant la valeur User Level dans le fichier Common.cxu.

Note: les barres d'outils sont initialisées en même temps que les boutons radio quand la fenêtre des préférences est instanciée.


    // initialize the Radio button (User Level)
    switch ( getUserLevel() )
    {
        case USER_LEVEL_BEGINNER:
        {
#ifdef DEBUG
	    fprintf(stdout, " %s : User level beginner \n", __func__);
#endif

            setToolbarState( sStandardbarToolbarTypeName, false);
            setToolbarState( sBeginnerbarToolbarTypeName, true );
            setToolbarState( sAveragebarToolbarTypeName, false);
            aUserLevelBeginnerRB.SetState( TRUE );
        }
            break;

        case USER_LEVEL_AVERAGE:
        {
#ifdef DEBUG
            fprintf(stdout, " %s : User level average \n", __func__);
#endif

            setToolbarState( sStandardbarToolbarTypeName, false);
            setToolbarState( sBeginnerbarToolbarTypeName, false );
            setToolbarState( sAveragebarToolbarTypeName, true);
            aUserLevelAverageRB.SetState( TRUE );
        }
            break;    

        case USER_LEVEL_EXPERT:
        {
#ifdef DEBUG
            fprintf(stdout, " %s : User level expert \n", __func__);
#endif
          aUserLevelExpertRB.SetState( TRUE );

            setToolbarState( sStandardbarToolbarTypeName, true );
            setToolbarState( sBeginnerbarToolbarTypeName, false );
            setToolbarState( sAveragebarToolbarTypeName, false);

        }
            break;
        default:
            break;
    }
#endif // OOo4Kids



  • activer la bonne barre d'outils quand le niveau utilisateur est modifié (Bouton Radio) dans les préférences : fait dans le callback IMPL_LINK( OfaMiscTabPage, UserLevelCheckHdl_Impl, RadioButton*, pButton )

Note: pour être certain qu'une seule barre est active, une seule est activée et les deux autres sont détruites, pour chaque niveau utilisateur.



#ifdef OOo4Kids
IMPL_LINK( OfaMiscTabPage, UserLevelCheckHdl_Impl, RadioButton*, pButton )
{
	(void) pButton;
    if ( aUserLevelExpertRB.IsChecked() )
    {
        setUserLevel( USER_LEVEL_EXPERT );

        setToolbarState( sStandardbarToolbarTypeName, true );
        setToolbarState( sBeginnerbarToolbarTypeName, false );
        setToolbarState( sAveragebarToolbarTypeName, false);
    }
    
    else if ( aUserLevelAverageRB.IsChecked() )
    {
        setUserLevel( USER_LEVEL_AVERAGE );

        setToolbarState( sStandardbarToolbarTypeName, false );
        setToolbarState( sBeginnerbarToolbarTypeName, false );
        setToolbarState( sAveragebarToolbarTypeName, true);
    }

    else
    {
        setUserLevel( USER_LEVEL_BEGINNER );

        setToolbarState( sStandardbarToolbarTypeName, false );
        setToolbarState( sBeginnerbarToolbarTypeName, true );
        setToolbarState( sAveragebarToolbarTypeName, false);
    }
    return 0;
}



Module sfx2

Tout a été implémenté dans sfx2/source/appl/workwin.cxx. le rôle de la SfxWorkWindow est extrêmement important, car pour chaque nouveau document, les barres d'outils seront dessinée là. Autre cas : lorsqu'on ferme la la boîte de dialogue des préférence (boîte de dialogue modale)


Ce qui a été fait :

  • define static OUStrings pour améliorer la lisibilité du code
// The standard toolbar
static const OUString sStandardbarToolbarTypeName( RTL_CONSTASCII_USTRINGPARAM( "private:resource/toolbar/standardbar" ) );
// The beginner toolbar (every application has its own)
static const OUString sBeginnerbarToolbarTypeName( RTL_CONSTASCII_USTRINGPARAM( "private:resource/toolbar/beginner" ) );
// The average toolbar (every application has its own)
static const OUString sAveragebarToolbarTypeName( RTL_CONSTASCII_USTRINGPARAM( "private:resource/toolbar/average" ) );
// Generic constants
static const OUString sULConfigSrvc( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.configuration.ConfigurationProvider" ) );
static const OUString sULAccessSrvc( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.configuration.ConfigurationUpdateAccess" ) );


  • define getUserLevel() permet de lire le niveau utilisateur dans Common.xcu.


static short getUserLevel()
{
    short dUserLevel = 1; // default is beginner 
    try
    {
	// get service provider
        Reference< XMultiServiceFactory > xSMgr( vcl::unohelper::GetMultiServiceFactory() );
        // create configuration hierachical access name
        if( xSMgr.is() )
        {
            try
            {
                Reference< XMultiServiceFactory > xConfigProvider(
                    Reference< XMultiServiceFactory >(
                        xSMgr->createInstance( sULConfigSrvc ),
                        UNO_QUERY )
                    );
                if( xConfigProvider.is() )
                {
                    Sequence< Any > aArgs(1);
                    PropertyValue aVal;
                    aVal.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "nodepath" ) );
                    aVal.Value <<= OUString( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Office.Common/Misc" ) );
                    aArgs.getArray()[0] <<= aVal;
                    Reference< XNameAccess > xConfigAccess(
                        Reference< XNameAccess >(
                            xConfigProvider->createInstanceWithArguments( sULAccessSrvc, aArgs ), UNO_QUERY )
                        );
                    if( xConfigAccess.is() )
                    {
                        try
                        {
                            short bValue = 1;
                            Any aAny = xConfigAccess->getByName( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UserLevel" ) ) );
                            if( aAny >>= bValue )
                                dUserLevel = bValue;
                        }
                        catch( NoSuchElementException& )
                        {
                        }
                        catch( WrappedTargetException& )
                        {
                        }
                    }
                }
            }
            catch( Exception& )
            {
            }
        }
    }
    catch( WrappedTargetException& )
    {
    }
    return dUserLevel;
}


  • ajouter des nouveaux ids et noms de barres d'outils dansle tableau pToolBarResToName[] qui sera utilisé ici.

Note: valeurs défiies "au pif" car rien trouvé sur le sujet dans le code.

static const ResIdToResName pToolBarResToName[] =
{
    { 558,      "fullscreenbar"        },
    { 560,      "standardbar",         },

...

#ifdef OOo4Kids
    { 20001,    "beginner"      },      //writer
    { 20002,    "average"       },      //writer
#endif

...

  • Lire le niveau de l'utilisateur dans le fichier Common.xcu, et activer les barres d'outils dans la SfxFrameWorkWin_Impl::UpdateObjectBars_Impl()

Note: déverouiller par "unlock" le LayoutManager, déclenche le rafraichissement, mais quand le niveau de l'utilisateur est modifié dans les préférences, le rafraichissement n'est effectif que lorsqu'on ferme la boîte de dialogue (basiquement une boîte de dialogue modale, qui garde le focus, et empêche le rafraichissement des autres fenêtres).


....

void SfxWorkWindow::UpdateObjectBars_Impl()
{

#ifdef OOo4Kids
        short int nUserLevel = getUserLevel();
        rtl::OUString aTbxId( m_aTbxTypeName );
        aTbxId += GetResourceURLFromResId( aObjBarList[n].nId );

        switch ( nUserLevel ) 
        {
            case USER_LEVEL_BEGINNER:
              {
#ifdef DEBUG
                fprintf(stdout, " %s : User level beginner \n", __func__);
                fprintf(stdout, "nId = %d \n", nId );
                fprintf(stdout, "aTbxId = %s \n", dbg_dump( aTbxId) );
#endif
                //xLayoutManager->showElement( sBeginnerbarToolbarTypeName );
                xLayoutManager->requestElement( sBeginnerbarToolbarTypeName );
                xLayoutManager->destroyElement( sAveragebarToolbarTypeName );
                xLayoutManager->destroyElement( sStandardbarToolbarTypeName );
              }
                break;

            case USER_LEVEL_AVERAGE:
              {
#ifdef DEBUG
                fprintf(stdout, " %s : User level average \n", __func__);
                fprintf(stdout, " nId = %d \n", nId );
#endif
                //xLayoutManager->showElement( sAveragebarToolbarTypeName );
                xLayoutManager->requestElement( sAveragebarToolbarTypeName );
                xLayoutManager->destroyElement( sBeginnerbarToolbarTypeName );
                xLayoutManager->destroyElement( sStandardbarToolbarTypeName );
              }
                break;

            case USER_LEVEL_EXPERT:
              {
#ifdef DEBUG
                fprintf(stdout, " %s : User level expert \n", __func__);
                fprintf(stdout, " nId = %d \n", nId );
#endif
                //xLayoutManager->showElement( sStandardbarToolbarTypeName );
                xLayoutManager->requestElement( sStandardbarToolbarTypeName );
                xLayoutManager->destroyElement( sBeginnerbarToolbarTypeName );
                xLayoutManager->destroyElement( sAveragebarToolbarTypeName );
              }
                break;

            default:
                break;        
        }
#endif // OOo4Kids

...

}
Personal tools