For an RCP E4 Text Editor application implemented with a StyledText/SourceViewer it is necessary receive the status of the inset key.
Once received the state (insert, smart-insert), the application shall modify the cursor icon and notify other parts the INSERT state (i.e. notify to the status bar control like in a normal plain text editor behavior).
SWT.INSERT only listens for the key to be pressed, but nothing if the StyledText is in INSERT MODE.
styledText.addKeyListener(new KeyAdapter(){
public void keyPressed(KeyEvent e){
if(e.keyCode == SWT.INSERT){
System.out.println("INSERT KEY PRESSED!!!");
}
}
};
I have avoided to extend
org.eclipse.ui.texteditor.AbstractTextEditor
and use the method
getInsertMode()
since the application is intended to be pure E4 text editor.
Any hint?
Thanks in advance
First off you need to tell the StyledText not to do the default action when it sees the Insert key:
textWidget.setKeyBinding(SWT.INSERT, SWT.NULL);
Next you need to define a Command, Handler and Key Binding in the context for the editor to deal with the Insert key.
The Handler for the insert command can update the status display and shoyld then tell the StyledText to update the overwrite mode:
textWidget.invokeAction(ST.TOGGLE_OVERWRITE);
Also note that Mac keyboards don't have an Insert key!
Since I found some difficulties to deal with the INSERT_KEY within a sourceviewer control for E4 RCP text editor, I will write extra details to gregg449's answer (great help from him as everytime!).
Following the above answer, I have created Binding Context, Binding Table, Command, Handler and added the Binding Context to the required Part (the part implementing the SourceViewer).
The next code is for SourceViewer and InserKey Handler:
public class CheckKeyBindingSourceViewer extends ITextEditorPart{
public SourceViewer sv = null;
public StyledText st = null;
#PostConstruct
public void postConstruct(Composite parent) {
sv = new SourceViewer(parent, null, null, true, SWT.MULTI | SWT.V_SCROLL |SWT.H_SCROLL);
IDocument doc = new Document("");
sv.setDocument(doc);
st = sv.getTextWidget();
//tell the StyledText not to do the default action when it sees the Insert key
st.setKeyBinding(SWT.INSERT, SWT.NULL);
}
}
public class InsertKeyHandler {
#Execute
public void execute(#Named(IServiceConstants.ACTIVE_PART) MPart activePart) {
if (activePart.getObject() instanceof ITextEditorPart){
ITextEditorPart theSourceViewer = (ITextEditorPart) activePart.getObject();
theSourceViewer.st.invokeAction(ST.TOGGLE_OVERWRITE);
//TODO
//Change cursor sourcewiewer, notify to Statusbar...
}
}
}
The next figure shows the Application.e4xmi with the Binding Context and Binding Table created.
Note that if you do not add the supplementary tag "type:user" to the Binding Table, the bindings are not working at all.
This is not reflected into vogella's tutorial (http://www.vogella.com/tutorials/EclipseRCP/article.html) neither his book.
The only place I found this information was at stackoverflow question:
eclipse rcp keybindings don't work
I'm using eclipse Mars (4.5.0) for both Linux and Windows, I do not know if for newer verions this 'bug' is solved.
Related
In e3 to create not restorable View I set field "restorable" to false in extension org.eclipse.ui.views and it works. In my e4 application I create PartDescriptor with tag "NoRestore" but it do nothing. After restart Part is shown. What I do wrong? Or it is bug?
If you let e4 save the workbench model on exit it is restored exactly as saved the next time the RCP is started. There is no support for a NoRestore tag.
Specifying the -clearPersistedState flag on startup will reset the model to the initial state. You can also specify -persistState false to stop the model being saved on exit.
If you just want to deal with one part you can alter the model in your life cycle class during startup. Something like:
#ProcessAdditions
public void processAdditions(MApplication app, EModelService modelService)
{
MUIElement el = modelService.find("your part id", app);
if (el != null) {
el.setToBeRendered(false);
}
}
which just finds a part and turns off the 'to be rendered' flag.
For compatibility with future versions, in which the IPresentationEngine.NO_RESTORE("NoRestore") tag will be present, you can use the following code.
#PreSave
void preSave(MApplication a_app, EModelService a_modelService){
ArrayList<MElementContainer<MUIElement>> containers = new ArrayList<>();
List<MPart> parts = a_modelService.findElements(a_app, null, MPart.class, Arrays.asList("NoRestore"));
parts.forEach(p -> {
p.setToBeRendered(false); // hide parts
containers.add(p.getParent()); // collect containers with no restorable parts
});
// hide containers which contains only no restorable parts
containers.stream().filter(c -> c.getChildren().stream().allMatch(ch -> ch.getTags().contains("NoRestore"))).forEach(c -> c.setToBeRendered(false));
}
NOTE. Attempts to add the same code to methods with annotations #ProcessAdditions or #ProcessRemovals did not help: errors occurred and after the restart of the application no parts were displayed. So I added my code to the #PreSave method.
How do I clear the selection in my Eclipse RCP application?
Basically I would like to clear it on escape key down:
Display display = PlatformUI.createDisplay();
display.addFilter(SWT.KeyDown, new Listener() {
#Override
public void handleEvent(Event event) {
if (event.character == SWT.ESC) {
// if this is escape key, clear selection in the application
}
}
});
I thought I would be able to do something like PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService().clearSelection()/setSelection(IStructuredSelection.EMPTY), but no go.
You need to look up the ISelectionProvider rather than the ISelectionService. That will provide you with a setSelection() method.
You can get the selction provider from the site:
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActivePart().getSite().getSelectionProvider();
or
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor().getSite().getSelectionProvider();
Note that some of those return values could be null so add the appropriate checks.
You can't clear the selection provided by the selection service directly.
The selection the service returns is provided by a 'selection provider' (ISelectionProvider) for the current part.
You can get the selection provider from an IWorkbenchPart with IWorkbenchPart.getSite().getSelectionProvider().
ISelectionProvider has a setSelection method but it often does nothing or throws an exception so you may not be able to clear the selection.
I successfully extended the PyDev editor in Eclipse with a side-by-side display, but I can't copy the contents of the extra SourceViewer that I added. I can select some text in the display, but when I press Ctrl+C, it always copies the main PyDev editor's selected text.
I found an article on key bindings in Eclipse editors, but the code there seems incomplete and a bit out-of-date. How can I configure the copy command to copy from whichever SourceViewer has focus?
The reason I want to do this is that I've written a tool for live coding in Python, and it would be much easier for users to submit bug reports if they could just copy the display and paste it into the bug description.
David Green's article was a good start, but it took a bit of digging to make it all work. I published a full example project on GitHub, and I'll post a couple of snippets here.
The TextViewerSupport class wires up a new action handler for each command you want to delegate to the extra text viewer. If you have multiple text viewers, just instantiate a TextViewerSupport object for each of them. It wires up everything in its constructor.
public TextViewerSupport(TextViewer textViewer) {
this.textViewer = textViewer;
StyledText textWidget = textViewer.getTextWidget();
textWidget.addFocusListener(this);
textWidget.addDisposeListener(this);
IWorkbenchWindow window = PlatformUI.getWorkbench()
.getActiveWorkbenchWindow();
handlerService = (IHandlerService) window
.getService(IHandlerService.class);
if (textViewer.getTextWidget().isFocusControl()) {
activateContext();
}
}
The activateContext() method has a list of all the commands you want to delegate, and registers a new handler for each one. This was one of the changes from David's article; his ITextEditorActionDefinitionIds has been deprecated and replaced with IWorkbenchCommandConstants.
protected void activateContext() {
if (handlerActivations.isEmpty()) {
activateHandler(ITextOperationTarget.COPY,
IWorkbenchCommandConstants.EDIT_COPY);
}
}
// Add a single handler.
protected void activateHandler(int operation, String actionDefinitionId) {
StyledText textWidget = textViewer.getTextWidget();
IHandler actionHandler = createActionHandler(operation,
actionDefinitionId);
IHandlerActivation handlerActivation = handlerService.activateHandler(
actionDefinitionId, actionHandler,
new ActiveFocusControlExpression(textWidget));
handlerActivations.add(handlerActivation);
}
// Create a handler that delegates to the text viewer.
private IHandler createActionHandler(final int operation,
String actionDefinitionId) {
Action action = new Action() {
#Override
public void run() {
if (textViewer.canDoOperation(operation)) {
textViewer.doOperation(operation);
}
}
};
action.setActionDefinitionId(actionDefinitionId);
return new ActionHandler(action);
}
The ActiveFocusControlExpression gives the new handler a high enough priority that it will replace the standard handler, and it's almost identical to David's version. However, to get it to compile, I had to add extra dependencies to my plug-in manifest: I imported packages org.eclipse.core.expressions and org.eclipse.ui.texteditor.
I love an Emacs feature to copy selection to clipboard automatically. Is it possible to do the same on Eclipse?
Environment: Windows XP, Helios
To copy a String from Eclipse to the clipboard, you can use
void copyToClipboard (String toClipboard, Display display){
String toClipboard = "my String";
Clipboard clipboard = new Clipboard(display);
TextTransfer [] textTransfer = {TextTransfer.getInstance()};
clipboard.setContents(new Object [] {toClipboard}, textTransfer);
clipboard.dispose();
}
Then you can call this method from a MouseAdapter or KeyAdapter, depending on where you want to get your String from. In your case it could be MouseAdapter, which listens to doubleclicks, gets the current cursor position of the text, marks the word and then adds the String to the clipboard.
edit to answer a question: You can set up your own MouseAdapater and attach it to buttons, text fields or whateer you like. Here's an example for a button:
Button btnGo1 = new Button(parent, SWT.NONE);
btnGo1.setText("Go");
btnGo1.addMouseListener(new MouseAdapter() {
#Override
public void mouseDoubleClick(MouseEvent e) {
//do what you want to do in here
}
});
If you want to implement mouseUp and mouseDown events, too, you can just add MouseListenerinstead of the Adapter. The only advantage of the Adapter is, that you don't have to override the other methods of the interface.
Since the original question was to automatically get the selection of the text of an editor: the way to get the selection from an editor is explained here.
You can try this plugin. Along with auto copy points mentioned in Eclipse show number of lines and/or file size also addressed.
I have to bind my editor widget objects in property sheet.So that i can the property of my widget from property view.
Please help me on this, if possible provide me some code snippets.
You have a good example in the Getting started with Properties
Using the Properties view is simple enough.
Since it shows properties for the selected object, the first step to using it is to make sure that the workbench selection service knows about the object selected in your view. There’s an entire Eclipse Corner article written on the subject of the selection service
public void createPartControl(Composite parent) {
viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
viewer.setContentProvider(new ViewContentProvider());
viewer.setLabelProvider(new ViewLabelProvider());
getSite().setSelectionProvider(viewer);
viewer.setInput(getViewSite());
}
Once you have your view contributing to the workbench selection, you need to make sure that the objects that your view is selecting contribute properties
(extract)
public class Person implements IPropertySource {
private String name;
private Object street;
private Object city;
public Person(String name) {
this.name = name;
this.street = "";
this.city = "";
}
public Object getEditableValue() {
return this;
}
public IPropertyDescriptor[] getPropertyDescriptors() {
return new IPropertyDescriptor[] {
new TextPropertyDescriptor("name", "Name"),
new TextPropertyDescriptor("street", "Street"),
new TextPropertyDescriptor("city", "City")
};
}
I indicated earlier that this solution is “not necessarily [the] most correct”. This is because, for this to work, my domain object needs to know about the very view-centric (and Eclipse-centric) notion of being a property source; in short, there is a tight-coupling between the model and view and this not a good thing™.
Using adapter is a better approach, as described in this article:
Person should implement IAdaptable.
See also this recent article on how to create a custom property view
how to hack the Properties View to listen only to a specific view.
The isImportant() method is the one which decides whether to create an IPage for the specific IWorkbenchPart or not.
The idea is to override that method and return false for all the workbenchPart that we are not interested in. Lets create the view first:
<view
class="com.eclipse_tips.views.CustomPropertiesView"
icon="icons/sample.gif"
id="com.eclipse-tips.views.customePropertiesView"
name="My Properties View">
</view>
The CustomPropertiesView should extend PropertySheet and override the isImportant():
public class CustomPropertiesView extends PropertySheet {
#Override
protected boolean isImportant(IWorkbenchPart part) {
if (part.getSite().getId().equals(IPageLayout.ID_PROJECT_EXPLORER))
return true;
return false;
}
}
In this case, I'm making the view only to respond to Project Explorer and ignore other views
According to this thread, the same principle should be valid for an Editor instead of a View.
The property sheet listens to the workbench page selection provider.
The selection provider depends on what viewer/editor is active.
Each editor/viewer provides their own selection provider to use when that editor/viewer is active.
This way the property sheet doesn't care who is active, it just listens to the selection provider.
That way depending upon the view, a different set of properties are displayed.
For example, the Navigator view provides IResource selections, so the property sheet then displays IResource properties when the Navigator is active.
The Workbench Selection mechanism is illustrated in this article
The ISelectionListener is a simple interface with just one method.
A typical implementation looks like this:
private ISelectionListener mylistener = new ISelectionListener() {
public void selectionChanged(IWorkbenchPart sourcepart, ISelection selection) {
if (sourcepart != MyView.this && // 1
selection instanceof IStructuredSelection) { // 2
doSomething(((IStructuredSelection) selection).toList()); // 3
}
}
};
Depending on your requirements your listener implementation probably needs to deal with the following issues as shown in the code snippet above:
In case we also provide selections (e.g. a view or editor) we should exclude our own selection events from processing. This avoids unexpected results when the user selects elements within our part (1).
Check whether we can handle this kind of selection (2).
Get the selected content from the selection and process it (3).