LicenseDialog/fr
From OOo4Kids
|
Boite de dialogue Licence |
À 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 12th august 2009
Introduction
Ci-dessous, vous trouverez une description technique de l'implémentation de la fonctionnalité : faire afficher la boîte de dialogue associée à l'entrée de menu ou le bouton "Licence...". Il est ainsi question de code source (C++, objective C), mais aussi de la structure et de l'organisation interne d'OpenOffice.org (framework), et 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.
État de l'Implémentation
-
Partie Mac OS X (Aqua)
-
Écrire le .xcu
-
Création de la boîte de dialogue
-
Description de la Classe ShowLicenseDialog
-
Connexion avec vcl
-
Changements dans svx
-
Connexion avec sfx2
-
Connexion avec framework
-
Connexion avec unotools
-
Deboguage
-
Documentation
Specifications
- Ajouter une entrée dans toutes les applications, qui permet de connaître la licence de OOo4Kids.
- Comportement attendu :
- un clic sur l'entrée de menu ouvre une fenêtre modale, qui explique la licence utilisée par OOo4Kdids, et donne un lien pointant sur la licence complète.
- clicquer sur OK ferme la fenêtre
Réalisation
Cette entrée sera disponible par défaut :
- dans le menu Application (menu Cocoa, à gauche), en dessous de l'entrée "Préférences" pour la version Mac OS X d'OOo4Kids
- dans le menu Aide pour les autres systèmes d'exploitation (Linux et Windows).
Moyens utilisés
- Nouvelle entrée ajoutée dans un menu
Le clic sur l'item va générer un événement, que l'application va recevoir, et transfomer en une commande UNO ( .uno:ShowLicense). Cette commande sera diffusée, et la fenêtre modale correspondant à l'affichage de la licence sera ouverte. Un appui sur Ok (ou esc ) permettra à l'utilisateur de fermer cette fenêtre.
Autres possibilités :
- Le fichier de configuration GenericCommands.xcu possède une entrée .uno:ShowLicense ( la commande correspondante sera dispatchée )
Et donc, l'utilisateur pourra soit ajouter une nouvelle entrée de menu "Licence..." dans un menu de son choix, soit ajouter un nouveau bouton "Licence...".
Ceci pourra se faire grâce au menu Outils -> Personnaliser...
Cette entrée sera disponible par défaut :
- dans le menu Application (menu Cocoa, à gauche), en dessous de l'entrée "Préférences" pour les version Mac OS X
- dans le menu Aide pour les autres systèmes d'exploitation.
Comment cela fonctionne-t-il ?
1) En partant de vcl
Cette partie décrit uniquement l'implémentation de la version Mac OS X Aqua d'OOo4Kids
Sous Mac OS X, version Aqua :
La chaîne "License ..." (en-US) est créee dans vcl/source/src/stdtext.src (j'ai aussi ajouté la chaîne en fr, et donc, en fonctionnement, "Licence..." sera affiché avec la version fr, ce qui signifie que le menu correspondant sera automatiquemenet localisé)
String SV_STDTEXT_LICENSE
{
Text [ en-US ] = "License ...";
Text [ fr ] = "Licence ...";
};
Au moment de la compilation, les chaînes ajoutées seront ajoutées dans le binaire vclfr.res (version fr) ou vcl.res (en-US, pardefaut), puis délivrées dansle solver, packagées, ... etc
L'action sélectionner le menu principal Aqua " File -> License... "
=> aura pour effet d'envoyer un message interne (Cocoa) de type "SHOW_DIALOG" et contenant, parmi d'autres informations, la chaîne "LICENSE"
Dans le code source, see vcl/aqua/source/window/salmenu.cxx
else if( nDialog == SHOWDIALOG_ID_LICENSE )
aDialog = String( RTL_CONSTASCII_USTRINGPARAM( "LICENSE" ) );
const ApplicationEvent* pAppEvent = new ApplicationEvent( String(),
ApplicationAddress(),
ByteString( "SHOWDIALOG" ),
aDialog );
AquaSalInstance::aAppEventList.push_back( pAppEvent );
2) ...dans la partie "framework"
Étape suivante : comme il s'agit d'un événement système, l'Application (voir le point suivant dans desktop), n'est pas capable d'intercepter l'événement, et pour contourner cette insuffisance, un écouteur d'événéments (eventListener) est démaré dans le framework, afin que celui-ci intercepte tous les événement hard codés de type SHOWDIALOG. Ceci est précisément réalisé dans framework/source/dispatch/windowcommanddispatch.c
xx
Tout d'abord, un écouteur d'événements est démarré ( void WindowCommandDispatch::impl_startListening() ) dans le constructeur de la classe WindowCommandDispatch.
Ensuite, on crée une chaîne de caractères, de type OUString :
const ::rtl::OUString WindowCommandDispatch::COMMAND_LICENSEBOX = ::rtl::OUString::createFromAscii(".uno:ShowLicense");
Et une fois que l'événement est intercepté, on utlise un callback, afin de diffuser la commande, de la façon suivante :
IMPL_LINK(WindowCommandDispatch, impl_notifyCommand, void*, pParam)
Qui fait ... :
switch (nCommand)
{
...
case SHOWDIALOG_ID_LICENSE :
sCommand = WindowCommandDispatch::COMMAND_LICENSEBOX;
en terminant avec :
impl_dispatchCommand(sCommand);
Étape suivante-> la commande est interceptée, est exécutée dans sfx2
Suggestion :
=> voir la description complète de l'interface dans : framework/source/inc/dispatch/windowcommanddispatch.hxx
/** @short internal helper to bind e.g. MAC-Menu events to our internal dispatch API.
@descr On e.g. MAC platform system menus are merged together with some fix entries as
e.g. "Preferences" or "About". These menu entries trigger hard coded commands.
Here we map these commands to the right URLs and dispatch them.
3) de desktop vers ... unotools ?)
TODO : est-ce que l'API serait déjà capable d'utiliser ce qui est implémenté ?
4) officefg
Que se passe-t-il dans officecfg ?
- Un nouvelle entrée de menu est ajoutée, et porte le nom : .uno:ShowLicense. Si cette commande correspond avec un numéro de Slot existant vraiment, alors l'entrée de menu devient active, sinon, elle reste grisée.
Les changements sont faits dans GenericCommand.xcu,en respectant la syntaxe .xml. Le noeud suivant a été créé : .uno:ShowLicense :
<node oor:name=".uno:ShowLicense" oor:op="replace"> <prop oor:name="Label" oor:type="xs:string"> <value xml:lang="en-US">L~icense ...</value> <value xml:lang="fr">L~icence ...</value> </prop> </node>
Ainsi, dans Outils -> Personnaliser, l'utilisateur aura la possibilité d'ajouter soit une nouvelle entrée de menu de type "Licence...", soit un nouveau bouton de type "Licence..." dans la barred 'outils de son choix.
L'exemple ci-dessous, décrit le cas de l'addition d'un nouvel item "Licence ..." dans un menu :
5) ce qui se passe dans sfx2
- Un slot, vu comme une nouvelle commande, devient actif si sa déclaration est correcte, et si elle existe vraiment (sinon l'entrée de menu correspondante est grisée). Le rôle de sfx2 est de diffuser rediriger un événement tel que l'entrée de menu, losque celle-ci est "cliquée".
- La détection de tous les slots actifs/inactifs, se fait au lancement d'OpenOffice.org (détection des services .etc).
- Tout événement, vu comme l'émission de la constante SID_LICENSE sera diffusée et envoyée au framework. Elle sera alors vue comme une commande UNO de type : .uno:ShowLicense, traitée dans appserv.cxx (dans framework/source/app/appserv.cxx )
Attention : dans ce qui suit, il y a peut être des valeurs erronnées. Dans ce cas, merci de me contacter en m'expliquant ce qui n'est pas correct, et doit être modifié.
Par exemple, j'ai un peu défini certaines valeurs au pif ;-)
Définition des nouvelles constantes
Comment choisir les bonnes valeurs ?
=> Il semble qu'il n'y ait pas de règles exact (juste faire attention à ne pas avoir de recouvrement des ID ressources)
- Dans sfx2/inc/sfx2/sfx.hrc:
Added :
// ressource ID used in appserv.cxx
#define RID_DEFAULTLICENSE (RID_SFX_START+20)
// constants used to define the dialog box content
#define LICENSE_BTN_OK 6
#define LICENSE_FTXT_VERSION 6
#define LICENSE_FTXT_COPYRIGHT 7
#define LICENSE_STR_DEVELOPER_ARY 6
#define LICENSE_STR_FRENCH_COPYRIGHT 7
#define LICENSE_STR_ACCEL 8
- in sfx2/inc/sfx2/sfxsids.hrc:
// ajouté la constante SID_LICENSE // default-ids for application #define SID_QUITAPP (SID_SFX_START + 300) #define SID_ABOUT (SID_SFX_START + 301) #define SID_SETUPPRINTER (SID_SFX_START + 302) #define SID_EXITANDRETURN (SID_SFX_START + 303) #define SID_LICENSE (SID_SFX_START + 304)
Définition du nouveau slot
Tout d'abord, ajouter l'item dans sfx2/sdi/sfx.sdi:SfxVoidItem ShowLicense SID_LICENSE
Merci de bien noter la syntaxe utilisée : SfxVoidItem ShowLicense SID_LICENSE
- Le type est SfxVoidItem
- Le nom de la méthode est ShowLicense
- La constante associée est SID_LICENSE
Note : tout ceci est évidemment inspiré de l'équivalent SID_ABOUT
//--------------------------------------------------------------------------
SfxVoidItem ShowLicense SID_LICENSE
()
[
/* flags: */
AutoUpdate = FALSE,
Cachable = Cachable,
FastCall = FALSE,
HasCoreId = FALSE,
HasDialog = TRUE,
ReadOnlyDoc = TRUE,
Toggle = FALSE,
Container = FALSE,
RecordAbsolute = FALSE,
RecordPerSet;
Synchron;
/* config: */
AccelConfig = TRUE,
MenuConfig = TRUE,
StatusBarConfig = FALSE,
ToolBoxConfig = TRUE,
GroupId = GID_APPLICATION;
]
Et maintenant, définissons l'interface. Cela signifie, que dans appserv.cxx, l'implémentation réelle utilisera la méthode MiscExec() pour lancer l'initialisation, puis l'exécution de l'affichage de la boîte de dialogue.
Si vous lisez le fichier dont le nom figure ci-dessous, vos trouverez d'autres cas possibles, ce qui vous permettra d'adapter ce qui est exposé à votre cas.
Index: sfx2/sdi/appslots.sdi
===================================================================
--- sfx2/sdi/appslots.sdi (revision 274625)
+++ sfx2/sdi/appslots.sdi (working copy)
@@ -52,6 +52,10 @@
[
ExecMethod = MiscExec_Impl ;
]
+ SID_LICENSE // ole(no) api(final/play/rec)
+ [
+ ExecMethod = MiscExec_Impl ;
+ ]
SID_SETOPTIONS
[
ExecMethod = MiscExec_Impl ;
Implémentation de la méthode
Maintenant, nous sommes dans sfx2/source/appl/appserv.cxx
Nous avons d'abord besoin d'inclure le fichier d'en tête showlicence.hxx (nouveau fichier d'en-tête, dérivé de about.hxx )
Donc, comme attendu, dans void SfxApplication::MiscExec_Impl( SfxRequest& rReq ) , nous ajoutons le nouveau cas SID_LICENSE dans le switch :
+ case SID_LICENSE:
+ {
+
+ String sBuildId( String::CreateFromAscii( "This text will explain the license OOo4Kids will use
Ce qui suit va contenir "License ..."
+ + rtl::OUString aLicenseContent( DEFINE_CONST_OUSTRING( "SHOW_LICENSE" ) );
Retrouver l'ID ressource :
+ // search for the resource of the license box + ResId aDialogResId( RID_DEFAULTLICENSE, *pAppData_Impl->pLabelResMgr ); + ResMgr* pResMgr = pAppData_Impl->pLabelResMgr; + if( ! pResMgr->IsAvailable( aDialogResId.SetRT( RSC_MODALDIALOG ) ) ) + pResMgr = GetOffResManager_Impl(); +
... vérifier que c'est ok
+ aDialogResId.SetResMgr( pResMgr );
+ if ( !pResMgr->IsAvailable( aDialogResId ) )
+ {
+ DBG_ERRORFILE( "No RID_DEFAULTLICENSE in label-resource-dll" );
+ }
+
Une fois que tout est ok, alors afficher la boîte de dialogue (modale) :
+ // then show the license box
+ ShowLicenseDialog* pDlg = new ShowLicenseDialog( 0, aDialogResId, sBuildId );
pDlg->Execute();
delete pDlg;
bDone = TRUE;
+ break;
+ }
6) La boîte de dialogue modale "ShowLicense"
TODO : décrire ..
Soit la classe : ShowLicenseDialog::ShowLicenseDialog( Window* pParent, const ResId& rId, const String& rVerStr ). Cette classe est un clone de la classe AboutDialog (voir about.hxx dans sfx2/inc ). Les ressources pour l'affichage sont gérées dans svx ( à suivre )
Justification: nous utilisons une classe, copiée sur la classe AboutDialog, pour contruire l'affichage de la licence. Les intérêts sont :
- classe modale - nous réutilisons le défilement pour faire apparaître le nom des contributeurs à OOo4Kids avec le contrôle : CTRL+SDT ( CMD+SDT sous Mac OS X) - nous affichons un .png (et non un .bmp ), car nous réutilisons le loader .png.
7) note about what happens in desktop
FIXME : why do we never hit that ?
In desktop, Desktop::HandleAppEvent() should normaly catch the event, in app.cxx:2830 ( see desktop/source/app/app.cxx ) , and if the catched string does contain "LICENSE". But for a reason I still ignore, we never hit this method ?? If ever we can reach the place, w<hat should happen is described below :
First, the string ".uno:ShowLicense", means the command label, will be created :
In the code :
app.cxx:2837, in void Desktop::HandleAppEvent( const ApplicationEvent& rAppEvent ) :
else if( rAppEvent.GetData().EqualsAscii( "LICENSE" ) )
aCommand.Complete = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( ".uno:ShowLicense" ) );
Then, once completed, the command is dispatched :
if( aCommand.Complete.getLength() )
{
xParser->parseStrict(aCommand);
css::uno::Reference< css::frame::XDispatch > xDispatch = xDesktop->queryDispatch(aCommand, rtl::OUString(), 0);
if (xDispatch.is())
xDispatch->dispatch(aCommand, css::uno::Sequence< css::beans::PropertyValue >());
}
Mac OS X (Aqua) part
Changements dans le code :
1) vcl :
- HUNK1
Ajout de la constante dans vcl/inc/vcl/cmdevt.hxx
+#if defined( OOo4Kids ) +#define SHOWDIALOG_ID_LICENCE 3 +#endif
- HUNK 2
Ajout de la nouvelle entrée de menu Cocoa, en tant que chaîne de caractères, dans vcl/source/src/stdtxt.src
String SV_STDTEXT_LICENSE
{
Text [ en-US ] = "License ";
Text [ fr ] = "Licence ";
};
- HUNK 3
Ajout de la nouvelle constante dans vcl/inc/vcl/menu.hxx :
Index: vcl/inc/vcl/menu.hxx =================================================================== --- vcl/inc/vcl/menu.hxx (revision 274625) +++ vcl/inc/vcl/menu.hxx (working copy) @@ -90,6 +90,7 @@ #define MIB_AUTOCHECK ((MenuItemBits)0x0004) #define MIB_ABOUT ((MenuItemBits)0x0008) #define MIB_HELP ((MenuItemBits)0x0010) +#define MIB_SHOWLICENSE ((MenuItemBits)0x0016) #define MIB_POPUPSELECT ((MenuItemBits)0x0020) // not in rsc/vclsrc.hxx because only a prelimitary solution #define MIB_NOSELECT ((MenuItemBits)0x0040)
Ajout de la nouvelle constante dans vcl/inc/vcl/svids.hrc :
Index: vcl/inc/vcl/svids.hrc
===================================================================
--- vcl/inc/vcl/svids.hrc (revision 274625)
+++ vcl/inc/vcl/svids.hrc (working copy)
@@ -108,6 +108,7 @@
#define SV_STDTEXT_ABOUT 10204
#define SV_STDTEXT_PREFERENCES 10205
#define SV_MAC_SCREENNNAME 10206
+#define SV_STDTEXT_LICENSE 10207
#define SV_STDTEXT_LAST SV_MAC_SCREENNNAME
#define SV_ACCESSERROR_FIRST SV_ACCESSERROR_WRONG_VERSION
Add the new entry in the Aqua menu ( vcl/aqua/source/window/salmenu.cxx )
@@ -146,11 +153,25 @@
[pAppMenu insertItem: [NSMenuItem separatorItem] atIndex: 3];
}
+ // insert license entry
+ String aLicense( ResId( SV_STDTEXT_LICENSE, *pMgr ) );
+ pString = CreateNSString( aLicense );
+ pNewItem = [pAppMenu insertItemWithTitle: pString
+ action: @selector(showLicense:)
+ keyEquivalent: @","
+ atIndex: 4];
+ if (pString)
+ [pString release];
+ if( pNewItem )
+ {
+ [pNewItem setTarget: pMainMenuSelector];
+ [pAppMenu insertItem: [NSMenuItem separatorItem] atIndex: 5];
+ }
+ définition de la méthode qui recevra et les événements :
Interface :
-(void)showLicense: (id)sender;
Implementation :
-(void)showLicense: (id) sender
{
[self showDialog: SHOWDIALOG_ID_LICENSE];
}
IMPORTANT : ne pas oublier d'ajouter +2 à tous les indexes !! (sinon, les autres entrées de menu vont se superposer - effet Fun garanti- :-) )
2) svx:
dans svx/inc/globlmn_tmpl.hrc
-> ajouter l'item .uno:ShowLicence
As example :
- define ITEM_HELP_ABOUT \
Identifier = SID_ABOUT ; \
Command = ".uno:About" ; \
HelpID = SID_ABOUT ; \
Text [ en-US ] = "A~bout %PRODUCTNAME..." ; \
3) desktop
desktop/source/app/app.cxx
- HUNK 1
361 struct AboutBoxVersion
362 : public rtl::Static< String, AboutBoxVersion > {};
- HUNK 2
+ see ReplaceStringHookProc( UniString& rStr )
=>
void ReplaceStringHookProc( UniString& rStr )
374 {
375 static int nAll = 0, nPro = 0;
376
377 nAll++;
378 if ( rStr.SearchAscii( "%PRODUCT" ) != STRING_NOTFOUND )
379 {
380 String &rBrandName = BrandName::get();
381 String &rVersion = Version::get();
382 String &rAboutBoxVersion = AboutBoxVersion::get();
- HUNK 3
+ see : void Desktop::HandleAppEvent(
5) unotools
unotools/inc/unotools/configmgr.hxx#ABOUTBOXPRODUCTVERSION
See line around 90 : enum ConfigProperty
And :
//direct readonly access to some special configuration elements 108 static com::sun::star::uno::Any GetDirectConfigProperty(ConfigProperty eProp); 109 110 sal_Bool IsLocalConfigProvider(); 111 com::sun::star::uno::Reference< com::sun::star::container::XHierarchicalNameAccess> 112 GetHierarchyAccess(const rtl::OUString& rFullPath); 113 com::sun::star::uno::Any GetLocalProperty(const rtl::OUString& rProperty); 114 void PutLocalProperty(const rtl::OUString& , const com::sun::star::uno::Any& rValue); 115
External links
- The extremely important article from Mathias Bauer : Implementation of the Dispatch API in sfx2
To do
- The background image
- Put a mockup here.




