I'm working on adding a preference page to my eclipse application (Juno). I would like create something similar to what you see on the following Eclipse preference page: Eclipse (Juno) > Window Menu > Preferences > Java > Compiler > Building. That preference page appears to be created using org.eclipse.swt.widgets.Tree, but I'm not sure. If that is the case, how did they create the TreeItems? Are they org.eclipse.swt.widgets.TreeItems? I need to add StringFieldEditors and IntegerFieldEditors, or some type of fields (TextArea??), with some labels in front of them, that I could validate later on. From what I understand, it's not possible to add a Composite to a TreeItem, so how should I go around this problem? Any suggestion is greatly appreciated. Thanks.
Need to add that, since I can't use the Eclipse internal packages, is there other way to implement what I described above using the public API?
Here is an idea, but this code places the TreeItems contents under the tree. Thoughts?
Composite comp = getFieldEditorParent();
Tree tree = new Tree(comp, SWT.NONE);
tree.setLayout(new FillLayout());
tree.setHeaderVisible(true);
TreeItem item1 = new TreeItem(tree, SWT.NONE);
item1.setText("Name1");
TreeItem item11 = new TreeItem(item1, SWT.NONE);
item11.setText("Name11");
StringFieldEditor s11 = new StringFieldEditor(
"name11",
"label11:",
comp);
item11.setData(s11);
TreeItem item12 = new TreeItem(item1, SWT.NONE);
item12.setText("Name12");
StringFieldEditor s12 = new StringFieldEditor(
"name12",
"label12:",
comp);
item12.setData(s12);
item1.setExpanded(true);
item11.setExpanded(true);
item12.setExpanded(true);
TreeItem item2 = new TreeItem(tree, SWT.NONE);
item2.setText("Name2");
If you are interested in the implementation of any UI element in Eclipse, then install the Eclipse SDK (via Help > Install New Software...) and use the plug-in spy. The spy tells you which class implements the UI element (in your case it's org.eclipse.jdt.internal.ui.preferences.JavaBuildPreferencePage in the org.eclipse.jdt.ui bundle). Since the SDK includes the source, you can jump right there from the spy's pop-up and look for yourself how it's done.
The problem was solved by using org.eclipse.ui.forms.widgets.ExpandableComposite.
See the example below. I hope this helps someone :).
protected final void createFieldEditors()
{
// Create the ScrolledComposite to scroll horizontally and vertically
fScrolledComposite = new ScrolledComposite(
getFieldEditorParent(),
SWT.H_SCROLL | SWT.V_SCROLL);
//Displays the scrollbars when the window gets smaller
fScrolledComposite.setAlwaysShowScrollBars(false);
// Sets the minimum size for the composite to work for scrolling
fScrolledComposite.setMinSize(fCompositeWidth, fCompositeHeight);
fScrolledComposite.setExpandHorizontal(true);
fScrolledComposite.setExpandVertical(true);
Composite composite = new Composite(fScrolledComposite, SWT.NONE);
composite.setLayout(new GridLayout());
fScrolledComposite.setContent(composite);
// Sets up the toolkit.
Display display = composite.getDisplay();
toolkit = new FormToolkit(display);
// Creates a form instance.
form = toolkit.createForm(composite);
form.getBody().setLayout(new GridLayout());
form.setBackground(display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND));
form.setText("Model: " + SignalGeneratorDevice.MODEL_ID);// Sets title of the Preference page
// Add the three main nodes to the preference page
addNode1();
}
/**
* Adds the first node to the preference page
*/
private void addNode1()
{
ExpandableComposite expandableComposite = createExpandableComposite(
"Signal Generator Device Host/Port:",
true);
Composite childComposite = createChildComposite(expandableComposite);
//Builds fields here (StringFieldEditor, IntegerFieldEditor, etc.)
..................
}
/**
* Creates an ExpandableComposite that will be added to the preference page
*
* #param label
* #param expanded
* #return
*/
private ExpandableComposite createExpandableComposite(
String label,
boolean expanded)
{
ExpandableComposite expandableComposite = null;
if (expanded) {
expandableComposite = toolkit.createExpandableComposite(
form.getBody(),
ExpandableComposite.TWISTIE | ExpandableComposite.CLIENT_INDENT
| ExpandableComposite.EXPANDED);
} else {
expandableComposite = toolkit
.createExpandableComposite(
form.getBody(),
ExpandableComposite.TWISTIE
| ExpandableComposite.CLIENT_INDENT);
}
expandableComposite.setText(label);
expandableComposite.setBackground(form.getBackground());
expandableComposite.addExpansionListener(new ExpansionAdapter() {
#Override
public void expansionStateChanged(
ExpansionEvent e)
{
form.pack();
}
});
GridData gd = new GridData();
expandableComposite.setLayoutData(gd);
return expandableComposite;
}
/**
* Creates a child composite for an ExpandableComposite
*
* #param expandableComposite
* #return
*/
private Composite createChildComposite(
ExpandableComposite expandableComposite)
{
Composite childComposite = new Composite(expandableComposite, SWT.None);
GridData gd = new GridData(GridData.FILL_BOTH);
gd.horizontalSpan = 2;
//gd.horizontalAlignment = GridData.END;
childComposite.setLayoutData(gd);
expandableComposite.setClient(childComposite);
return childComposite;
}
Related
I'm trying to add an Eclipse status trimbar contribution where the contents of the contribution (i.e., child elements' text) dynamically change. Note that I'm not trying to add "line, column" information into the status bar.
Ideally, the contribution's width should adapt to the width of its contents, a bit like what happens in VSCode:
However, if that isn't easily feasible, an acceptable alternative would be to have a "fixed" width for the status trimbar, or even a fixed width for each individual child (since I don't intend to have children appearing and disappearing).
Below is what I've tried. How do you think I should do this if nothing I've tried for the past 2 days worked?
In case you think the problem might actually be an Eclipse bug, note that I'm using Eclipse version 2021-06 (4.20.0) on Linux.
What I have tried
I have this in plugin.xml:
<extension
point="org.eclipse.ui.menus">
<menuContribution
locationURI="toolbar:org.eclipse.ui.trim.status">
<toolbar
id="some.package.StatusTrimBarContribution">
<control
class="some.package.StatusTrimBarContribution">
</control>
</toolbar>
</menuContribution>
</extension>
I've tried doing this in at least 4 different ways. As a reference, here is the class StatusTrimBarContribution:
public class StatusTrimBarContribution extends WorkbenchWindowControlContribution {
// A
private static String currText = /* see below */;
private Label m_lbl = null;
private Label m_lbl2 = null;
private Control m_root = null;
public StatusTrimBarContribution() {
// Register to String event
}
#Override
public void dispose() {
// Unregister from String event
}
#Override
protected Control createControl(Composite parent) {
// B
}
#Subscribe // From guava
private void someEventHandler(String event) {
currText = "lp_much_longer";
if (m_lbl != null) {
m_lbl.setText();
m_root.getParent().requestLayout();
}
}
}
Attempt #1
In this attempt we add an intermediary Composite between the labels and parent, we use a GridLayout on the intermediary, and we add a GridData into m_lbl.
// A
private static String currText = "empty";
// B
#Override
protected Control createControl(Composite parent) {
GridLayout gl = new GridLayout(2, false);
Composite comp = new Composite(parent, SWT.NONE);
comp.setLayout(gl);
m_lbl = new Label(comp, SWT.RIGHT);
m_lbl.setText(currText);
GridDataFactory.defaultsFor(m_lbl).hint(200, SWT.DEFAULT).applyTo(m_lbl);
m_lbl2 = new Label(comp, SWT.RIGHT);
m_lbl2.setText("lbl2");
m_root = comp;
return comp;
}
The result is that the labels are too tall and get truncated. Note that I've also tried setting the margin height to 0, and, while it's better than below, the labels would still get truncated.
Attempt #2
Compared to #1, we remove the intermediary Composite, and instead use the layout directly on parent. Also, we remove the GridData, because, at this point, why not.
// A
private static String currText = "empty";
// B
#Override
protected Control createControl(Composite parent) {
GridLayout gl = new GridLayout(2, false);
parent.setLayout(gl);
m_lbl = new Label(parent, SWT.RIGHT);
m_lbl.setText(currText);
m_lbl2 = new Label(parent, SWT.RIGHT);
m_lbl2.setText("lbl2");
m_root = m_lbl;
return m_lbl;
}
The result is the same as before, except, additionally, that m_lbl is not large enough to hold the text:
Attempt #3
Compared to #2, we additionally remove the layout.
// A
private static String currText = "empty";
// B
#Override
protected Control createControl(Composite parent) {
m_lbl = new Label(parent, SWT.RIGHT);
m_lbl.setText(currText);
m_lbl2 = new Label(parent, SWT.RIGHT);
m_lbl2.setText("lbl2");
m_root = m_lbl;
return m_lbl;
}
The labels are no longer too tall, however, the width of the labels is still to small for the text:
Attempt #4
Compared to #3, we initially assign a very long string into m_lbl.
// A
// Yes, this is ridiculous
private static String currText = " ".repeat(60);
// B
#Override
protected Control createControl(Composite parent) {
m_lbl = new Label(parent, SWT.RIGHT);
m_lbl.setText(currText);
m_lbl2 = new Label(parent, SWT.RIGHT);
m_lbl2.setText("lbl2");
m_root = m_lbl;
return m_lbl;
}
The result is that both labels are completely visible, but now m_lbl2 has the same width as m_lbl, which is far more than I want. Plus, if the user's font is different from mine, the width of the labels might become too large or too small due to the initial string.
Using the minimum width setting of GridData works for me:
#Override
protected Control createControl(final Composite parent)
{
final Composite comp = new Composite(parent, SWT.NONE);
GridLayoutFactory.fillDefaults().numColumns(2).applyTo(comp);
m_lbl = new Label(comp, SWT.RIGHT);
m_lbl.setText("label 1");
GridDataFactory.fillDefaults().grab(true, false).minSize(200, SWT.DEFAULT).applyTo(m_lbl);
m_lbl2 = new Label(comp, SWT.RIGHT);
m_lbl2.setText("lbl2");
GridDataFactory.fillDefaults().grab(true, false).minSize(100, SWT.DEFAULT).applyTo(m_lbl2);
m_root = comp;
return comp;
}
Note: Changing the layout of parent is against the rules, it could damage the layout of other components.
I have a pretty large ZEST Tree, displaying a Hashtree (Merkletree). Because of its size and limited available space it gets so compressed you can't read it anymore:
Therefore I want to be able to grab more space than the actual shell has, and implement a scrolling/dragging option to move around with the mouse.
However, I can't find a subelement in which I can contain it, which doesn't get filled into the space I have.
I already have tried SashForm (org.eclipse.swt.custom.SashForm), but it couldn't become bigger than the window.
Is there a possibility to implement my plan or is it generally not supported in SWT?
I know little about Zest, thus you should first look if Zest itself offers zooming and/or scrolling.
If there is no built-in support, you can use SWT's ScrolledComposite. See here for more information:
Detailed article: http://www.codeaffine.com/2016/03/01/swt-scrolledcomposite/
Code snippets: https://www.eclipse.org/swt/snippets/ (search for ScrolledComposite)
Layout: Java SWT - ScrolledComposite inside Group
By setting the style of the Graph to SWT.V_SCROLL | SWT.H_SCROLL you can make the graph scrollable:
Graph graph = new Graph(shell, SWT.H_SCROLL | SWT.V_SCROLL);
After some time I got it working in a decent way. I use a simple PaintListener with the method setSize. For the Zooming I use the class org.eclipse.gef.editparts.ZoomManager. I found one big disatvantage, this class needs a lot of performance and there are certainly other solutions as well.
I hope the code makes clear why and how.
public class ZoomableZestGraph extends Composite {
private GraphViewer graphViewer;
private Graph graph;
public ZoomableZestGraph(Composite parent, int style) {
super(parent, style);
this.setLayout(new GridLayout(1, true));
this.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1,1));
//create a GraphViewer and Graph
graphViewer = new GraphViewer(this, SWT.V_SCROLL | SWT.H_SCROLL);
graph = graphViewer.getGraphControl();
graph.setLayoutAlgorithm(new TreeLayoutAlgorithm(LayoutStyles.NO_LAYOUT_NODE_RESIZING), true);
graph.setHorizontalScrollBarVisibility(Graph.ALWAYS);
graph.setVerticalScrollBarVisibility(Graph.ALWAYS);
//Fill our graph with some nodes and connect them
GraphNode node1 = new GraphNode(graph, SWT.NONE, "Earendil");
GraphNode node2 = new GraphNode(graph, SWT.NONE, "Elros");
GraphNode node3 = new GraphNode(graph, SWT.NONE, "Elrond");
GraphNode node4 = new GraphNode(graph, SWT.NONE, "Elladan");
GraphNode node5 = new GraphNode(graph, SWT.NONE, "Elrohir");
GraphNode node6 = new GraphNode(graph, SWT.NONE, "Arwen");
new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, node1, node2);
new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, node1, node3);
new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, node2, node4);
new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, node2, node5);
new GraphConnection(graph, ZestStyles.CONNECTIONS_DIRECTED, node2, node6);
/*
This graphViewer consists of 2 components: the control and the graph (Figure)
We want to give the control a size by the layout and the graph a custom, bigger value.
For the control (graphViewer.getControl) I simply grab all available space
*/
GridDataFactory.fillDefaults().grab(true, true).applyTo(graphViewer.getControl());
//For the graph we have to create a PaintListener.
graph.addPaintListener(new PaintListener() {
#Override
public void paintControl(PaintEvent e) {
graph.setSize(1300, 1080);
}
});
//The Graph now fills the shell/parent composite,
//but the actual graph size can be set as we want in the paint //listener
//Zooming with the class org.eclipse.gef.editparts.ZoomManager
//As arguments we need a ScalableFigure which we receive by graph.getRootLayer and the Viewport.
ZoomManager zoomManager = new ZoomManager(graph.getRootLayer(), graph.getViewport());
//we bind the zoom mechanic to a simple mouse wheel listener
graph.addMouseWheelListener(new MouseWheelListener() {
#Override
public void mouseScrolled(MouseEvent e) {
if (e.count < 0) {
zoomManager.zoomOut();
} else {
zoomManager.zoomIn();
}
}
});
//We give the focus to our graphViewer, so it receives the MouseWheel Events
graphViewer.getControl().forceFocus();
}
#Override
protected void checkSubclass() {
//we are a composite subclass
}
}
Note: I didn't include the imports
Title says it all. Let's say I have a right-click menu with "Strikethrough selected text" option. When I have selected some text in jtextpane, right-click --> "Strikethrough selected text" , and the selected text gets strikedthrough.
Any ideas?
Swing text components use Actions to provide the various formatting features of a text pane.
Following is the code for the UnderlineAction of the StyledEditorKit.
public static class UnderlineAction extends StyledTextAction {
/**
* Constructs a new UnderlineAction.
*/
public UnderlineAction() {
super("font-underline");
}
/**
* Toggles the Underline attribute.
*
* #param e the action event
*/
public void actionPerformed(ActionEvent e) {
JEditorPane editor = getEditor(e);
if (editor != null) {
StyledEditorKit kit = getStyledEditorKit(editor);
MutableAttributeSet attr = kit.getInputAttributes();
boolean underline = (StyleConstants.isUnderline(attr)) ? false : true;
SimpleAttributeSet sas = new SimpleAttributeSet();
StyleConstants.setUnderline(sas, underline);
setCharacterAttributes(editor, sas, false);
}
}
}
So basically you will need to create your own "StrikeThroughAction" by replacing the "underline" StyleConstants methods to use the "strikethrough" StyleConstants methods.
Once you create a Action you can then use the Action by creating a JMenuItem or JButton with the Action. When the component is clicked the strike through attribute will then be added to the selected text.
in your right click action
objJTextPane.setContentType( "text/html" );
String[] args = objJTextPane.getText().split(objJTextPane.getSelectedText());
objJTextPane.setText("<strike>" + objJTextPane.getSelectedText() + "</strike>"+ args[1].toString());
apply your logic in splitting string.
I've got an issue with the drag and drop support for my tree items within a tab, the simple piece of code below works well on Windows XP/Seven, Ubuntu, Fedora and RedHat 4 but fails on RedHat 5.
#Override
protected Control createDialogArea(Composite parent) {
Composite composite = (Composite) super.createDialogArea(parent);
setShellStyle(getShellStyle() | SWT.RESIZE);
TabFolder tabFolder = new TabFolder(composite, SWT.NONE);
tabFolder.setLayoutData(new GridData(GridData.FILL_BOTH));
TabItem tab = new TabItem(tabFolder, SWT.NONE);
tab.setText("TabName");
/*
* TabItem 1 Content:
*/
TreeViewer tree = new TreeViewer(tabFolder, SWT.SINGLE|SWT.BORDER);
tree.setLabelProvider(provider);
tree.setContentProvider(provider);
tree.getTree().setHeaderVisible(true);
tree.getTree().setLayoutData(new GridData(GridData.FILL_BOTH));
TreeColumn tc = new TreeColumn(tree.getTree(), SWT.NONE, 0);
tc.setText("Name");
tc.setWidth(100);
tab.setControl(tree.getTree());
tree.setInput(provider.getInput());
/*
* Drag&Drop Support
*/
Transfer[] transfers = new Transfer[] { TextTransfer.getInstance()};
DragDropItemsSupport dndItemsListener = new DragDropItemsSupport(tree);
tree.addDragSupport(DND.DROP_MOVE, transfers, dndItemsListener);
tree.addDropSupport(DND.DROP_MOVE, transfers, dndItemsListener);
return composite;
}
When I said "works well", I'm able to pass through the method dragOver of ViewerDropAdapter on mentioned hosts.
#Override
public void dragOver(DropTargetEvent event) {
if (event.item != null)
System.out.println("Drag over : " + ((TreeItem)event.item).getText());
}
Is someone has a explanation, a way to investigate, or a solution :) ?
I see the same thing on a TableViewer in a TabItem in a TabFolder on Centos 5. Haven't tested on other OS. Can be fixed by changing to CTabFolder and CTabItem.
I've been tasked with creating a Composite that contains two TableViewers. The top table contains a single row of editable cells. These table cells will be used to filter data in the bottom table. There are a number of things that are not working properly, but I'll limit my inquiry, here, to one in particular. The TableViewers' tables extend beyond the width and height of the Composite that contains them, and I am not able to view table columns beyond the right edge (or rows of the bottom table that extend below the bottom) of the Composite. The Composite's horizontal scroll bar scrolls properly, but only as far as the width of the Composite (not surprisingly). I'm sure it is as simple as tweaking GridData or SWT constants during construcion. Sadly, I've tried several different combinations without success. Here's a snippet of my relevant code:
public class ControlledColumnFilterTableComposite<T> extends Composite {
private TableViewer filterViewer;
private TableViewer mainViewer;
public ControlledColumnFilterTableComposite(Composite parent,
IControlledColumnTableContentProvider<T> content) {
super(parent, SWT.H_SCROLL);
createComposite(parent, content);
}
private void createComposite(Composite parent,
IControlledColumnTableContentProvider<T> content) {
this.setLayout(new GridLayout(1, false));
GridData data = getLayoutData(parent);
this.setLayoutData(data);
addHorizontalBarListener();
this.filterViewer = createFilterViewer(parent, content);
this.mainViewer = createMainViewer(parent, content);
}
private TableViewer createFilterViewer(Composite parent,
IControlledColumnTableContentProvider<T> content) {
TableViewer viewer = new TableViewer(this, SWT.MULTI
| SWT.FULL_SELECTION | SWT.BORDER);
viewer.getTable().setHeaderVisible(true);
viewer.getTable().setLinesVisible(true);
viewer.setContentProvider(content);
ControlledColumnTableMetadata<T> metadata = content.getMetadata();
for (int i = 0; i < metadata.getBean().getDeclaredFields().length; i++) {
getViewerColumn(viewer, metadata.getBean().getDeclaredFields()[i],
true);
}
return viewer;
}
private TableViewer createMainViewer(Composite parent,
IControlledColumnTableContentProvider<T> content) {
TableViewer viewer = new TableViewer(this, SWT.MULTI | SWT.V_SCROLL
| SWT.FULL_SELECTION | SWT.BORDER);
viewer.getTable().setHeaderVisible(false);
viewer.getTable().setLinesVisible(true);
viewer.setContentProvider(content);
viewer.setInput(((IPagingContentProvider<T>) content)
.getModelProvider().getTableRows());
ControlledColumnTableMetadata<T> metadata = content.getMetadata();
for (int i = 0; i < metadata.getBean().getDeclaredFields().length; i++) {
getViewerColumn(viewer, metadata.getBean().getDeclaredFields()[i],
false);
}
viewer.getTable().setLayoutData(getLayoutData(parent));
/*
* I've tried getLayoutData(this) and I've also tried manipulating the
* grabExcessHorizontalSpace and grabExcessVerticalSpace on the returned
* GridData without getting the desired results
*/
return viewer;
}
private TableViewerColumn getViewerColumn(TableViewer viewer, Field field,
boolean listen) {
final TableViewerColumn viewerColumn = new TableViewerColumn(viewer,
SWT.NONE);
final TableColumn column = viewerColumn.getColumn();
setColumnProperties(viewer, column, field);
viewerColumn.setLabelProvider(getColumnLabelProvider(field));
// Only the filter TableViewer should have Listeners and EditingSupport
if (listen) {
// add sorting support
viewerColumn.getColumn().addListener(SWT.Selection,
new SortListener(field));
// add support for saving column width preferences
viewerColumn.getColumn()
.addControlListener(createControlListener());
// add editing support
viewerColumn.setEditingSupport(getEditingSupport(viewer, field));
}
return viewerColumn;
}
private void setColumnProperties(TableViewer viewer, TableColumn column,
Field field) {
ControlledColumnTableMetadata<T> metadata = ((IControlledColumnTableContentProvider<T>) viewer
.getContentProvider()).getMetadata();
column.setText(metadata.getColumnHeader(field));
column.setToolTipText(metadata.getColumnHeader(field));
if (metadata.isVisible(field)) {
column.setWidth(metadata.getColumnWidth(field));
column.setResizable(true);
column.setMoveable(true);
} else {
column.setWidth(0);
column.setResizable(false);
column.setMoveable(false);
}
}
private GridData getLayoutData(Composite parent) {
GridLayout layout = (GridLayout) parent.getLayout();
// Layout the viewer
GridData gridData = new GridData();
gridData.verticalAlignment = GridData.FILL;
gridData.horizontalAlignment = GridData.FILL;
gridData.horizontalSpan = layout.numColumns;
gridData.grabExcessHorizontalSpace = true;
gridData.grabExcessVerticalSpace = true;
return gridData;
}
...
}
Any suggestions are GREATLY appreciated. Thanks, in advance.
dont do this
GridData data = getLayoutData(parent); // inside getLayoutData: GridLayout layout = (GridLayout) parent.getLayout();
this.setLayoutData(data);
setLayout should be used by composite which arranges child-controls (this.setlayout). same as this.someControl.setLayoutData(). In your case: parent handles where ControlledColumnFilterTableComposite is placed and ControlledColumnFilterTableComposite handles how TableViewer are arranged. This means that you should never call: parent.getLayout() and this.setLayoutData() because you might not now which Layout parent uses and using invalid LayoutData leads to some exceptions.
try this
this.setLayout(new GridLayout(1,false));
this.filterViewer = createFilterViewer();
this.filterViewer.getTable().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,true));
this.mainViewer = createMainViewer();
this.mainViewer.getTable().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,true));
GridLayout works as table in HTML - places controls in cells. SWT.FILL means that control will fill sorounding cell horizontally and vertically, and true (3rd and 4th argument) means that cell will expand to maximum available size horizontally and vertically
remove the H_SCROLL, If you want Scrolling in your Composite use ScrolledComposite