nattable: how to disable single cell selection? - java

How to disable single cell selection when clicking? Example
I'm trying it that way:
class CustomDefaultSelectionBindings extends DefaultSelectionBindings {
#Override
protected void configureBodyMouseClickBindings(final UiBindingRegistry uiBindingRegistry) {
//do nothing
}
}
class CustomDefaultSelectionLayerConfiguration extends DefaultSelectionLayerConfiguration {
#Override
protected void addSelectionUIBindings() {
addConfiguration(new CustomDefaultSelectionBindings());
}
}
final SelectionLayer selectionLayer = new SelectionLayer(bodyDataLayer);
selectionLayer.addConfiguration(new CustomDefaultSelectionLayerConfiguration());
Thanks in advance.

You need to create the SelectionLayer without the default configuration
final SelectionLayer selectionLayer = new SelectionLayer(bodyDataLayer, false);
selectionLayer.addConfiguration(new CustomDefaultSelectionLayerConfiguration());
But with the above solution you could still select in the body because of the body mouse drag mode. The easy way would be to not using the SelectionLayer anyhow. Not sure about the other requirements you have.

Related

Multiple AjaxCheckBox did not work to control setEnabled

I'm quite new using Wicket framework.
Currently I'm working on to set the setEnabled of the TextField. In my case, I have two TextField to control using AjaxCheckbox. During my trial, I have no issue to setEnabled for the first TextField, but when I add second TextField with AjaxCheckbox, the second one didn't work, only the first one.
Is there something that I missed out?
The first one
mobileNo = new TextField<String>("mobileNo", new PropertyModel<String>(getModelObject(), "mobileNo")) {
#Override
protected void onConfigure() {
setEnabled(mobileNoCheckBoxValue);
}
};
mobileNo.setOutputMarkupPlaceholderTag(true);
form.add(mobileNo);
AjaxCheckBox mobileNoCheckBox = new AjaxCheckBox("mobileNoCheckBox", new PropertyModel<Boolean>(this, "mobileNoCheckBoxValue")) {
private static final long serialVersionUID = 1L;
#Override
protected void onUpdate(AjaxRequestTarget target) {
target.add(mobileNo);
}
};
form.add(mobileNoCheckBox);
and the second one
appliedAmount = new TextField<BigDecimal>("appliedAmount", new BigDecimalFormatProperty<BigDecimal>(getModel(), "appliedAmount")) {
#Override
protected void onConfigure() {
setEnabled(appliedAmountCheckBoxValue);
}
};
appliedAmount.setOutputMarkupPlaceholderTag(true);
form.add(appliedAmount);
AjaxCheckBox appliedAmountCheckBox = new AjaxCheckBox("appliedAmountCheckBox", new PropertyModel(this, "appliedAmountCheckBoxValue")) {
private static final long serialVersionUID = 1L;
#Override
protected void onUpdate(AjaxRequestTarget target) {
target.add(appliedAmount);
}
};
form.add(appliedAmountCheckBox);
Check your HTML code and make sure you use different id attribute values for <input type="checkbox" .../>.
If you have id attribute in your HTML template then better remove it completely and let Wicket to auto-generate it. The ids must be unique by HTML specification. But also Wicket uses them to lookup the HTML elements when sending their values with Ajax.
I guess when you click the second checkbox Wicket sends the state of the first one, which does not toggle.

What parent to set when calling FieldEditor#setEnabled?

I am building a preference page in Eclipse by extending the FieldEditorPreferencePage class. this page contains 2 fields : 1 BooleanFieldEditor (checkbox) and 1 FileFieldEditor. I would like to disable/enable the file field following the checkbox value.
I went up to something like this (some obvious code is not displayed):
public class PreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {
public static final String PREF_KEY_1 = "checkBoxPref";
public static final String PREF_KEY_2 = "filePref";
private FileFieldEditor pathField;
private BooleanFieldEditor yesOrNoField;
private Composite pathFieldParent;
#Override
protected void createFieldEditors() {
this.yesOrNoField = new BooleanFieldEditor(PREF_KEY_1, "Check this box!", getFieldEditorParent());
this.pathFieldParent = getFieldEditorParent();
this.pathField = new FileFieldEditor(PREF_KEY_2, "Path:", this.pathFieldParent);
addField(this.yesOrNoField);
addField(this.pathField);
boolean isChecked = getPreferenceStore().getBoolean(PREF_KEY_1);
updatePathFieldEnablement(! isChecked);
}
/**
* Updates the fields according to entered values
*/
private void updatePathFieldEnablement(boolean enabled) {
this.pathField.setEnabled(enabled, this.pathFieldParent);
}
#SuppressWarnings("boxing")
#Override
public void propertyChange(PropertyChangeEvent event) {
if (event.getProperty().equals(FieldEditor.VALUE) && event.getSource() == this.yesOrNoField) {
updatePathFieldEnablement(! (boolean) event.getNewValue());
}
super.propertyChange(event);
}
}
My question is about this second parameter in FieldEditor#setEnabled. This parameter is the parent composite of the FieldEditor's controls ("Used to create the controls if required" says the javadoc) . At first, I set the value with the return of getFieldEditorParent but then I got an exception "Different parent". So I ended storing it (cf. this.pathFieldParent) and give it back to setEnabled and it works (or it seems to work).
But I am not sure I am doing well, especially because I had to create a member in my class that means nothing to it (and I would have to create many of them if I had many fields to enable/disable).
Do you think I am doing well or is there a better way to provide this parent ? And could you explain to me why *setEnabled" needs it ?
Thanks.
You are using the default FLAT layout for the preference page. When this layout is used each call to getFieldEditorParent generates a new Composite so you have to make just one call and remember the correct parent. Using the GRID layout getFieldEditorParent always returns the same parent. This is the actual code:
protected Composite getFieldEditorParent() {
if (style == FLAT) {
// Create a new parent for each field editor
Composite parent = new Composite(fieldEditorParent, SWT.NULL);
parent.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
return parent;
}
// Just return the parent
return fieldEditorParent;
}
setEnabled does sometimes create a new Label control so it needs to know the correct parent Composite.

Vaadin GridLayout not updating correctly

I have a problem where Vaadin does not update the display of a GridLayout in time. The GridLayout is a component in a VerticalLayout, that I use to list all uploaded files. When I upload a file everything works fine on the server-side but the client does not see the change until he creates a new request to the server (by uploading another file or triggering some other event / rarely the update works fine though).
Here is the component that contains the problematic GridLayout:
public class ListedMultiFileUpload extends VerticalLayout {
private MultiFileUpload multiFileUpload;
private GridLayout fileList;
public ListedMultiFileUpload(UploadFinishedHandler uploadFinishedHandler, UploadStateWindow uploadStateWindow) {
multiFileUpload = new MultiFileUpload(uploadFinishedHandler, uploadStateWindow);
fileList = new GridLayout(2, 5);
fileList.setImmediate(true);
addComponents(multiFileUpload, fileList);
}
public SmartMultiUpload getSmartUpload() {
return multiFileUpload.getSmartUpload();
}
public void addFile(String fileName, final Runnable fileRemover) {
final Label label = new Label(fileName);
final Button button = new Button("X");
button.addClickListener(new ClickListener() {
#Override
public void buttonClick(ClickEvent event) {
fileList.removeComponent(label);
fileList.removeComponent(button);
fileRemover.run();
}
});
fileList.addComponent(label);
fileList.addComponent(button);
markAsDirtyRecursive();
}
}
I already tried setting the GridLayout to immediate as well as marking the whole component as dirty but nothing seems to make a difference.
So basically am I doing something wrong here? Or if not, is there a "nice" way I could force the client to update its components?
As proposed by #Morfic I enabled the Server-Push addon in automatic mode and now the required updates to the client are made by that addon. Not sure how much I like that solution but it works.

GWT Updating Main Content using EventBus and ActivityMapper - Can GWT help me to do this cleaner?

I would like to know
Am I doing things (the following) too complicated?
Is there a better way to update the main content of an activity that allows me to bookmark the event calendar of a store via URL like #MainPlace:eventCalendar?storeId=<id>?
I'm having this ActivityMapper here
public class AppActivityMapper implements ActivityMapper {
private ClientFactory clientFactory;
private MainActivity mainActivity;
// ..
#Override
public Activity getActivity(Place place) {
if (place instanceof LoginPlace) {
return new LoginActivity((LoginPlace) place, clientFactory);
} else if (place instanceof MainPlace) {
if(this.mainActivity == null) {
this.mainActivity = new MainActivity((MainPlace) place, clientFactory);
} else {
this.mainActivity.updateMainContent(((MainPlace) place).getMainContentToken());
}
return this.mainActivity;
}
return null;
}
}
and a MainActivity that controls my MainView that is just a menu ond the left side and the main content on the right side.
I want to decouple my views like in Best Practices for Architecting GWT App which is why I'm trying to control the main content by using events that get fired as something gets clicked in my MenuView.
Therefore I am initializing some event handlers in my MainActivity that react to clicks on the buttons in my menu to delegate the update to the MainView.
public class MainActivity extends AbstractActivity implements MainView.MainPresenter {
#Override
public void start(AcceptsOneWidget panel, EventBus eventBus) {
this.mainView = this.clientFactory.getMainView();
this.mainView.setPresenter(this);
this.mainView.initialize();
this.eventBus = eventBus;
this.eventBus.addHandler(HomeClickedEvent.TYPE, new HomeClickedHandler() {
#Override
public void onHomeClicked(HomeClickedEvent event) {
goTo(new MainPlace("home"));
}
});
this.eventBus.addHandler(EventCalendarClickedEvent.TYPE, new EventCalendarClickedHandler() {
#Override
public void onEventCalendarClicked(EventCalendarClickedEvent eventCalendarClickedEvent) {
goTo(new MainPlace("eventCalendar?storeId=" + eventCalendarClickedEvent.getStoreId()));
}
});
panel.setWidget(this.mainView.asWidget());
}
#Override
public void goTo(Place place) {
this.clientFactory.getPlaceController().goTo(place);
}
#Override
public void updateMainContent(String currentMainContentToken) {
this.mainView.updateMainContent(currentMainContentToken);
}
}
this event gets fired by MenuPresenter.clickedEventCalendar() that reacts to a click on the corresponding menu entry of the MenuView:
public class MenuPresenter implements MenuView.MenuPresenter {
// ..
#Override
public void clickedEventCalendar(Long storeId) {
this.eventBus.fireEvent(new EventCalendarClickedEvent(storeId));
}
}
One of the things I really don't like is this where I append parameters to the token e.g. to display the event calendar of a store given by storeId:
#Override
public void onEventCalendarClicked(EventCalendarClickedEvent eventCalendarClickedEvent) {
goTo(new MainPlace("eventCalendar?storeId=" + eventCalendarClickedEvent.getStoreId()));
}
is there a cleaner solution for a problem like this in GWT? I don't like the fact that I'd have to parse that string in my actual event calendar. Am I using the ActivityMapper wrong or is there simply no other way to do this?
This question should really be split into several separate ones, but that's maybe something to keep in mind for the future. If you're asking one thing then it's easier to answer thoroughly and others can find the answer easier too.
Anyway, I can see a few improvements:
use EventBinder to get rid a bit of the cruft when handling and creating new events.
if you just want to let the presenter know that a button was pressed on in the view (associated with that presenter) sending a custom event over the event bus is a bit of an overkill. Depending on your needs you can expose the button in your view's interface:
public interface Display {
HasClickHandlers getButton();
}
And then just register the ClickHandler in your presenter.
Or, if you need to do something view- and presenter- related on the click, register the ClickHandler in your view and call the presenter:
// In MainView:
#UiHandler("button")
void handleClick(ClickEvent event) {
// Do some stuff with view,
// like hide a panel or change colour
panel.setVisible(false);
// Let the presenter know that a click event has been fired
presenter.onEventCalendarClicked();
}
you're right - creating MainPlace like you are proposing is wrong. You are creating the token too soon - that's what the tokenizer associated with the place is for. You should create MainPlace by passing just the storeId to the constructor - why should MainPresenter (or any other class using this place) should know how to create the token? MainPlace should look more like this:
public class MainPlace extends Place {
private final Long storeId;
public MainPlace(Long storeId) {
this.storeId = storeId;
}
public Long getStoreId() {
return storeId;
}
public static class Tokenizer implements PlaceTokenizer<MainPlace> {
#Override
public MainPlace getPlace(String token) {
return new MainPlace(Long.valueOf(token));
}
#Override
public String getToken(MainPlace place) {
return "eventCalendar?storeId=" + place.getStoreId();
}
}
}
Now, it's the Tokenizer's responisibily to create and parse the token. Just remember to register it on your PlaceHistoryMapper.

How to disable a tab in a GXT 3 tabpanel

I have a GXT 3 TabPanel and would like to disable one or more tabs in response to an event.
There does not seem to be a way to do this.
PlainTabPanel panel = new PlainTabPanel();
TabItemConfig config = new TabItemConfig("Disabled");
Label disabled = new Label("This tab should be disabled");
config.setEnabled(false); // here what you need
panel.add(disabled, config);
I figured this out a while back and forgot to post the answer. Here's a way to do this that works reliably :
public class SimpleTabPanel extends com.sencha.gxt.widget.core.client.PlainTabPanel
implements TabPanel {
Tab currentActiveTab;
private Map<SimpleTab,TabItemConfig> tabConfigs = new HashMap<SimpleTab,TabItemConfig>();
// a map sorted by priority used to keep the expected tab order
SortedMap<TabData, SimpleTab> tabsConfig = new TreeMap<TabData, SimpleTab>(
new Comparator<TabData>() {
#Override
public int compare(TabData o1, TabData o2) {
return Float.compare(o1.getPriority(), o2.getPriority());
}
});
#Override
public Tab addTab(TabData tabData, String historyToken) {
SimpleTab newTab = createNewTab(tabData);
tabsConfig.put(tabData, newTab);
newTab.setTargetHistoryToken(historyToken);
return newTab;
}
private void disableTab(SimpleTab tab, TabData key){
// get and save tab's config.
TabItemConfig tic = getConfig(tab);
tabConfigs.put(tab, tic);
// put new one on tab to disable it.
tic = new TabItemConfig(key.getLabel());
tic.setEnabled(false);
update(tab, tic);
}
public void enableAllTabs(){
for(TabData key : tabsConfig.keySet()){
SimpleTab tab = tabsConfig.get(key);
TabItemConfig tic = tabConfigs.get(tab);
if(tic!=null){
tic.setEnabled(true);
update(tab, tic);
}
}
}
}
I had the same issue happening in my project.
The way I solved it is really simple and I hope that it answers your need.
public void enableTab(IsWidget item, Boolean enable) {
TabItemConfig config = tabPanel.getConfig(item.asWidget());
config.setEnabled(enable);
tabPanel.update(item.asWidget(), config);
}
I call that method every time I need to change a tab state.

Categories