ToolbarsAndUserLevel/fr

À 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 agrandir ), 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 :



Niveau moyen
Pour enfants entre 10 et 11 ans :



Niveau Expert
Enfants au delà de 11 ans :



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: {	   fprintf(stdout, " %s : User level beginner \n", __func__);
 * 1) ifdef DEBUG
 * 1) endif

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

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

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

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

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

}           break; default: break; }
 * 1) 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.

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

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",         },

...

{ 20001,   "beginner"      },      //writer { 20002,   "average"       },      //writer
 * 1) ifdef OOo4Kids
 * 1) 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 {

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

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

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

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

default: break; }
 * 1) endif // OOo4Kids

...

}