Eclipse Plugin: Opening dialogs alongside quickfix - java

I'm working on a plugin and am trying to add some additional information around the quickfix menu that is triggered by clicking on my custom markers.
I'm adding a method call in MarkerResolutionGenerator.getResolutions() to draw the new dialog window, but I'm having trouble getting it to agree with the quickfix dialog. I can get it to draw at the same time, but I can't control the position and it also draws an extra blank dialog in the background.
Any thoughts? Relevant code below. The first two methods are from my MarkerResolutionGenerator, and my custom class is below that. (I just copied it from an example, I'm more worried about getting it to behave before I work on the content.)
#Override
public IMarkerResolution[] getResolutions(IMarker marker)
{
IMarker problem = marker;
makeStuff();
...
}
private void makeStuff()
{
Display display = Activator.getDefault().getWorkbench().getDisplay();
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor()
.getSite().getWorkbenchWindow().getShell();
Shell myShell = new Shell(shell, SWT.NO_TRIM);
MyDialog md = new MyDialog(myShell);
md.open();
}
public class MyDialog extends Dialog
{
public MyDialog(Shell parentShell)
{
super(parentShell);
setShellStyle(SWT.CLOSE | SWT.MODELESS | SWT.BORDER | SWT.TITLE);
setBlockOnOpen(false);
}
#Override
protected Control createDialogArea(Composite parent)
{
Composite container = (Composite) super.createDialogArea(parent);
Button button = new Button(container, SWT.PUSH);
button.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false));
button.setText("Press me");
button.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
System.out.println("Pressed");
}
});
return container;
}
...
}

Do you really need to create another Shell? Why not just use the one you already have as parent for your dialog? It might be the reason for the "extra blank dialog in the background".
You should be able to set the initial position overriding getInitialLocation in your custom dialog:
#Override
protected Point getInitialLocation(Point initialSize) {
return new Point(10, 10); // x and y coordinates of the initial position
}

Related

View not updating synchronously

Before I go any further, here is my ViewPart class:
public class Exp extends ViewPart {
public static final String ID = "edu.bitsgoa.views.Exp"; //$NON-NLS-1$
public static Text text;
public Exp() {
}
#Override
public void createPartControl(final Composite parent) {
ScrolledComposite sc = new ScrolledComposite(parent, SWT.H_SCROLL | SWT.V_SCROLL);
Composite composite = new Composite(sc, SWT.NONE);
sc.setContent(composite);
composite.setLayout(new GridLayout(2, false));
text = new Text(composite, SWT.BORDER | SWT.WRAP | SWT.V_SCROLL | SWT.MULTI | SWT.READ_ONLY);
text.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
Font newFont=new Font(text.getDisplay(),new FontData("Monospace",10,SWT.NATIVE));
text.setFont(newFont);
GridDataFactory.fillDefaults().grab(true, true).hint(400, 400).applyTo(text);
sc.setExpandHorizontal(true);
sc.setExpandVertical(true);
sc.setMinSize(composite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
createActions();
initializeToolBar();
initializeMenu();
}
private void createActions() {
// Create the actions
}
private void initializeToolBar() {
IToolBarManager toolbarManager = getViewSite().getActionBars()
.getToolBarManager();
}
private void initializeMenu() {
IMenuManager menuManager = getViewSite().getActionBars()
.getMenuManager();
}
public void setFocus() {
// Set the focus
}
}
I have create this class to act as a console, so that I can print data on it from my custom plugin. This is how I display data on it (this may be a very naive approach, but works to some extent):
public static void display(final String message){
Display.getDefault().asyncExec(new Runnable() {
#Override
public void run() {
Exp.text.append(message);
Exp.text.append("\n");
}
});
}
This method is in some different class. Whenever I have to print something on the console, I called this method as:
Preparation.display("Calculating parameters...);
calculateParameters();
Preparation.display("Done");
Now, the problem is that in the above three lines, the data is not printed on the console as:
Calculating parameters...
(wait for some time, calculate parameters)
Done
Instead, the parameters are calculated first, and then everything is printed at once, as:
(wait for some time, calculate parameters)
Calculating parameters...
Done
I want it to be done synchronously, as I call the display method. I am very new to SWT and Java graphics in general. Any idea where I might be going wrong?
Thanks!
A long running task in the UI thread will lock up the UI and nothing will update until it finishes. You must use a background thread.
Since you are blocking the SWT readAndDispatch loop even operations you have done before to long running code starts may not happen until the code ends since they rely on the dispatch loop.
You can just use a normal Thread for the background code or you can use an Eclipse Job. Jobs allow you to update a 'progress monitor' which reports the work's progress.
In the background thread you can use the asyncExec or syncExec methods of Display to run code in the UI thread.
For more details see Eclipse Jobs and Background Processing

GXT Drag and drop from tree label to a widget

I just want to drag and drop an label from tree to a widget. I am using the below code and it is not getting dropped as a widget. Can you please help me how to display a widget as a dropped item.
final FlowLayoutContainer dropContainer = new FlowLayoutContainer();
dropContainer.setBorders(true);
DropTarget target = new DropTarget(dropContainer) {
#Override
protected void onDragDrop(DndDropEvent event) {
super.onDragDrop(event);
Widget window = (Widget) event.getData();
dropContainer.add(window);
}
};
target.setGroup("test");
target.setOverStyle("drag-ok");
Instead of creating widget, you can instantiate new window like below and set the properties of it.
final FlowLayoutContainer dropContainer = new FlowLayoutContainer();
dropContainer.setBorders(true);
DropTarget target = new DropTarget(dropContainer) {
#Override
protected void onDragDrop(DndDropEvent event) {
super.onDragDrop(event);
Window window = new Window();
window.setClosable(true);
window.setHeight(200);
window.setWidth(200);
};
target.setGroup("test");
target.setOverStyle("drag-ok");
}

Tabbing from field to field doesn't work (aka "tab order" in Java SWT)

I have a Java SWT desktop application with various pages etc. pp. It works perfectly well, except the tab order - not at all. When I am in "field 1" and press Tab on my keyboard, I want the application to jump to "field 2", so I don't have to click to the second field after I entered the information in the first one.
Generally there is the "setTabList", where you can set the right order for "tabbing through the form". My problem is I don't even need to set the order right, tabbing doesn't work at all.
When I am in a field of my form and press Tab, for a millisecond I can see the Windows "working circle" (or whatever it is called) and nothing happens. The cursor stays exactly at the same position. It won't jump to another field and I have no idea why.
Generally my code:
public void createControl(Composite parent) {
Composite container = new Composite(parent, SWT.BORDER);
setControl(container);
fieldOne = new StyledText(container, SWT.NONE);
fieldOne.setBounds(whatever);
fieldOne.addKeyListener(new KeyAdapter() {
public void keyReleased(KeyEvent arg0) {
txtChanged();
}
});
fieldTwo = new StyledText(container, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
fieldOne.setBounds(whatever);
fieldOne.addKeyListener(new KeyAdapter() {
public void keyReleased(KeyEvent arg0) {
txtChanged();
}
});
Control[] controls = { fieldOne, fieldTwo };
container.setTabList(controls);
}
Even if I leave the Control[] and container.setTabList rows out, nothing happens.
Any ideas?
In a StyledText control Tab normally just moves the cursor to the next tab stop inside the control. Ctrl+Tab moves to the next control.
You can override this with a traverse listener:
fieldOne.addTraverseListener(new TraverseListener() {
#Override
public void keyTraversed(final TraverseEvent e) {
if (e.detail == SWT.TRAVERSE_TAB_NEXT || e.detail == SWT.TRAVERSE_TAB_PREVIOUS) {
e.doit = true;
}
}
});
It is also possible that your key listener is interfering with normal operation. Use a ModifyListener if all you want to know is that the text has changed.

SWT Popup Composite unexpected disposal

So I've stolen this cool PopupComposite, and I am really satisfied with it.
There's just one issue. If it put a org.eclipse.swt.widgets.Text in it, I open the popup, focus the Text, and press ESC, then both the Text and the PopupComposite dispose themselves.
I really can't figure out where the dispose call is coming from. Is it a Shell issue? What Shell should I use with the popup?
SSCCE:
/**
*
* #author ggrec
*
*/
public class PopupCompositeTester
{
public static void main(final String[] args)
{
new PopupCompositeTester();
}
private PopupCompositeTester()
{
final Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new GridLayout(1, false));
createContents(shell);
shell.pack();
shell.open();
while (!shell.isDisposed())
{
if ( !display.readAndDispatch() )
display.sleep();
}
display.dispose();
}
private static void createContents(final Composite parent)
{
final Button button = new Button(parent, SWT.PUSH);
button.setText("Poke Me");
final PopupComposite popup = new PopupComposite(parent.getShell());
new Text(popup, SWT.NONE);
popup.pack();
button.addSelectionListener(new SelectionAdapter()
{
#Override public void widgetSelected(final SelectionEvent e)
{
popup.show( Display.getDefault().map(parent, null, button.getLocation()) );
}
});
}
}
The reason for this is because when you focus the text field and press Escape, the field sends a SWT.TRAVERSE_ESCAPE event to its parent shell. The shell (in your case not being a top-level shell) responds by calling Shell.close(). You can work around that by adding a traverse listener to your text field, which would cancel the event (code below).
new Text(popup, SWT.NONE).addTraverseListener(new TraverseListener() {
#Override
public void keyTraversed(TraverseEvent e) {
if(e.detail == SWT.TRAVERSE_ESCAPE) {
e.doit = false;
}
}
});
Keep in mind, this is a rather crude solution to your specific issue. I would not recommend using this for anything other than testing purposes. You can read more about this here -> http://help.eclipse.org/indigo/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fswt%2Fevents%2FTraverseEvent.html
And here: http://help.eclipse.org/helios/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fswt%2Fwidgets%2FShell.html
Because my "bug" is actually a normal behaviour of the SWT platform, I've used the following workaround:
/**
* Lazy initialization of the popup composite
*/
private void createPopup()
{
// popupContainer is now a field
if (popupContainer != null && !popupContainer.isDisposed())
return;
// ... create popup AND its contents ...
}
and in the button listener:
createPopup();
popup.show( Display.getDefault().map(parent, null, button.getLocation()) );
Thank you #blgt

How to update/refresh a view in an eclipse plug-in?

I have an eclipse plug-in with a single view (like the eclipse helloworld-view-plugin-project). In the view-file I get an event when I want to update the view.
In this view I have a GridData in a Group with multiple labels. I have several services which register to the programe and whose status should be shown in this GridData.
Edit: In order to better show my problem I updated this post and added the whole code:
CreatePartControl():
public void createPartControl(Composite _parent) {
parent = _parent;
createContents();
addBindings();
makeActions();
contributeToActionBars();
}
CreateContents():
protected void createContents() {
// fixed
checkIcon = //...
errorIcon = //...
smallFont = SWTResourceManager.getFont("Segoe UI", 7, SWT.NORMAL);
// content
gl_shell = new GridLayout(1, false);
//margins, etc. for gl_shell
parent.setLayout(gl_shell);
final Label lblGreeting = new Label(parent, SWT.NONE);
lblGreeting.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false, 1, 1));
lblGreeting.setText("Hi " + Preferences.getPreName());
// -- GROUP YOUR STATS (show all services)
createStatusGroupBox();
}
createStatusGroupBox():
private Group grpYourStatus = null; // outside the method for access in listener (below)
private void createStatusGroupBox() {
grpYourStatus = new Group(parent, SWT.NONE);
grpYourStatus.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 1, 1));
grpYourStatus.setText("Your upload status");
grpYourStatus.setLayout(new GridLayout(3, false));
// add message if no service is registered
if ( r.getServiceList().size() == 0 ) {
Label status = new Label(grpYourStatus, SWT.NONE);
status.setText("No service registered.");
new Label(grpYourStatus, SWT.NONE); //empty
new Label(grpYourStatus, SWT.NONE); //empty
}
// add labels (status, message, name) for each registered service
for ( IRecorderObject service : r.getServiceList() ) {
Label name = new Label(grpYourStatus, SWT.NONE);
Label status = new Label(grpYourStatus, SWT.NONE);
Label message = new Label(grpYourStatus, SWT.NONE);
message.setFont(smallFont);
message.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1));
service.getServiceViewItem().setLabelsAndIcons(name, status, message, checkIcon, errorIcon); //this also sets the values of the labels (label.setText(...) via data binding)
}
Unfortunately, I don't know what the right way is to update/reset it. I tried the following:
listener (which should update the view / the services-list):
r.addPropertyChangeListener(BindingNames.SERVICE_ADDED, new PropertyChangeListener() {
public void propertyChange(final PropertyChangeEvent evt) {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
// This "redraws" the view, but just places the whole content (generated in createStatusGroupBox()) above the other parts.
//Display.getCurrent().update();
//createStatusGroupBox();
//parent.layout(true);
//parent.redraw();
// disposes grpYourStatus-Group but doesn't show anything then
grpYourStatus.dispose();
createStatusGroupBox();
grpYourStatus.layout();
grpYourStatus.redraw();
}
});
}
});
I also tried the following statements (individually); all without success:
parent.redraw();
parent.update();
parent.layout();
parent.layout(true);
parent.refresh();
In this post I read the following:
createPartControls is that time of the life cycle of a view, where its
contained widgets are created (when the view becomes visible
initially). This code is only executed once during the view life
cycle, therefore you cannot add anything here directly to refresh your
view.
Eclipse parts typically update their content as a reaction to a
changed selection inside of the workbench (e.g. the user might click
on another stack frame in the debug view).
Unfortunately, I don't know what to else I could try and I didn't find anything helpful with searches... thank's for your help and suggestions!
I finally found the answer (together with AndreiC's help!):
my listener now looks like this:
r.addPropertyChangeListener(BindingNames.SERVICE_ADDED, new PropertyChangeListener() {
public void propertyChange(final PropertyChangeEvent evt) {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
// remove grpYourStatus from parent
grpYourStatus.dispose();
// add grpYourStatus (with updated values) to parent
createStatusGroupBox();
// refresh view
parent.pack();
parent.layout(true);
}
});
}
});
The rest is the same like the code above.
I do not know the API by heart, but have you tried parent.update()?

Categories