get apply button in preference page + swt eclipse - java

I have MyPreferencePage which extends PreferencePage. Inside the PreferencePage there is a method getApplyButton() I am overriding that method to get the apply button.
I need the apply button because there are some validators that I put on the data in the preference dialog and till the all the data is not correct I dont want the apply button to be enabled.
My code
public class DefaultColorsPreferencePage extends PreferencePage implements IWorkbenchPreferencePage {
#Override
protected Control createContents(Composite parent) {
this.container = new Composite(parent, SWT.NONE);
this.container.setLayout(new GridLayout(1, false));
GridData gd_area = new GridData(SWT.FILL, SWT.FILL, true, true);
this.container.setLayoutData(gd_area);
this.defalutColoringGroup = new Group(container, SWT.NONE);
this.defalutColoringGroup.setLayout(new GridLayout(1, false));
this.defalutColoringGroup.setLayoutData(gd_area);
this.defalutColoringGroup.setText(Constants.DESCRIPTION_TEXT);
this.defaultColoringCheckBox = new Button(defalutColoringGroup, SWT.CHECK);
this.defaultColoringCheckBox.setText(Constants.DEFAULT_COLORING_BUTTON_TEXT);
errorLabel = new Label(defalutColoringGroup, SWT.NONE);
errorLabel.setText("Expression is not valid, enter a valid expression and try again!");
errorLabel.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_RED));
errorLabel.setVisible(false);
this.viewer = tableviewerComposite.createTableViewer(defalutColoringGroup);
this.viewer.setContentProvider(new ArrayContentProvider());
try {
contentProvider = new ContentProvider();
this.viewer.setInput(contentProvider.getScenarios());
} catch (ParserConfigurationException | SAXException | IOException e) {
e.printStackTrace();
}
return container;
}
#Override
protected Button getApplyButton() {
super.getApplyButton();
}
}
//Method to create columns of the table
private void createTableColumns(final TableViewer viewer,final Composite defalutColoringGroup) {
TableViewerColumn scenariosColumn = createTableViewerColumn(viewer,Constants.SCENARIOS_COLUMN_NAME,Constants.SCENARIOS_COLUMN_NUMBER);
ScenariosLabelProvider scenariosLabelProvider = new ScenariosLabelProvider();
scenariosColumn.setLabelProvider(scenariosLabelProvider);
scenariosColumn.setEditingSupport(new ScenariosEditingSupport(viewer));
//more columns
}
//Editing Support for column
public class ScenariosEditingSupport extends EditingSupport {
private final TableViewer viewer;
private final CellEditor editor;
private final DefaultColorsPreferencePage preferencePage;
public ScenariosEditingSupport(TableViewer viewer) {
super(viewer);
this.viewer = viewer;
this.editor = new TextCellEditor(viewer.getTable());
this.preferencePage = new DefaultColorsPreferencePage();
}
#Override
protected CellEditor getCellEditor(Object element) {
return editor;
}
#Override
protected boolean canEdit(Object element) {
return true;
}
#Override
protected Object getValue(Object element) {
return ((Content) element).getExpression();
}
#Override
protected void setValue(Object element, Object changedExpression) {
String expression = String.valueOf(changedExpression);
if(Repository.isExpressionValid(expression)){
((Content) element).setExpression(expression);
viewer.update(element, null);
}
else{
preferencePage.setValid(false);
preferencePage.setErrorMessage("Expression is not valid, enter a valid expression and try again!");
((Content) element).setExpression(expression);
viewer.update(element, null);
}
}
}

You don't access the Apply button to enable / disable the preference page. Instead call the
setValid(false);
method of PreferencePage to disable Apply and OK.
Call setValid(true) when the page is OK.
You might also want to call the setErrorMessage or setMessage methods to set a message while the page is invalid.

Related

How can I prevent the Escape Key from closing a JFace Dialog

I would like to be able to have it so that the Escape key doesn't close a JFace dialog pop up.
In the code I have prepared you can see this behaviour by running the main method, when you press escape.
public class TestDialog extends Dialog
{
private Label status;
private String title;
public TestDialog(Shell parentShell, String title)
{
super(parentShell);
this.title = title;
setShellStyle(getShellStyle() & ~SWT.CLOSE);
}
#Override
protected void configureShell(Shell shell)
{
super.configureShell(shell);
shell.setText(this.title);
}
#Override
protected Control createDialogArea(Composite parent)
{
Composite composite = (Composite) super.createDialogArea(parent);
composite.setLayout(new GridLayout(1, false));
status = new Label(composite, SWT.NONE);
status.setText("Hello World");
composite.pack();
parent.pack();
return composite;
}
#Override
protected Control createButtonBar(Composite parent)
{
return parent;
}
public static void main(String[] args) {
TestDialog d = new TestDialog(new Shell(), "Test");
d.open();
}
}
You can add a key listener to the parent Composite control and get the keyEvent to match with SWT.ESC and write your custom code there what you want to perform when ESC key is pressed. Now it will prevent the JFace dialog from closing.
#Override
protected Control createDialogArea(final Composite parent) {
Composite composite = (Composite) super.createDialogArea(parent);
composite.setLayout(new GridLayout(1, false));
status = new Label(composite, SWT.NONE);
status.setText("Hello World");
composite.pack();
parent.pack();
composite.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
String string = "";
if (e.keyCode == SWT.ESC) {
string += "ESCAPE - keyCode = " + e.keyCode;
}
if (!string.isEmpty()) {
// do nothing
// here I am printing in console
System.out.println(string);
}
}
});
return composite;
}

How to trigger EditingSupport on TableViewer

I'm currently writing an application where I use a JFace TableViewer. There's a Button next to the table that adds a new item to it. The TableViewer has only one column in this example, but this column has an EditingSupport assigned to it.
That all works as expected. A new item is added to the table when I click the button and it's also selected automatically.
However, what I want to achieve is that the EditingSupport of this column is triggered for the new item, i.e. when a new item is added, the cell within the new row should automatically show the text input that shows up when you use the editing support.
How would I achieve that? Do I need to fake up a mouse event or is there something in the API that I'm missing?
Here's some example code that roughly shows the current state of the table
public static void main(String[] args)
{
final Display d = new Display();
Shell s = new Shell(d);
s.setLayout(new FillLayout());
List<Project> projects = new ArrayList<>();
Table table = new Table(s, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION | SWT.BORDER);
table.setHeaderVisible(true);
TableViewer viewer = new TableViewer(table);
viewer.setContentProvider(ArrayContentProvider.getInstance());
viewer.setInput(projects);
TableViewerColumn nameColumn = new TableViewerColumn(viewer, SWT.NONE);
nameColumn.getColumn().setText("Project name");
nameColumn.setLabelProvider(new ColumnLabelProvider()
{
#Override
public String getText(Object element)
{
Project p = (Project) element;
return p.name;
}
});
// Add the editing support
nameColumn.setEditingSupport(new ProjectNameEditingSupport(viewer));
// Button to add new item
Button add = new Button(s, SWT.PUSH);
add.setText("Add");
add.addListener(SWT.Selection, e -> {
// Create the new item
Project project = new Project("Project");
projects.add(project);
// Refresh the table
viewer.refresh();
// Select the item
viewer.setSelection(new StructuredSelection(project), true);
// TODO: Trigger editing support
});
for (TableColumn c : viewer.getTable().getColumns())
c.pack();
s.pack();
s.open();
s.setSize(300, 400);
while (!s.isDisposed())
{
if (!d.readAndDispatch())
d.sleep();
}
d.dispose();
}
private static class Project
{
private String name;
public Project(String name)
{
this.name = name;
}
}
public static class ProjectNameEditingSupport extends EditingSupport
{
private final TableViewer viewer;
private final CellEditor editor;
public ProjectNameEditingSupport(TableViewer viewer)
{
super(viewer);
this.viewer = viewer;
this.editor = new TextCellEditor(viewer.getTable());
}
#Override
protected CellEditor getCellEditor(Object element)
{
return editor;
}
#Override
protected boolean canEdit(Object element)
{
return true;
}
#Override
protected Object getValue(Object element)
{
return ((Project) element).name;
}
#Override
protected void setValue(Object element, Object userInputValue)
{
((Project) element).name = String.valueOf(userInputValue);
viewer.update(element, null);
}
}
IIRC you can use ColumnViewer::editElement in order to activate the editing control. The first method argument is the element that should be edited, the second argument is the index of the column on which the editor should be opened.
For example:
viewer.editElement( project, 0 );

How to validate a Text with Jface Dialog?

i created a Dialog with two input fields with the following Code.
public class CCIDDialog extends TitleAreaDialog {
private Text ccidText;
private Text descriptionText;
private String CCID;
private String description;
public CCIDDialog(Shell parentShell) {
super(parentShell);
}
public void create() {
super.create();
setTitle(_title);
setMessage("Bitte geben Sie die CCID "+firstchar+"xxxxxxx und eine Beschreibung ein (max. 7-stellig): ", IMessageProvider.INFORMATION); }
#Override
protected Control createDialogArea(Composite parent) {
Composite area = (Composite) super.createDialogArea(parent);
Composite container = new Composite(area, SWT.NONE);
container.setLayoutData(new GridData(GridData.FILL_BOTH));
GridLayout layout = new GridLayout(2, false);
container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
container.setLayout(layout);
createCCID(container);
createDescription(container);
return area;
}
private void createCCID(Composite container) {
Label lbtFirstName = new Label(container, SWT.NONE);
lbtFirstName.setText("CCID (ohne "+firstchar+"): ");
GridData dataCCID = new GridData();
dataCCID.grabExcessHorizontalSpace = true;
dataCCID.horizontalAlignment = GridData.FILL;
ccidText = new Text(container, SWT.BORDER);
ccidText.setLayoutData(dataCCID);
}
private void createDescription(Composite container) {
Label lbtLastName = new Label(container, SWT.NONE);
lbtLastName.setText("Beschreibung: ");
GridData dataDescription = new GridData();
dataDescription.grabExcessHorizontalSpace = true;
dataDescription.horizontalAlignment = GridData.FILL;
descriptionText = new Text(container, SWT.BORDER);
descriptionText.setLayoutData(dataDescription);
}
#Override
protected boolean isResizable() {
return true;
}
// save content of the Text fields because they get disposed
// as soon as the Dialog closes
private void saveInput() {
CCID = ccidText.getText();
description = descriptionText.getText();
}
#Override
protected void okPressed() {
saveInput();
super.okPressed();
}
public String getCCID() {
return CCID;
}
public String getDescription() {
return description;
}
}
Is there a way to validate the ccidtext?
If the user type more then 7 chars, he must get a notification and should not be able to continue the dialog. I read so lot at the internet but can`t find a solution for this problem.
Thank u so much for your help.
JonasInt
You can use Text.addModifyListener to add a ModifyListener which will be called each time the text is changed. You can also use Text.addVerifyListener to add VerifyListener which can actually prevent text being entered.
For TitleAreaDialog you can call setMessage or setErrorMessage to display a message in the title area.
You can disable the OK button on the dialog using:
getButton(IDialogConstants.OK_ID).setEnabled(false);
Note: getButton(xxx) can return null if you call it too early in the dialog construction. Buttons are created during the createContents method after the createDialogArea method has been called.
So you can access the buttons by overriding createContents like this:
#Override
protected Control createContents(final Composite parent)
{
Control control = super.createContents(parent);
// TODO access buttons here
return control;
}

Using wizard and ScrolledForm(jface and forms api)

I'm new to eclipse plugin - SWT development. I'm trying to create wizard page having number of text fields and combo boxes. For better look n feel I'm trying to use FormToolkit for creating components and add them in ScrolledForm. But with this nothing is rendered on wizard page at runtime and there is no error also.
Questions:
Is it possible to have scrolled container inside wizard page?
Can we mix JFace and forms api?
(removed unwanted code)
Here is wizard page code:
public class ContactWizardPage extends WizardPage {
private static int counter;
private Form form;
public ContactWizardPage() {
super("New Contact Wizard" + ++counter, "New Contact Wizard" + counter, null);
setMessage("Please enter contact info." + counter);
}
public void createControl(final Composite parent) {
createControlWithoutToolkit(parent);
// commenting out toolkit code
// createControlWithToolkit(parent);
}
public void createControlWithoutToolkit(final Composite parent) {
Composite composite = new Composite(parent, SWT.DEFAULT);
composite.setLayout(new GridLayout(2, true));
Label lblFirstName = new Label(composite, SWT.FLAT);
lblFirstName.setText("First Name");
Label lblLastName = new Label(composite, SWT.FLAT);
lblLastName.setText("Last Name");
Text txtFirstName = new Text(composite, SWT.FLAT);
Text txtLastName = new Text(composite, SWT.FLAT);
Label lblEmail = new Label(composite, SWT.FLAT);
lblEmail.setText("Email");
GridDataFactory.swtDefaults().span(2, 1).align(
SWT.FILL,
SWT.BEGINNING).applyTo(lblEmail);
Text txtEmail = new Text(composite, SWT.FLAT);
GridDataFactory.swtDefaults().span(2, 1).align(
SWT.FILL,
SWT.BEGINNING).applyTo(txtEmail);
setControl(composite);
}
public void createControlWithToolkit(final Composite parent) {
FormToolkit toolkit = new FormToolkit(Display.getCurrent());
ScrolledForm form = toolkit.createScrolledForm(parent);
Composite composite = form.getBody();
composite.setLayout(new GridLayout(2, true));
Label lblFirstName = toolkit.createLabel(composite, "First Name");
Label lblLastName = toolkit.createLabel(composite, "Last Name");
Text txtFirstName = toolkit.createText(composite, "");
Text txtLastName = toolkit.createText(composite, "");
Label lblEmail = toolkit.createLabel(composite, "Email");
GridDataFactory.swtDefaults().span(2, 1).align(
SWT.FILL,
SWT.BEGINNING).applyTo(lblEmail);
Text txtEmail = toolkit.createText(composite, "");
GridDataFactory.swtDefaults().span(2, 1).align(
SWT.FILL,
SWT.BEGINNING).applyTo(txtEmail);
setControl(composite);
}
}
Here is Wizard code:
public class SampleNewWizard extends Wizard implements INewWizard {
public SampleNewWizard() {
super();
setNeedsProgressMonitor(true);
}
#Override
public IWizardPage getNextPage(IWizardPage page) {
return super.getNextPage(page);
}
public void addPages() {
addPage(new ContactWizardPage());
addPage(new ContactWizardPage());
addPage(new ContactWizardPage());
addPage(new ContactWizardPage());
}
public boolean performFinish() {
return true;
}
public void init(IWorkbench workbench, IStructuredSelection selection) {
}
}
With this code first page of wizard shows fine but second page is never rendered properly. :(
here are screenshots:
first page:
second page:
The line
parent.getShell().setSize(240, 320);
is upsetting something (and is not something you should do in a wizard page as the Wizard class deals with sizing). Testing here it works fine without it (and I get your problem with it).
Make sure that you do not dispose the FormToolKit as long as the wizard is open. Paint events need the toolkit after createControl() has finished.
My solution is to create and dispose the FormToolKit in the wizard:
#Override
public void createPageControls(Composite pageContainer) {
toolkit = new FormToolkit(pageContainer.getDisplay());
super.createPageControls(pageContainer);
}
#Override
public void dispose() {
super.dispose();
if (toolkit != null) {
try { toolkit.dispose(); } catch (Exception e) {}
}
}
public FormToolkit getToolkit() {
return toolkit;
}
In the wizard pages you can than use ((FormWizard) getWizard).getToolkit() to get a reference to the wizard's form toolkit.
#Override
public void createControl(Composite parent) {
FormToolkit toolkit = ((FormWizard) getWizard()).getToolkit();
...
Hope this helps ...

Eclipse RCP: Generating views from form values

I want to build a user interface similar to the sketch below:
When the user fills out the form on the right and clicks the 'Plot!' button, a new closeable tab opens on the left with a chart.
I am new to RCP and have been following this tutorial. I am able to bring up tabs with charts triggered from a menu item. How do I go about:
creating the tab (view?) with the form
open a new chart tab when the user clicks the button
Edit
Here is my current code. It satisfies the basic requirements outlined in this question, but I am not sure if that is the best approach. I would be delighted if someone here can guide me in the right direction.
A view with the form; the button's listener invokes a command.
public class FormView extends ViewPart {
public static final String ID =
FormView.class.getPackage().getName() + ".Form";
private FormToolkit toolkit;
private Form form;
public Text text;
#Override
public void createPartControl(Composite parent) {
toolkit = new FormToolkit(parent.getDisplay());
form = toolkit.createForm(parent);
form.setText("Pie Chucker");
GridLayout layout = new GridLayout();
form.getBody().setLayout(layout);
layout.numColumns = 2;
GridData gd = new GridData();
gd.horizontalSpan = 2;
Label label = new Label(form.getBody(), SWT.NULL);
label.setText("Chart Title:");
text = new Text(form.getBody(), SWT.BORDER);
text.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
Button button = new Button(form.getBody(), SWT.PUSH);
button.setText("Plot");
gd = new GridData();
gd.horizontalSpan = 2;
button.setLayoutData(gd);
button.addMouseListener(new MouseAdapter() {
#Override
public void mouseDown(MouseEvent e) {
IHandlerService handlerService = (IHandlerService) getSite()
.getService(IHandlerService.class);
try {
handlerService.executeCommand(ShowChartHandler.ID, null);
} catch (Exception ex) {
throw new RuntimeException(ShowChartHandler.ID +
" not found");
}
}
});
}
#Override
public void setFocus() {
}
}
The command invoked by the button from the form. This opens a new view with a chart.
public class ShowChartHandler extends AbstractHandler implements IHandler {
public static final String ID =
ShowChartHandler.class.getPackage().getName() + ".ShowChart";
private int count = 0;
#Override
public Object execute(ExecutionEvent event) throws ExecutionException {
IWorkbenchWindow window = HandlerUtil.getActiveWorkbenchWindow(event);
try {
window.getActivePage().showView(ChartView.ID,
String.valueOf(++count), IWorkbenchPage.VIEW_ACTIVATE);
} catch (PartInitException e) {
e.printStackTrace();
}
return null;
}
}
The view with the chart. It looks up the form view and reads a value from a text field in the form (?!):
public class ChartView extends ViewPart {
public static final String ID =
ChartView.class.getPackage().getName() + ".Chart";
private static final Random random = new Random();
public ChartView() {
// TODO Auto-generated constructor stub
}
#Override
public void createPartControl(Composite parent) {
FormView form =
(FormView) Workbench.getInstance()
.getActiveWorkbenchWindow()
.getActivePage()
.findView(FormView.ID);
String title = form == null? null : form.text.getText();
if (title == null || title.trim().length() == 0) {
title = "Pie Chart";
}
setPartName(title);
JFreeChart chart = createChart(createDataset(), title);
new ChartComposite(parent, SWT.NONE, chart, true);
}
#Override
public void setFocus() {
// TODO Auto-generated method stub
}
/**
* Creates the Dataset for the Pie chart
*/
private PieDataset createDataset() {
Double[] nums = getRandomNumbers();
DefaultPieDataset dataset = new DefaultPieDataset();
dataset.setValue("One", nums[0]);
dataset.setValue("Two", nums[1]);
dataset.setValue("Three", nums[2]);
dataset.setValue("Four", nums[3]);
dataset.setValue("Five", nums[4]);
dataset.setValue("Six", nums[5]);
return dataset;
}
private Double[] getRandomNumbers() {
Double[] nums = new Double[6];
int sum = 0;
for (int i = 0; i < 5; i++) {
int r = random.nextInt(20);
nums[i] = new Double(r);
sum += r;
}
nums[5] = new Double(100 - sum);
return nums;
}
/**
* Creates the Chart based on a dataset
*/
private JFreeChart createChart(PieDataset dataset, String title) {
JFreeChart chart = ChartFactory.createPieChart(title, // chart title
dataset, // data
true, // include legend
true, false);
PiePlot plot = (PiePlot) chart.getPlot();
plot.setSectionOutlinesVisible(false);
plot.setLabelFont(new Font("SansSerif", Font.PLAIN, 12));
plot.setNoDataMessage("No data available");
plot.setCircular(false);
plot.setLabelGap(0.02);
return chart;
}
}
The perspective that ties it all together:
public class Perspective implements IPerspectiveFactory {
public void createInitialLayout(IPageLayout layout) {
layout.setEditorAreaVisible(false);
layout.addStandaloneView(FormView.ID, false,
IPageLayout.RIGHT, 0.3f,
IPageLayout.ID_EDITOR_AREA);
IFolderLayout charts = layout.createFolder("Charts",
IPageLayout.LEFT, 0.7f, FormView.ID);
charts.addPlaceholder(ChartView.ID + ":*");
}
}
I would recommend a different aproach. Eclipse has viewparts (views) and editors. It is easy to open multiple editors. Views are not so much for open multiple ones.
So my suggestion is, that you implement the part you call "FormView" as a StandAloneView and implement the "ChartView" as an editor.
I would also recommend to use a different listener for the button, so also the code will be executed when using the keyboard to click the button.
My proposal:
public class FormView extends ViewPart {
...
button.addSelectionListener(new SelectionAdapter() {
#Override
public void widgetSelected(SelectionEvent e) {
// this below can also be called by a command but you need to take care about the data, which the user put into the fields in different way.
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
IWorkbenchPage page = window.getActivePage();
ChartEditorInput input = new ChartEditorInput(text.getText(),...<other data you need to pass>);
try {
page.openEditor(input, ChartEditor.ID);
} catch (PartInitException e) {
e.printStackTrace();
}
}
});
ChartView needs to be changed to ChartEditor. See here http://www.vogella.de/articles/RichClientPlatform/article.html#editor_editorinput how that is done.
ChartEditorInput hereby is a class you need to implement aside the editor class, which holds the data.
In your perspective you call:
public void createInitialLayout(IPageLayout layout) {
String editorArea = layout.getEditorArea();
layout.setFixed(false);
layout.setEditorAreaVisible(true);
layout.addStandaloneView("your.domain.and.FormView", true,IPageLayout.RIGHT, 0.15f, editorArea);
Hope this helps!

Categories