On Windows and Linux, when holding down the Ctrl key one can move up and down using the caret keys without changing the selection. The table shows some visual feedback.
I've played with an SWT snippet which uses TableCursor but it seems half-baked, because it introduced a couple of new bugs - e.g. when pressing Ctrl+End, it jumped back to the previous selection after releasing the Ctrl key.
How to get or set this "focused" row?
This doesn't look like a property that can be get/set directly, but you can detect the focused row from paint event and custom paint the focus.
Add a Listener to your table for SWT.PaintItem event:
handleEvent(PaintEvent e) {
if (e.detail & SWT.FOSCUSED != 0)
myFocusedRow = ((Table)e.widget).indexOf((TableItem)e.item);
...
if (e.item == myFocusedItem)
e.gc.drawFocus(e.x, e.y, e.width, e.height);
}
I'm not sure this is exactly what you're looking for, but if you've wrapped your Table in a TableViewer, you can use a TableViewerEditor as part of the cell-editing support. (I believe you can use the focus-functionality of TableViewerEditor without actually having any cell editing.)
This actually overrides the operating system's focus handling but allows you to customize the focus handling programatically. I've used this to enable keyboard traversal for cell editing.
Here's some quick and dirty sample code that can support focusing a cell. (Untested. It's possible, for example, that cell editing support must be enabled for the TableViewerEditor support to work.)
FocusCellHighlighter cellHighlighter = new FocusCellHighlighter(tableViewer);
TableViewerFocusCellManager focusManager = new TableViewerFocusCellManager(tableViewer, cellHighlighter);
TableViewerEditor.create(tableViewer, focusCellManager, new ColumnViewerActivationStrategy(tableViewer), TableViewerEditor.KEYBOARD_NAVIGATION);
You can then get the focused cell by:
ViewerCell focusedCell = viewer.getColumnViewerEditor().getFocusCell();
TableItem focusedItem = focusedCell != null ? focusedCell.getItem() : null;
Note that this is only enabled in Eclipse >= 3.3.
To detect whether a TableItem is focused you can add a Listener of type SWT.EraseItem or SWT.PaintItem to the table and let it check if the bit flag SWT.FOCUSED is set in the detail field of the Event. (See also this Eclipse forum post.)
I could not find any API to set the focused item, but there is an ugly work around: post mouse events that simulate a click on the item. This requires the item to be selected and be visible on the display. The following utility class contains a method that does this:
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Widget;
/**
* Utility class for tables.
*
* #author Henno Vermeulen
*/
public final class Tables {
private Tables() {
}
/**
* Shows and selects the table <code>item</code> and lets it get the
* keyboard focus.
*
* <p>
* Windows has a "focused" row (drawn with a dotted line) that can be moved
* independently of the selected row (when pressing ctrl + up/down). This
* method ensures that this focused row is made equal to the selected row so
* that the selection does not jump to an unwanted location when the user
* uses the up or down arrow on the keyboard.
*
* <p>
* Implementation detail: there is no API to get/set the focused row (see
* also <a href="https://www.eclipse.org/forums/index.php/t/241852/">this
* post</a> and <a href=
* "http://stackoverflow.com/questions/8852574/swt-table-how-to-set-get-focused-row">
* this one</a>), so we use a filthy hack: faking a mouse click in the
* table.
*/
public static void selectAndFocus(TableItem item) {
fakeMouseClickTableItem(item);
}
private static void fakeMouseClickTableItem(TableItem item) {
Table table = item.getParent();
table.showItem(item);
Point cursorLocation = item.getDisplay().getCursorLocation();
fakeMouseClick(table, getCenter(item.getBounds(0)));
item.getDisplay().setCursorLocation(cursorLocation);
}
private static Point getCenter(Rectangle bounds) {
return new Point(bounds.x + bounds.width / 2,
bounds.y + bounds.height / 2);
}
/**
* Actually moves the mouse cursor to the given <code>location</code> so
* that the OS gives the correct click behavior.
*/
private static void fakeMouseClick(Control control, Point location) {
control.getDisplay().setCursorLocation(control.toDisplay(location));
control.getDisplay()
.post(createMouseEvent(SWT.MouseDown, control, location));
control.getDisplay()
.post(createMouseEvent(SWT.MouseUp, control, location));
}
public static Event createMouseEvent(int type, Widget widget,
Point position) {
Event e = new Event();
e.display = widget.getDisplay();
e.widget = widget;
e.type = type;
e.x = position.x;
e.y = position.y;
e.count = 1;
e.button = 1;
e.doit = true;
return e;
}
}
Related
When editing multiple cell content in nattable using MultiLineTextCellEditor the opened CellEditorDialog text area collapses when enter is clicked instead of OK button as in the below attached image.
Before Pressing Enter
After Pressing Enter
MultiLineTextCellEditor textCellEditor = new MultiLineTextCellEditor(true) {
/**
* {#inheritDoc}
*/
#Override
public boolean openInline(final IConfigRegistry configRegistry, final List<String> configLabels) {
return true;
}
/**
* {#inheritDoc}
*/
#Override
public boolean openMultiEditDialog() {
return super.openMultiEditDialog();
}
};
configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITOR, textCellEditor, DisplayMode.NORMAL,
COMMENT_CNG_LBL + "_" + COMMENT_COL_NUMBER);
configRegistry.registerConfigAttribute(EditConfigAttributes.CELL_EDITABLE_RULE, IEditableRule.ALWAYS_EDITABLE,
DisplayMode.EDIT, COMMENT_CNG_LBL + "_" + COMMENT_COL_NUMBER);
But the similar issue doesn't occur when using a TextCellEditor in nattable.
I need Multi Line inline cell editing feature so i cannot go for TextCellEditor
Please let me know if there some specific configuration that i am missed.
Do I understand correctly that for single cell you want to edit multiline text inline?
Because it looks like a bug. When the multi-value dialog is opened for a multiline value, the dialog should show a multiline input field. But in your case it only shows a single line input field. So I assume the configurations collide here.
Feel free to open a ticket via Bugzilla.
We followed this tutorial -> https://www.danklco.com/posts/2013/06/changing-cq-components-design-path.html to create a global design path solution for multiple components to share design which works perfect for classic UI design dialog.
public class GlobalDesignDialogTag extends BaseTag
{
/**
* Global design properties attribute name.
*/
public static final String GLOBAL_DESIGN_PROPERTIES_ATTRIBUTE_NAME = "globalDesignProperties";
private static final long serialVersionUID = 1L;
#Override public final int doEndTag()
{
final String
globalDesignPath =
getCurrentDesign().getPath() + "/" + JCR_CONTENT + "/" + getCurrentResource().getName();
EditContext editContext = getEditContext();
String currentDesignPath = getCurrentDesign().getPath() + "/jcr:content/default-page/par-main/secondary-nav";
if (WCMMode.fromRequest(getSlingRequest()) == WCMMode.DESIGN)
{
// Set the design dialog content path to be global design level instead of template
editContext.setContentPath(globalDesignPath);
}
if (AuthoringUIMode.fromRequest(getSlingRequest()).equals(AuthoringUIMode.TOUCH)) {
editContext.setContentPath(globalDesignPath);
}
final Resource globalDesignResource = getResourceResolver().getResource(globalDesignPath);
if (globalDesignResource != null)
{
// Set an attribute containing global design properties as ${currentStyle.propertyName} will still
// point to the default design dialog path under the template.
pageContext.setAttribute(GLOBAL_DESIGN_PROPERTIES_ATTRIBUTE_NAME,
globalDesignResource.adaptTo(ValueMap.class));
}
return EVAL_PAGE;
}
/**
* Gets the EditContext from the pageContext.
*
* #return The EditContext from the pageContext.
*/
private EditContext getEditContext()
{
return (EditContext) pageContext.getAttribute(DefineObjectsTag.DEFAULT_EDIT_CONTEXT_NAME);
}
/**
* Gets the current design from the pageContext.
*
* #return The current design from the pageContent.
*/
private Design getCurrentDesign()
{
if (pageContext.getAttribute(DefineObjectsTag.DEFAULT_CURRENT_DESIGN_NAME) != null)
{
return (Design) pageContext.getAttribute(DefineObjectsTag.DEFAULT_CURRENT_DESIGN_NAME);
}
return getCurrentResource().adaptTo(Design.class);
}
}
Now We need to to upgrade classic UI to touch UI which involves lots components upgrade, but we still wish to keep most core java code unchanged or as less change as possible.
But the above tutorial method editContext.setContentPath(globalDesignPath);
does not work with touch UI design dialog it seems...
Please see below image illustration
So what happened with the pink lines , in classic UI design dialog are expected behaviour, using editContext.setContentPath(globel) it does save the design dialog secondary-nav node in the design template level.
But with the green lines, using the same code example above, triggled design dialog save from touch UI, editContext.setContentPath(globel) it does not look like did anything ... it saved node under demo-site/jcr:content/default-page/par-main/secondary-nav which is the page template level of design ... other secondary-nav component in different page design template will not able to access the properties.
Ideally, the touch UI design dialog should do what blue lines does... by saving the dialog, it should updated the demo-site/jcr:content/secondary-nav node property
After investigation, I think the most suspicious line is editContext.setContentPath(globel) , is it in touch UI, it has a new kinda of (EditContext) object or API to save touch UI design dialog into the customized path?
Please suggest with code sample if possible.
Thanks
Check if iniside /content node your page is pointing to correct cq:designpath.
I found ResizeColumnHideShowLayer class at nattable version 1.6.
(about https://bugs.eclipse.org/bugs/show_bug.cgi?id=521486)
That is work fine for normal column headers only.
But, if I collapse a column group, no adjust size to fit window. (no increasing column size)
How can I solve the problem?
Is there way to resize other columns to fit window automatically increase?
Thank you.
Currently not because the ColumnGroupExpandCollapseLayer is taking care of hiding collapsed columns.
I found solution by myself!
It works fine very well. :-)
I was run based on NatTable v1.6 version.(downloaded yesterday)
I think this is a basic feature, so I hope this feature will be included in the next NatTable version.
In narrow tables, behavior that collapsing column group means that may be someone want to view other column data more widely.
Overview (Problem screen and solved screen)
I explain using two application(before, after) screen shot.
Refer to bottom image if you want understand my issue easily at once.
Problem screen
enter image description here
Improved screen
enter image description here
Solution summary :
Add event listener to ColumnGroupExpandCollapseLayer.
(HideColumnPositionsEvent, ShowColumnPositionsEvent)
Handle above events.
Get column indices which is hidden by collapsed
Execute MultiColumnHideCommand with the indices
Layer structure of my test code
↑ ViewportLayer (top layer)
| SelectionLayer
| ColumnGroupExpandCollapseLayer
| ResizeColumnHideShowLayer
| ColumnGroupReorderLayer
| ColumnReorderLayer
| DataLayer (base layer)
Implementation code is below:
void method() {
...
columnGroupExpandCollapseLayer.addLayerListener(new ILayerListener() {
#Override
public void handleLayerEvent(ILayerEvent event) {
boolean doRedraw = false;
//It works for HideColumnPositionsEvent and ShowColumnPositionsEvent
// triggered by ColumnGroupExpandCollapseCommandHandler
if (event instanceof HideColumnPositionsEvent) {
HideColumnPositionsEvent hideEvent = (HideColumnPositionsEvent)event;
Collection<Range> columnPositionRanges = hideEvent.getColumnPositionRanges();
Collection<Integer> convertIntegerCollection = convertIntegerCollection(columnPositionRanges);
int[] positions = convertIntPrimitiveArray(convertIntegerCollection);
//Execute command to hide columns that was hidden by collapsed column group.
MultiColumnHideCommand multiColumnHideCommand = new MultiColumnHideCommand(resizeColumnHideShowLayer, positions);
resizeColumnHideShowLayer.doCommand(multiColumnHideCommand);
doRedraw = true;
}else if (event instanceof ShowColumnPositionsEvent) {//called by ColumnGroupCollapsedCollapseCommandHandler
ShowColumnPositionsEvent showEvent = (ShowColumnPositionsEvent)event;
Collection<Range> columnPositionRanges = showEvent.getColumnPositionRanges();
Collection<Integer> positions = convertIntegerCollection(columnPositionRanges);
//Execute command to show columns that was hidden by expanded column group.
MultiColumnShowCommand multiColumnShowCommand = new MultiColumnShowCommand(positions);
resizeColumnHideShowLayer.doCommand(multiColumnShowCommand);
//Set whether or not to redraw table
doRedraw = true;
}
if (doRedraw) {
natTable.redraw();
}
}
/**
* Merge position values within several Ranges to Integer collection
*/
private Collection<Integer> convertIntegerCollection(Collection<Range> rangeCollection) {
Iterator<Range> rangeIterator = rangeCollection.iterator();
Set<Integer> mergedPositionSet = new HashSet<Integer>();
while (rangeIterator.hasNext()) {
Range range = rangeIterator.next();
mergedPositionSet.addAll(range.getMembers());
}
return mergedPositionSet;
}
/**
* Convert Integer wrapper object to primitive value
*/
private int [] convertIntPrimitiveArray(Collection<Integer> integerCollection) {
Integer [] integers = (Integer [])integerCollection.toArray(new Integer[integerCollection.size()]);
int [] positionPrimitives = new int[integers.length];
for (int i = 0 ; i < integers.length ; i++) {
positionPrimitives[i] = integers[i].intValue();
}
return positionPrimitives;
}
});
}
I want to show a custom menu item for a ToolItem when it is in the toolbar's overflow menu. This seems to be the purpose of the set_proxy_menu_item method. However, when I set the proxy menu item via using this method, it has no effect on the overflow menu. It still uses the default menu item (with the ToolItem's name as the label).
Here is a simple project (in Vala) that reproduces the problem. It creates a tiny window containing a toolbar with 3 buttons. The window should be small enough that all but one of these buttons is in the overflow menu.
When I view the overflow menu, I should see "proxy" for as the menu item for edit_button. Instead, I see "edit".
What am I doing wrong?
void main(string[] args) {
Gtk.init(ref args);
MainWindow main_window = new MainWindow();
main_window.show_all();
Gtk.main();
}
public class MainWindow : Gtk.Window {
public MainWindow() {
destroy.connect(Gtk.main_quit);
title = "Main Window";
Gtk.Box main_box = new Gtk.Box(Gtk.Orientation.VERTICAL, 6);
add(main_box);
Gtk.Toolbar toolbar = new Gtk.Toolbar();
main_box.pack_start(toolbar, false, false);
Gtk.ToolButton new_button = new Gtk.ToolButton.from_stock(Gtk.Stock.NEW);
Gtk.ToolButton edit_button = new Gtk.ToolButton.from_stock(Gtk.Stock.EDIT);
Gtk.ToolButton delete_button = new Gtk.ToolButton.from_stock(Gtk.Stock.DELETE);
Gtk.MenuItem proxy = new Gtk.MenuItem.with_label("proxy");
proxy.show_all();
edit_button.set_proxy_menu_item("proxy_menuitem", proxy);
toolbar.add(new_button);
toolbar.add(edit_button);
toolbar.add(delete_button);
Gtk.Label content_label = new Gtk.Label("Placeholder");
main_box.pack_start(content_label, false, false);
}
}
It turns out that set_proxy_menu_item is temporary, and should be used in a response to the create-menu-proxy signal. I can't find this documented anywhere on the web, but here it is from the Gtk+ source code:
/**
* GtkToolItem::create-menu-proxy:
* #tool_item: the object the signal was emitted on
*
* This signal is emitted when the toolbar needs information from #tool_item
* about whether the item should appear in the toolbar overflow menu. In
* response the tool item should either
* <itemizedlist>
* <listitem>call gtk_tool_item_set_proxy_menu_item() with a %NULL
* pointer and return %TRUE to indicate that the item should not appear
* in the overflow menu
* </listitem>
* <listitem> call gtk_tool_item_set_proxy_menu_item() with a new menu
* item and return %TRUE, or
* </listitem>
* <listitem> return %FALSE to indicate that the signal was not
* handled by the item. This means that
* the item will not appear in the overflow menu unless a later handler
* installs a menu item.
* </listitem>
* </itemizedlist>
*
* The toolbar may cache the result of this signal. When the tool item changes
* how it will respond to this signal it must call gtk_tool_item_rebuild_menu()
* to invalidate the cache and ensure that the toolbar rebuilds its overflow
* menu.
*
* Return value: %TRUE if the signal was handled, %FALSE if not
**/
So the right way to solve this would be something like:
edit_button.create_menu_proxy.connect(on_create_menu_proxy);
...
private bool on_create_menu_proxy(Gtk.ToolItem tool_item) {
Gtk.MenuItem proxy = new Gtk.MenuItem.with_label("proxy");
tool_item.set_proxy_menu_item("proxy_menuitem", proxy);
return true;
}
You may not actually want to create a new proxy every time the signal is fired, but that should be enough to help anyone reading this get started.
This is a question about which general approach to take, so I haven't included any code.
Requirement:
I need to create a page within a multi-page editor that has two vertical sections in it. The top section has a tree and the bottom section has a text field. The tree and text field should fill their respective sections. Each section should scroll independently and there should be a splitter in between. When the editor is opened I want the visible area of the editor to be divided among the two sections based on some ratio I provide. Then when the editor is resized, the two sections will adjust proportionally to maintain the ratio and fit the page. This way there won't be scroll bars on the editor page itself, just the two sections.
Proposed Solution:
My idea was to add a SashForm to the editor page and set the size of the SashForm to be the same as the editor's visible area. Then I'd add a resize listener to the editor page and adjust the size of the SashForm so that it stays in sync with the page. However, I can't find a way to get the editor's visible area. So when I add the SashForm it just makes each section big enough to fit its data and adds a scroll on the editor page itself.
Is it possible to meet my requirement?
Success! The key was to listen for resize events on the ScrolledForm. I've only tested on Fedora but I'll take a look on Windows soon. The only thing that bothers me is that the use of the buffer constants seems a little hacky.
/**
* Form page that contains a sash form and a button. The sash form is dynamically sized to ensure
* that it always fills the available space on the page.
*/
public class SashFormDemoPage extends FormPage
{
/** Horizontal buffer needed to ensure that content fits inside the page */
private static final int HORIZONTAL_BUFFER = 8;
/** Vertical buffer needed to ensure that content fits inside the page */
private static final int VERTICAL_BUFFER = 12;
/** Percentages of the sash form occupied by the tree and text box respectively */
private static final int[] SASH_FORM_WEIGHTS = new int[] {30, 70};
/**
* Constructor
*
* #param editor parent editor
*/
public SashFormDemoPage(ComponentEditor editor)
{
super(editor, "sashFormDemoPage", "Demo");
}
/**
* {#inheritDoc}
*/
#Override
protected void createFormContent(IManagedForm managedForm)
{
// Set page title
ScrolledForm scrolledForm = managedForm.getForm();
scrolledForm.setText("SashForm Demo");
// Set page layout and add a sash form
final Composite parent = scrolledForm.getBody();
parent.setLayout(new GridLayout());
final SashForm sashForm = new SashForm(parent, SWT.VERTICAL);
// Add a tree as the top row of the sash form and fill it with content
FormToolkit toolkit = managedForm.getToolkit();
int style = SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER;
Tree tree = toolkit.createTree(sashForm, style);
for (int i = 0; i < 40; i++) {
TreeItem parentNode = new TreeItem(tree, SWT.NONE);
parentNode.setText("parent-" + i);
for (int j = 0; j < 3; j++) {
TreeItem childNode = new TreeItem(parentNode, SWT.NONE);
childNode.setText("child-" + i + "-" + j);
}
}
// Add a text box as the bottom row of the sash form and fill it with content
style = SWT.MULTI | SWT.V_SCROLL | SWT.WRAP | SWT.BORDER;
Text text = toolkit.createText(sashForm, null, style);
String message = "";
for (int i = 0; i < 100; i++) {
message += "This is a test of the layout demo system. This is only a test. ";
}
text.setText(message);
// Add button below sash form
final Button button = toolkit.createButton(parent, "Test", SWT.NONE);
// Add resize listener to sash form's parent so that sash form always fills the page
parent.addControlListener(new ControlListener() {
#Override
public void controlMoved(ControlEvent e)
{
// Stub needed to implement ControlListener
}
#Override
public void controlResized(ControlEvent e)
{
GridData data = new GridData();
Point size = parent.getSize();
data.widthHint = size.x - HORIZONTAL_BUFFER;
data.heightHint = size.y - button.getSize().y - VERTICAL_BUFFER;
sashForm.setLayoutData(data);
}
});
// Set sash form's weights and pack its parent so that the initial layout is correct
sashForm.setWeights(SASH_FORM_WEIGHTS);
parent.pack();
}
}
Why set the size of the SashForm explicitly? Why not just add it to the parent Composite of the editor? The parent Compositehas a FillLayout and thus the SashForm with fill the editor area automatically.