Grid SelectionMode.MULTI is missing the header checkbox to select all for BackEndDataProvider - vaadin-grid

I am working with a new application written to version 8 (currently testing with 8.1.0.rc2).
The issue surrounds the "select all" checkbox that appears in the header of a Grid when using SelectionMode.MULTI. In particular, the problem is that the checkbox appears and operates as expected when the DataProvider implements InMemoryDataProvider, but the checkbox does not appear when the DataProvider implements BackEndDataProvider.
The following code creates two grids that differ only in whether they use InMemory or BackEnd:
public class Test {
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
private String name;
}
public class TestView extends BaseView {
public TestView() {
super("Test");
addComponent(new TestGrid(new TestDataProvider0()));
addComponent(new TestGrid(new TestDataProvider1()));
}
}
public class TestGrid extends Grid<Test> {
public TestGrid(DataProvider<Test, ?> dataProvider) {
setHeightByRows(4);
setSelectionMode(SelectionMode.MULTI);
setDataProvider(dataProvider);
addColumn(Test::getName).setCaption("Name");
}
}
public class TestDataProvider0 extends AbstractDataProvider<Test, SerializablePredicate<Test>> implements
BackEndDataProvider<Test, SerializablePredicate<Test>> {
public Stream<Test> fetch(Query<Test, SerializablePredicate<Test>> query) {
List<Test> tests = new ArrayList<>(query.getLimit());
for (int i = 0; i < query.getLimit(); i++) {
Test test = new Test();
test.setName(String.valueOf(query.getOffset() + i));
tests.add(test);
}
return tests.stream();
}
public int size(Query<Test, SerializablePredicate<Test>> query) {
return 100;
}
public void setSortOrders(List<QuerySortOrder> sortOrders) {
}
}
public class TestDataProvider1 extends AbstractDataProvider<Test, SerializablePredicate<Test>> implements
InMemoryDataProvider<Test> {
public Stream<Test> fetch(Query<Test, SerializablePredicate<Test>> query) {
List<Test> tests = new ArrayList<>(query.getLimit());
for (int i = 0; i < query.getLimit(); i++) {
Test test = new Test();
test.setName(String.valueOf(query.getOffset() + i));
tests.add(test);
}
return tests.stream();
}
public int size(Query<Test, SerializablePredicate<Test>> query) {
return 100;
}
public SerializablePredicate<Test> getFilter() {
return null;
}
public void setFilter(SerializablePredicate<Test> filter) {
}
public SerializableComparator<Test> getSortComparator() {
return null;
}
public void setSortComparator(SerializableComparator<Test> comparator) {
}
}
Here is how the grids are rendered:
Have I missed a critical step in setting up my BackEnd-based data provider/grid? The related documentation does not seem to address this issue.
Is there a known issue related to this?
Is select-all not available by design? Obviously, this could interact really badly with the concept of lazy-loading on a large data set...

MultiSelectionModelImpl has this method:
protected void updateCanSelectAll() {
switch (selectAllCheckBoxVisibility) {
case VISIBLE:
getState(false).selectAllCheckBoxVisible = true;
break;
case HIDDEN:
getState(false).selectAllCheckBoxVisible = false;
break;
case DEFAULT:
getState(false).selectAllCheckBoxVisible = getGrid()
.getDataProvider().isInMemory();
break;
default:
break;
}
}
This indicates that the default behavior for non-in-memory providers is to not show the select-all checkbox, but that this behavior can be overridden by setting the visibility to VISIBLE.
Tweaking the original code here:
public class TestGrid extends Grid<Test> {
public TestGrid(DataProvider<Test, ?> dataProvider) {
setHeightByRows(4);
MultiSelectionModel<Test> selectionModel = (MultiSelectionModel<Test>) setSelectionMode(SelectionMode.MULTI);
selectionModel.setSelectAllCheckBoxVisibility(SelectAllCheckBoxVisibility.VISIBLE);
setDataProvider(dataProvider);
addColumn(Test::getName).setCaption("Name");
}
}
Specifically, this call is required for the checkbox to appear for data providers that implement BackEndDataProvider:
MultiSelectionModel<Test> selectionModel = (MultiSelectionModel<Test>) setSelectionMode(SelectionMode.MULTI);
selectionModel.setSelectAllCheckBoxVisibility(SelectAllCheckBoxVisibility.VISIBLE);
With this change, the select-all checkbox now appears:

Related

Issue getting fault message from message context in Masstransit

I have an application that needs to intercept the current message consume context and extract a value that is defined in a base interface. That value is a tenant code that is eventually used in an EF database context.
I have a provider that takes a MassTransit ConsumerContext, and then using context.TryGetMessage(), extracts the tenant code, which is ultimately used to switch database contexts to a specific tenant database.
The issue lies in the MessageContextTenantProvider below. If a non-fault message is consumed then ConsumeContext<IBaseEvent> works fine. However if it is a fault, ConsumeContext<Fault<IBaseEvent>> doesn't work as expected.
Durring debugging I can see that the message context for a fault is ConsumeContext<Fault<IVerifyEvent>>, but why doesn't it work with a base interface as per the standard message? Of course, ConsumeContext<Fault<IVerifiedEvent>> works fine, but I have a lot of message types, and I don't want to have to define them all in that tenant provider.
Any ideas?
public interface ITenantProvider
{
string GetTenantCode();
}
public class MessageContextTenantProvider : ITenantProvider
{
private readonly ConsumeContext _consumeContext;
public MessageContextTenantProvider(ConsumeContext consumeContext)
{
_consumeContext = consumeContext;
}
public string GetTenantCode()
{
// get tenant from message context
if (_consumeContext.TryGetMessage(out ConsumeContext<IBaseEvent> baseEvent))
{
return baseEvent.Message.TenantCode; // <-- works for the non fault consumers
}
// get tenant from fault message context
if (_consumeContext.TryGetMessage<Fault<IBaseEvent>>(out var gebericFaultEvent))
{
return gebericFaultEvent.Message.Message.TenantCode; // <- doesn't work generically
}
// get tenant from fault message context (same as above)
if (_consumeContext.TryGetMessage(out ConsumeContext<Fault<IBaseEvent>> faultEvent))
{
return faultEvent.Message.Message.TenantCode; // <= generically doesn't work when using the base interface?
}
// get tenant from specific concrete fault class
if (_consumeContext.TryGetMessage(out ConsumeContext<Fault<IVerifiedEvent>> verifiedFaultEvent))
{
return verifiedFaultEvent.Message.Message.TenantCode; // <-- this works
}
// not able to extract tenant
return null;
}
}
public partial class VerificationDbContext
{
string connectionString;
public string ConnectionString
{
get
{
if (connectionString == null)
{
string tenantCode = _tenantProvider.GetTenantCode();
connectionString = _tenantConnectionManager.GetConnectionString(orgId);
}
return connectionString;
}
}
private readonly ITenantProvider _tenantProvider;
private readonly ITenantConnectionManager _tenantConnectionManager;
public VerificationDbContext(ITenantProvider tenantProvider, ITenantConnectionManager tenantConnectionManager)
{
_tenantProvider = tenantProvider;
_tenantConnectionManager = tenantConnectionManager;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (string.IsNullOrEmpty(this.ConnectionString))
{
optionsBuilder.UseSqlServer(#"Data Source=.\SQLEXPRESS;Initial Catalog=VerificationDb;Integrated Security=True")
.ConfigureWarnings((warningBuilder) => warningBuilder.Ignore(RelationalEventId.AmbientTransactionWarning));
}
else
{
optionsBuilder.UseSqlServer(this.ConnectionString)
.ConfigureWarnings((warningBuilder) => warningBuilder.Ignore(RelationalEventId.AmbientTransactionWarning));
}
}
}
public interface ITenantConnectionManager
{
string GetConnectionString(string tenantCode);
}
public class TenantConnectionManager : ITenantConnectionManager
{
private ITenantRepository _tenantRepository;
public TenantConnectionManager(ITenantRepository tenantRepository)
{
_tenantRepository = tenantRepository;
}
public string GetConnectionString(string tenantCode)
{
return _tenantRepository.GetByTenantCode(tenantCode).ConnectionString;
}
}
public interface IBaseEvent
{
string TenantCode { get; }
}
public interface IVerifiedEvent : IBaseEvent
{
string JobReference { get; }
}
public class VerifiedEventConsumer : IConsumer<IVerifiedEvent>
{
private readonly IVerifyCommand _verifyCommand;
private readonly ITenantProvider _tenantProvider;
public VerifiedEventConsumer(ITenantProvider tenantProvider, IVerifyCommand verifyCommand)
{
_verifyCommand = verifyCommand;
_tenantProvider = tenantProvider;
}
public async Task Consume(ConsumeContext<IVerifiedEvent> context)
{
await _verifyCommand.Execute(new VerifyRequest
{
JobReference = context.Message.JobReference,
TenantCode = context.Message.TenantCode
});
}
}
public class VerifiedEventFaultConsumer : IConsumer<Fault<IVerifiedEvent>>
{
private readonly IVerifyFaultCommand _verifyFaultCommand;
private readonly ITenantProvider _tenantProvider;
public CaseVerifiedEventFaultConsumer(ITenantProvider tenantProvider, IVerifyFaultCommand verifyFaultCommand)
{
_verifyFaultCommand = verifyFaultCommand;
_tenantProvider = tenantProvider;
}
public async Task Consume(ConsumeContext<Fault<ICaseVerifiedEvent>> context)
{
await _verifyFaultCommand.Execute(new VerifiedFaultRequest
{
JobReference = context.Message.Message.JobReference,
Exceptions = context.Message.Exceptions
});
}
}
I've solved the issue by using the GreenPipes TryGetPayload extension method:
public class MessageContextTenantProvider : ITenantProvider
{
private readonly ConsumeContext _consumeContext;
public MessageContextTenantProvider(ConsumeContext consumeContext)
{
_consumeContext = consumeContext;
}
public string GetTenantCode()
{
// get tenant from message context
if (_consumeContext.TryGetMessage(out ConsumeContext<IBaseEvent> baseEvent))
{
return baseEvent.Message.TenantCode;
}
// get account code from fault message context using Greenpipes
if (_consumeContext.TryGetPayload(out ConsumeContext<Fault<IBaseEvent>> payloadFaultEvent))
{
return payloadFaultEvent.Message.Message.TenantCode;
}
// not able to extract tenant
return null;
}
}

LayoutManager for Recyclerview with different cell spancount

I am working to achieve a recycler view interface that looks like this:
Presently, am only using a recyclerview with LinearLayoutManager using an adapter with two viewholders, i tried gridLayout manager too but i did not achieve the target interface: I need help achieving this, Do i have to create a custom Layout Manager? or What exactly do i have to do? Please, I am really stuck on this.
This is my adapter code
public class SimpleStringRecyclerViewAdapter : RecyclerView.Adapter
{
private List<Data> mValues;
private Context context;
private const int TYPE_FULL = 0;
private const int TYPE_HALF = 1;
private const int TYPE_QUARTER = 2;
public SimpleStringRecyclerViewAdapter(Context context, List<Data> items)
{
this.context = context;
mValues = items;
}
public override int ItemCount
{
get
{
return mValues.Count();
}
}
public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
if (holder is SimpleViewHolder)
try
{
Data item = mValues.ElementAt(position);
var simpleHolder = holder as SimpleViewHolder;
simpleHolder.mTxtView.Text = Android.Text.Html.FromHtml(item.article.Title).ToString();
simpleHolder.mTxtView2.Text = item.article.Description;
using (var imageView = simpleHolder.mImageView)
{
string url = Android.Text.Html.FromHtml(item.article.UrlToImage).ToString();
//Download and display image
UrlImageViewHelper.SetUrlDrawable(imageView,
url, Resource.Drawable.cheese_1
);
}
// simpleHolder.mprogressbar.Visibility = ViewStates.Gone;
}
catch (Exception e)
{
//Toast.MakeText(this.context, e.ToString(), ToastLength.Long).Show();
}
else
{
try
{
Data item = mValues.ElementAt(position);
var simpleHolder = holder as SimpleViewHolder2;
simpleHolder.mTxtView.Text = Android.Text.Html.FromHtml(item.youTubeItem.Title).ToString();
// simpleHolder.mTxtView2.Text = item.DescriptionShort;
using (var imageView = simpleHolder.mImageView)
{
string url = Android.Text.Html.FromHtml(item.youTubeItem.MaxResThumbnailUrl).ToString();
//Download and display image
UrlImageViewHelper.SetUrlDrawable(imageView,
url, Resource.Drawable.cheese_1
);
}
}
catch (Exception e)
{
//Toast.MakeText(this.context, e.ToString(), ToastLength.Long).Show();
}
}
}
public override int GetItemViewType(int position)
{
if (mValues.ElementAt(position).type == 1)
{
return Resource.Layout.ItemsList;
}
else
{
return Resource.Layout.VideoList;
}
}
public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
{
if (viewType == Resource.Layout.ItemsList)
{
View view = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.ItemsList, parent, false);
view.SetBackgroundColor(Color.White);
SimpleViewHolder holder = new SimpleViewHolder(view);
// holder.mprogressbar = view.FindViewById<ProgressBar>(Resource.Id.progressBar);
// holder.mprogressbar.Visibility = ViewStates.Visible;
//Showing loading progressbar
return holder;
}
else
{
View view = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.VideoList, parent, false);
view.SetBackgroundColor(Color.White);
SimpleViewHolder2 holder = new SimpleViewHolder2(view);
return holder;
}
}
}
public class SimpleViewHolder : RecyclerView.ViewHolder
{
public string mBoundString;
public readonly View mView;
public readonly ImageView mImageView;
public readonly TextView mTxtView;
public readonly TextView mTxtView2;
// public ProgressBar mprogressbar;
public SimpleViewHolder(View view) : base(view)
{
mView = view;
mImageView = view.FindViewById<ImageView>(Resource.Id.avatar2);
mTxtView = view.FindViewById<TextView>(Resource.Id.Text11);
mTxtView2 = view.FindViewById<TextView>(Resource.Id.Text12);
// mprogressbar = view.FindViewById<ProgressBar>(Resource.Id.progressBar);
}
public override string ToString()
{
return base.ToString() + " '" + mTxtView.Text;
}
}
public class SimpleViewHolder2 : RecyclerView.ViewHolder
{
public string mBoundString;
public readonly View mView;
public readonly ImageView mImageView;
public readonly TextView mTxtView;
public readonly TextView mTxtView2;
public SimpleViewHolder2(View view) : base(view)
{
mView = view;
mImageView = view.FindViewById<ImageView>(Resource.Id.videoavatar);
mTxtView = view.FindViewById<TextView>(Resource.Id.videoText1);
// mprogressbar = view.FindViewById<ProgressBar>(Resource.Id.progressBar);
}
}
SetUpRecyclerView Method:
dataUse = OfflineDeserializer.OfflineData(content, json2);
recyclerView.SetLayoutManager(new LinearLayoutManager(recyclerView.Context));
recyclerView.SetAdapter(new SimpleStringRecyclerViewAdapter(recyclerView.Context, dataUse));
if (vp.IsShown)
{
vp.Visibility = ViewStates.Invisible;
}
This is what I have presently:
you can use recycler view with multiple view type
here is the link you can refer
Recyclerview with multiple view types
Here is a sample code you can modify it according to your need
public class MyFeedsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
final int
VIDEO = 1,
IMAGE = 2,
AUDIO = 3;
public MyFeedsAdapter(HomeActivity homeActivity, ArrayList<MyFeedsModel> list, MyFeedsFragment myFeedsFragment) {
this.activity = homeActivity;
this.list = list;
this.myFeedsFragment = myFeedsFragment;
metrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view;
switch (viewType) {
case VIDEO:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_myfeeds, parent, false);
return new ViewForVideo(view);
case IMAGE:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_myfeeds, parent, false);
return new ViewForImage(view);
case AUDIO:
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_myfeeds, parent, false);
return new ViewForAudio(view);
default:
return null;
}
}
#Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
if (list.get(position).getFile_type().equals(IntentString.VIDEO)) {
setViewForVideo((ViewForVideo) holder, position);
} else if (list.get(position).getFile_type().equals(IntentString.IMAGE)) {
setViewForImage((ViewForImage) holder, position);
} else if (list.get(position).getFile_type().equals(IntentString.AUDIO)) {
setViewForAudio((ViewForAudio) holder, position);
}
}
#Override
public int getItemCount() {
return list.size();
}
#Override
public int getItemViewType(int position) {
if (list.get(position).getFile_type().equals(IntentString.VIDEO)) {
return VIDEO;
} else if (list.get(position).getFile_type().equals(IntentString.IMAGE)) {
return IMAGE;
} else if (list.get(position).getFile_type().equals(IntentString.AUDIO)) {
return AUDIO;
} else {
return 0;
}
}
public void setViewForVideo(final ViewForVideo holder, final int position) {
}
public void setViewForImage(final ViewForImage holder, final int position) {
}
public void setViewForAudio(final ViewForAudio holder, int position) {
}
public class ViewForVideo extends RecyclerView.ViewHolder {
public ViewForVideo(View itemView) {
super(itemView);
}
}
public class ViewForImage extends RecyclerView.ViewHolder {
public ViewForImage(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
public class ViewForAudio extends RecyclerView.ViewHolder {
public ViewForAudio(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}
}
}

Recycler View with Header and Edit Text

I have a recyclerview with a header achieved by using two different element types. In my header there is an edit text which I want to use for filtering the nonheader elements of the list. Below is my current implementation, I have one concern and one problem with it.
My concern is that what I am doing in publishResults with the notifyItemRangeRemoved and notifyItemInserted is the wrong way to update the recycler view. I originally was doing notifyDatasetChanged but his would cause the header row to be refreshed too and the edit text to lose focus. What I really want is a way to refresh only the item rows and leave the header row untouched.
My current problem is that with the existing code if I scroll down too much the edit text looses focus. I want the edit text to keep focus even if I scroll to the bottom of the list.
The code used to use a ListView with setHeaderView and that worked somehow so there must be someway of achieving the goal just not sure what the trick with a recycler view is. Any help is much appreciated.
public class SideListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements Filterable {
private static final int TYPE_HEADER = 0;
private static final int TYPE_ITEM = 1;
private final List<String> data;
public List<String> filteredData;
private HeaderActionListener headerActionListener;
public SideListAdapter(Context context, ArrayList<String> data, HeaderActionListener headerActionListener) {
this.data = data;
filteredData = new ArrayList<>(data);
this.context = context;
this.headerActionListener = headerActionListener;
}
#Override
public Filter getFilter() {
return new TestFilter();
}
static class SideListItem extends RecyclerView.ViewHolder {
LinearLayout baseLayout;
public SideListItem(View itemView) {
super(itemView);
baseLayout = (LinearLayout) itemView.findViewById(R.id.settings_defaultcolor);
}
}
class SideListHeader extends SideListHeader {
EditText sort;
public SideListHeaderLoggedIn(View itemView) {
super(itemView);
sort = (EditText) itemView.findViewById(R.id.sort);
}
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (viewType == TYPE_ITEM) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item, parent, false);
return new SideListItem(v);
} else if (viewType == SideListHeader) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.header, parent, false);
return new SideListHeader(v);
}
throw new RuntimeException("there is no type that matches the type " + viewType + " + make sure your using types correctly");
}
public interface HeaderActionListener {
boolean onSortEditorAction(TextView arg0, int arg1, KeyEvent arg2);
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
if (holder instanceof SideListHeader) {
final SideListHeader sideListHeader = (SideListHeader) holder;
sideListHeader.sort.setOnEditorActionListener(new TextView.OnEditorActionListener() {
#Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
}
});
sideListHeader.sort.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {
}
#Override
public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
}
#Override
public void afterTextChanged(Editable editable) {
String result = sideListHeader.sort.getText().toString().replaceAll(" ", "");
getFilter().filter(result);
}
});
}
if (holder instanceof SideListItem) {
// Inflate normal item //
}
}
// need to override this method
#Override
public int getItemViewType(int position) {
if (isPositionHeader(position)) {
return TYPE_HEADER;
}
return TYPE_ITEM;
}
private boolean isPositionHeader(int position) {
return position == 0;
}
//increasing getItemcount to 1. This will be the row of header.
#Override
public int getItemCount() {
return filteredData.size() + 1;
}
private class TestFilter extends Filter {
#Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
String prefix = constraint.toString().toLowerCase();
if (prefix.isEmpty()) {
ArrayList<String> list = new ArrayList<>(data);
results.values = list;
results.count = list.size();
} else {
final ArrayList<String> list = new ArrayList<>(data);
final ArrayList<String> nlist = new ArrayList<>();
for (int i = 0 ; i < list.size(); i++) {
String item = list.get(i);
if (item.contains(prefix)) {
nlist.add(item);
}
}
results.values = nlist;
results.count = nlist.size();
}
return results;
}
#SuppressWarnings("unchecked")
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
notifyItemRangeRemoved(1, getItemCount()-1);
filteredData.clear();
filteredData.addAll((List<String>)results.values);
for(int i = 1; i < getItemCount() - 1; i++){
notifyItemInserted(i);
}
}
}
}
I'm not sure how correct this way is, but in my code I implemented it like that
private var headerList: List<HeaderItem> = listOf(HeaderItem("Title"))
private fun searchItem(items: List<Items>, query: String) {
items.filterIsInstance<MainItem>().filter { filteredItems ->
filteredItems.header.lowercase().contains(query.lowercase())
}.let { searchedItems ->
rvAdapter.submitList(headerList + searchedItems)
}
}
This way I was able to preserve header element when I did my search

GWT retrieve list from datastore via serviceimpl

Hi I'm trying to retrieve a linkedhashset from the Google datastore but nothing seems to happen. I want to display the results in a Grid using GWT on a page. I have put system.out.println() in all the classes to see where I go wrong but it only shows one and I don't recieve any errors. I use 6 classes 2 in the server package(ContactDAOJdo/ContactServiceImpl) and 4 in the client package(ContactService/ContactServiceAsync/ContactListDelegate/ContactListGui). I hope someone can explain why this isn't worken and point me in the right direction.
public class ContactDAOJdo implements ContactDAO {
#SuppressWarnings("unchecked")
#Override
public LinkedHashSet<Contact> listContacts() {
PersistenceManager pm = PmfSingleton.get().getPersistenceManager();
String query = "select from " + Contact.class.getName();
System.out.print("ContactDAOJdo: ");
return (LinkedHashSet<Contact>) pm.newQuery(query).execute();
}
}
public class ContactServiceImpl extends RemoteServiceServlet implements ContactService{
private static final long serialVersionUID = 1L;
private ContactDAO contactDAO = new ContactDAOJdo() {
#Override
public LinkedHashSet<Contact> listContacts() {
LinkedHashSet<Contact> contacts = contactDAO.listContacts();
System.out.println("service imp "+contacts);
return contacts;
}
}
#RemoteServiceRelativePath("contact")
public interface ContactService extends RemoteService {
LinkedHashSet<Contact> listContacts();
}
public interface ContactServiceAsync {
void listContacts(AsyncCallback<LinkedHashSet <Contact>> callback);
}
public class ListContactDelegate {
private ContactServiceAsync contactService = GWT.create(ContactService.class);
ListContactGUI gui;
void listContacts(){
contactService.listContacts(new AsyncCallback<LinkedHashSet<Contact>> () {
public void onFailure(Throwable caught) {
gui.service_eventListContactenFailed(caught);
System.out.println("delegate "+caught);
}
public void onSuccess(LinkedHashSet<Contact> result) {
gui.service_eventListRetrievedFromService(result);
System.out.println("delegate "+result);
}
});
}
}
public class ListContactGUI {
protected Grid contactlijst;
protected ListContactDelegate listContactService;
private Label status;
public void init() {
status = new Label();
contactlijst = new Grid();
contactlijst.setVisible(false);
status.setText("Contact list is being retrieved");
placeWidgets();
}
public void service_eventListRetrievedFromService(LinkedHashSet<Contact> result){
System.out.println("1 service eventListRetreivedFromService "+result);
status.setText("Retrieved contactlist list");
contactlijst.setVisible(true);
this.contactlijst.clear();
this.contactlijst.resizeRows(1 + result.size());
int row = 1;
this.contactlijst.setWidget(0, 0, new Label ("Voornaam"));
this.contactlijst.setWidget(0, 1, new Label ("Achternaam"));
for(Contact contact: result) {
this.contactlijst.setWidget(row, 0, new Label (contact.getVoornaam()));
this.contactlijst.setWidget(row, 1, new Label (contact.getVoornaam()));
row++;
System.out.println("voornaam: "+contact.getVoornaam());
}
System.out.println("2 service eventListRetreivedFromService "+result);
}
public void placeWidgets() {
System.out.println("placewidget inside listcontactgui" + contactlijst);
RootPanel.get("status").add(status);
RootPanel.get("contactlijst").add(contactlijst);
}
public void service_eventListContactenFailed(Throwable caught) {
status.setText("Unable to retrieve contact list from database.");
}
}
It could be the query returns a lazy list. Which means not all values are in the list at the moment the list is send to the client. I used a trick to just call size() on the list (not sure how I got to that solution, but seems to work):
public LinkedHashSet<Contact> listContacts() {
final PersistenceManager pm = PmfSingleton.get().getPersistenceManager();
try {
final LinkedHashSet<Contact> contacts =
(LinkedHashSet<Contact>) pm.newQuery(Contact.class).execute();
contacts.size(); // this triggers to get all values.
return contacts;
} finally {
pm.close();
}
}
But I'm not sure if this is the best practice...

How do you add a key handler to a GWT FlexTable?

I'm trying to change the row highlighting in my FlexTable using KeyCodes.KEY_UP/DOWN. This doesn't seem to work (based on 1809155):
public class KeyAwareFlexTable extends FlexTable
implements KeyDownHandler, HasKeyDownHandlers {
public KeyAwareFlexTable() {
this.addKeyDownHandler(this);
}
#Override
public void onKeyDown(KeyDownEvent event) {
GWT.log("onKeyDown");
// check if up/down & do something useful
}
#Override
public HandlerRegistration addKeyDownHandler(KeyDownHandler handler) {
return addDomHandler(handler, KeyDownEvent.getType());
}
}
I've also tried this (based on this site):
FlexTable table = new FlexTable() {
#Override
public void onBrowserEvent(Event event) {
super.onBrowserEvent(event);
GWT.log("Event type = " + DOM.eventGetType(event));
switch (DOM.eventGetType(event)) {
case Event.ONKEYDOWN:
if (DOM.eventGetKeyCode(event) == KeyCodes.KEY_UP) {
GWT.log("up");
} else if (DOM.eventGetKeyCode(event) == KeyCodes.KEY_DOWN) {
GWT.log("down");
}
break;
default:
break;
}
}
};
table.sinkEvents(Event.ONKEYDOWN);
I'm looking for a way to have this behavior more or less. Does anybody have a way to do this in GWT?
Got it
FocusPanel focus = new FocusPanel(flexTable);
focus.addKeyDownHandler(new KeyDownHandler() {
#Override
public void onKeyDown(KeyDownEvent event) {
int code = event.getNativeKeyCode();
if (KeyCodes.KEY_UP == code) {
GWT.log("Bed goes up");
} else if (KeyCodes.KEY_DOWN == code) {
GWT.log("Bed goes down");
}
}
});

Resources