Raccourcis clavier avec SWT StyledText

David CHAUTARD

Dans ce billet nous allons présenter une solution pour incorporer les actions Copy/Paste et Undo/Redo au widget StyledText. Ce widget fait partie de la bibliothèque SWT, qui fournit un toolkit de composants graphiques pour développer une interface graphique en Java.
De plus, ce widget s'intègre dans des éditeurs de l'environnement Eclipse RCP, il est donc nécessaire que ces actions soient liées à cet environnement. Commentez

- Titre : Raccourcis clavier avec SWT StyledText

- Auteur : David CHAUTARD

- Parution : 7 mai 2010

- Mise à jour : 19 février 2020

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2010 David CHAUTARD. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Présentation

- II. La problématique

- III. La solution mise en place

- IV. Évolution

- V. Remerciements

I - Présentation

Nous développons une application Eclipse RCP dans laquelle nous utilisons le pattern Master/Details page, avec les UI Forms. Cela nous permet d'afficher nos données sous forme d'arbres et de pages détaillées, contenant les propriétés de l'élément édité. Dans les Details Page, nous utilisons donc des StyledText, pour renseigner les valeurs des différentes propriétés. Le choix du StyledText pour les champs d'édition s'explique par le fait qu'il s'agit d'un widget customisable qui permet de modifier la fonte ainsi que la couleur du texte affiché.

Figure 1 : Exemple de StyledText

II - La problématique

La problématique est donc de mettre en place les actions Copy/Paste et Undo/Redo dans nos différents StyleText, et que, de plus, celles-ci soient incorporées à notre RCP, via le menu Edit, comme n'importe quelle autre action disponible, par exemple dans les arbres.

Figure 2 : Actions dans le menu Edit

Cependant, le StyledText ne dispose pas de ces actions, que l'on peut avoir habituellement dans les champs texte, que ce soit par le biais d'un menu contextuel ou de raccourcis clavier, ce qui est donc problématique pour renseigner les différents champs que l'on retrouve dans notre application. Ceci s'explique par le fait que le StyledText est non natif, il ne bénéficie donc pas des actions par défaut, que l'on peut retrouver sur les widgets de gestion de texte. Il s'agit d'un « widget émulé, pour être utilisé dans les éditeurs Eclipse ».

Nous souhaitons donc pouvoir disposer de ces actions dans nos widgets, que ce soit directement avec les raccourcis clavier, ou avec un menu contextuel sur le StyledText.

III - La solution mise en place

Pour résoudre ce problème, la solution mise en place est la suivante.

Tout d'abord, nous créons la classe MyStyledText, dans laquelle nous avons un StyledText. Cette classe nous permet de gérer les listeners, ainsi que les actions que nous voulons ajouter au StyledText.

Nous avons trois types de listeners :

- ModifyListener : qui prend en compte la modification au niveau de l'élément, et informe l'éditeur qu'il a été modifié ;

- FocusListener : qui gère les actions Copy/Paste et Undo/Redo en fonction du widget qui prend le focus.
Lorsqu'un StyledText prend le focus, nous modifions les actions de l'ActionBars pour que celles-ci lui soient applicables. Ensuite, lors de la perte du focus du StyledText, nous restaurons les actions de l'ActionBarContributor. En réaffectant les actions de l'ActionBars avec les actions du StyledText, nos actions sont donc intégrées à l'application RCP, et sont de ce fait, accessibles dans la barre de menu, via la section Edit.

myStyledText.addFocusListener(new FocusListener() {

IAction undoActionOld;
IAction redoActionOld;
...

public void focusLost(FocusEvent e) {

// Restore previous commands
IActionBars actionBars = getEditor().getEditorSite().getActionBars();
actionBars.setGlobalActionHandler(ActionFactory.UNDO.getId(),  undoActionOld);
actionBars.setGlobalActionHandler(ActionFactory.REDO.getId(),  redoActionOld);
...
actionBars.updateActionBars();
}

public void focusGained(FocusEvent e) {

// Stock previous commands
undoActionOld = getActionBars().getGlobalActionHandler(ActionFactory.UNDO.getId());
redoActionOld = getActionBars().getGlobalActionHandler(ActionFactory.REDO.getId());

...

// Create the undo action
undoAction= new UndoActionHandler(getEditor().getSite(), undoManager.getUndoContext());
actionBars.setGlobalActionHandler(ActionFactory.UNDO.getId(), undoAction);
// Create the redo action.
redoAction= new RedoActionHandler(getEditor().getSite(), undoManager.getUndoContext());
actionBars.setGlobalActionHandler(ActionFactory.REDO.getId(), redoAction);

actionBars.updateActionBars();
}
});

Pour les actions d'Undo/Redo du StyledText, nous avons créé la classe UndoStyledTextManager, qui permet de gérer les actions effectuées dans le widget. Pour cela, elle contient un IUndoContext (qui filtre les opérations sur lesquelles le undo/redo est possible) et un IOperationHistory (les actions sont ajoutées à l'historique une fois qu'elles ont été exécutées) des opérations disponibles sur le widget.

Figure 3 : Liaison avec le menu Edit

- MouseListener : qui gère le menu contextuel pour les actions sur le contenu du StyledText
La classe PopUpMenu est couplée avec les actions construites précédemment.

Figure 4 : Le menu contextuel

//Create the menu
menu = new Menu(parent.getShell(),SWT.POP_UP);
menuItemCancel = new MenuItem(menu, SWT.CASCADE);
menuItemSeparator = new MenuItem(menu, SWT.SEPARATOR);
menuItemSeparator.setEnabled(true);
menuItemCut = new MenuItem(menu, SWT.CASCADE);
menuItemCopy = new MenuItem(menu, SWT.CASCADE);
menuItemPaste = new MenuItem(menu, SWT.CASCADE);
menuItemDelete = new MenuItem(menu, SWT.CASCADE);

...

menuItemCancel.addListener(SWT.Selection, new Listener() {
public void handleEvent(Event event) {
setActionCancel(true);
//Get the StyledText undo action
myStyledText.getUndoAction.run();
setMenuState(0);
}
});

...

Ensuite, nous avons la classe UndoStyledTextManager, qui va gérer le contexte et l'historique des opérations lors des modifications du contenu du StyledText. Le widget sera connecté à ce manager durant son existence.

UndoStyledTextManager undoManager = new UndoStyledTextManager(undoSize);
undoManager.connect(myStyledText);

Grâce à cette connexion, nous lui associons le contexte. Il s'agit de connaitre le contexte de l'action courante, pour déterminer les opérations à réaliser pour effectuer le Undo. De plus, nous avons également l'historique qui va gérer l'historique des opérations possibles suivant l'action courante. Celui-ci est géré par le biais d'un écouteur sur le StyledText. En effet, à chaque modification de son contenu, nous créons une nouvelle opération, et nous l'ajoutons à l'historique. Il s'agit de nos propres opérations de type UndoableOperation. Celles-ci permettent d'enregistrer les modifications apportées au contenu du StyledText pour pouvoir ensuite bénéficier des actions de Undo et de Redo.

IV - Évolution

L'axe d'évolution concerne la gestion des actions Undo/Redo, afin que celles-ci soient similaires à un éditeur de texte. En effet, actuellement ces actions agissent caractère par caractère, et non par suite de caractères tapés ou supprimés. Il pourrait donc être envisageable d'améliorer les actions de l'UndoableOperation.

V - Remerciements

Je voudrais remercier Furr pour sa relecture, ainsi que tous ceux qui ont pu m'aider à la rédaction de cet article.