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!
Related
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.
We have a large Java app that is used on both Windows and OSX.
We do custom Drag and Drop between 2 of our JTables.
On Windows, this works perfectly. The custom cursor is displayed as you drag over the target JTable.
On the Mac, the custom cursor is never displayed. Instead a gray rectangle (border only) is displayed when you start dragging. This rectangle is the width of the table column, and the height of the table. Our logging is showing that the dragOver() and dropActionChanged() methods are getting called, and we are setting the custom cursor. It just never gets displayed.
If I disable our custom cursor code, the same box is displayed - but it has the Circle/slash icon in the middle as well.
I want to get rid of the weird box, and display the custom cursor.
Excerpts from the code:
private class FileTransferHandler extends TransferHandler {
private static final long serialVersionUID = 1L;
private final Logger log = LogManager.getLogger();
private final CursorDragSourceListener dragSourceListener = new CursorDragSourceListener();
// Left out the Drop handling code that was here
#Override
public int getSourceActions( final JComponent c) {
log.debug("FileTransferHandler.getSourceAction: ");
return COPY | MOVE;
}
#Override
protected Transferable createTransferable( final JComponent c) {
log.debug("FileTransferHandler.createTransferable:");
List<iFilePage> pages = new ArrayList<iFilePage>();
// Left out the code that builds the pages list
DragSource.getDefaultDragSource().addDragSourceListener(dragSourceListener);
dragSourceListener.setCursorChoice(pages.size() == 1);
return new FilePageTransferable(pages);
}
#Override
protected void exportDone( final JComponent c,
final Transferable t,
final int action) {
log.debug("FileTransferHandler.exportDone: {}", action, t);
tblFixed.getSelectionModel().clearSelection();
DragSource.getDefaultDragSource().removeDragSourceListener(dragSourceListener);
return;
}
}
private static class CursorDragSourceListener implements DragSourceListener {
private Cursor singlePage = null;
private Cursor multiPage = null;
private Cursor badSinglePage = null;
private Cursor useCursor = null;
private boolean useSingle = false;
public CursorDragSourceListener() {
Toolkit toolkit = Toolkit.getDefaultToolkit();
URL url;
String name;
Image img;
url = FileUtils.getResourceURL("/images/page.png");
name = "DragPage";
img = toolkit.createImage(url);
singlePage = toolkit.createCustomCursor(img, new Point(16, 16), name);
url = FileUtils.getResourceURL("/images/badpage_stack.png");
name = "DragBadPage";
img = toolkit.createImage(url);
badSinglePage = toolkit.createCustomCursor(img, new Point(16, 16), name);
url = FileUtils.getResourceURL("/images/page_stack.png");
name = "DragPageStack";
img = toolkit.createImage(url);
multiPage = toolkit.createCustomCursor(img, new Point(16, 16), name);
return;
}
public void setCursorChoice( final boolean single) {
log.debug("CursorDragSourceListener.setCursorChoice: {}", single);
useSingle = single;
if (useSingle) {
useCursor = singlePage;
} else {
useCursor = multiPage;
}
return;
}
#Override
public void dropActionChanged( final DragSourceDragEvent dsde) {
log.debug("CursorDragSourceListener.dropActionChanged: {}", dsde.getDropAction(), useSingle);
if (dsde.getDropAction() == 2) {
if (!useSingle) {
useCursor = badSinglePage;
} else {
useCursor = singlePage;
}
} else {
if (useSingle) {
useCursor = singlePage;
} else {
useCursor = multiPage;
}
}
dsde.getDragSourceContext().setCursor(useCursor);
return;
}
#Override
public void dragOver( final DragSourceDragEvent dsde) {
try {
Object x = dsde.getDragSourceContext().getTransferable()
.getTransferData(DataFlavor.javaFileListFlavor);
log.trace("CursorDragSourceListener.dragOver: {}", (x != null) ? x.getClass().getSimpleName() : "null");
if (x instanceof ArrayList) {
dsde.getDragSourceContext().setCursor(useCursor);
}
} catch (Exception e) {
log.error("CursorDragSourceListener.dragOver:", e);
}
}
#Override
public void dragExit( final DragSourceEvent dse) {
}
#Override
public void dragEnter( final DragSourceDragEvent dsde) {
}
#Override
public void dragDropEnd( final DragSourceDropEvent dsde) {
}
}
After a bunch more checking and analysis, it turns out that our Custom Selection Model was causing this problem on OSX.
We have a selection model that allows you to select multiple individual cells, not just whole rows.
So the getMinSelectionindex() and getMaxSelectionIndex() methods returned dummy data, since we never used them.
That works fine on MS Win, but apparently the OSX drag and drop for JTable uses those calls.
After modifying our code to return reasonable values, the selection box is no longer as tall as the table.
The custom cursors appear most of the time, but still randomly disappear for no apparent reason.
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 ...
I have a webapp in which I need to get some data from the file and fill to the table. Here is the code of the page with this table:
public class Rules extends ContentPanel{
private final ServerManagementAsync serverManagementSvc = GWT.create(ServerManagement.class);
private ArrayList<PropertyItem> propslist;
private ArrayList<PropertyItem> itemArrayList;
private EditorGrid<PropertyItem> grid;
public Rules(final String customerId){
setLayout(new FlowLayout(10));
List<ColumnConfig> configs = new ArrayList<ColumnConfig>();
ColumnConfig column = new ColumnConfig();
column.setId("name");
column.setHeader("Name");
column.setWidth(220);
TextField<String> text = new TextField<String>();
text.setAllowBlank(false);
column.setEditor(new CellEditor(text));
configs.add(column);
column = new ColumnConfig();
column.setId("type");
column.setHeader("Type");
column.setWidth(220);
TextField<String> typeText = new TextField<String>();
typeText.setAllowBlank(false);
column.setEditor(new CellEditor(typeText));
configs.add(column);
column = new ColumnConfig();
column.setId("value");
column.setHeader("Value");
column.setWidth(220);
configs.add(column);
final ListStore<PropertyItem> store = new ListStore<PropertyItem>();
propslist = getPropslist(customerId);
for (PropertyItem propertyItem: propslist){
store.insert(propertyItem, 0);
}
ColumnModel cm = new ColumnModel(configs);
setHeading("Settings");
setFrame(true);
setWidth(600);
setLayout(new FitLayout());
grid = new EditorGrid<PropertyItem>(store, cm);
grid.setAutoExpandColumn("name");
grid.setBorders(true);
add(grid);
ToolBar toolBar = new ToolBar();
setTopComponent(toolBar);
setButtonAlign(Style.HorizontalAlignment.RIGHT);
addButton(new Button("Refresh", new SelectionListener<ButtonEvent>() {
#Override
public void componentSelected(ButtonEvent ce) {
store.insert(getPropslist(customerId), 5);
}
}));
addButton(new Button("Add", new SelectionListener<ButtonEvent>() {
#Override
public void componentSelected(ButtonEvent ce) {
store.commitChanges();
}
}));
}
public ArrayList<PropertyItem> getPropslist(String customerId){
itemArrayList = new ArrayList<PropertyItem>();
AsyncCallback<ArrayList<PropertyItem>> callback = new AsyncCallback<ArrayList<PropertyItem>>() {
#Override
public void onFailure(Throwable throwable) {
}
#Override
public void onSuccess(ArrayList<PropertyItem> propertyItems) {
itemArrayList = propertyItems;
Window.alert("read successful");
}
}
};
serverManagementSvc.getProperties(customerId, callback);
return itemArrayList;
}
}
When I run my app I See only columns names and no data in the cells(and no cells of course). As the example I used this one: Ext GWT 2.2.6 Explorer(Grid)
I don't understand what could cause such proplem. What can be the reason of this?
Because your propsList is being populated Asynchronously the grid is being rendered before the server call returns.
To fix this first make the store a private property like the grid
Next, move the code that populates your store:
for (PropertyItem propertyItem: propslist){
store.insert(propertyItem, 0);
}
into the onSuccess Method of your callback.
Lastly, you may also need to call :
grid.reconfigure(grid.getStore(), grid.getColumnModel());
Just to get the Grid to render again.
I have a TreeViewer, and I created a context menu with some actions.
With this code snippet below, I get the context menu for all tree items.
protected void createMasterPart(final IManagedForm managedForm, final Composite parent)
{
Tree t = toolkit.createTree(client, SWT.NULL);
GridData gd = new GridData(GridData.FILL_BOTH);
gd.heightHint = 20;
gd.widthHint = 100;
t.setLayoutData(gd);
toolkit.paintBordersFor(client);
section.setClient(client);
final SectionPart spart = new SectionPart(section);
managedForm.addPart(spart);
viewer = new TreeViewer(t);
viewer.addSelectionChangedListener(new ISelectionChangedListener()
{
public void selectionChanged(SelectionChangedEvent event)
{
managedForm.fireSelectionChanged(spart, event.getSelection());
}
});
viewer.setContentProvider(new MasterTreeContentProvider());
viewer.setInput(page.getEditor().getEditorInput());
m_newKeyAction = new AddNewKeyAction(viewer, parent.getShell());
m_newValueAction = new AddNewValueAction(viewer, parent.getShell());
hookContextMenu();
}
private void hookContextMenu()
{
MenuManager menuMgr = new MenuManager();
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(new IMenuListener() {
public void menuAboutToShow(IMenuManager manager)
{
fillContextMenu(manager);
}
});
Menu menu = menuMgr.createContextMenu(viewer.getControl());
viewer.getControl().setMenu(menu);
}
protected void fillContextMenu( IMenuManager manager )
{
manager.add( m_newKeyAction );
manager.add( m_newValueAction );
}
I want this context menu to be displayed only for tree items of particular type.
Please let me know how do I get this done.