How to resize a widget after it is selected from the widget menu - android-widget

I am creating a widget and I want to be able to have the user select the size of the widget in a menu during the configuration activity. My problem is that in the appwidget-provider meta data xml, the block size is already set before the configuration activity is already entered. I need to be able to reset the info of the widget, which contains the block size (minHeight, minWidth), without having to add separate widgets of different sizes. Any ideas?

You cannot do this. It is an Android limitation. Create several widgets with different sizes, name them like "YourWidget (small)", "YourWidget (large)", etc. Or "YourWidget 1x1" and "YourWidget 2x1". You'll need several nearly identical appwidget-provider xml...
Since you'll need also nearly identical provider and configuration classes, define a base classes with all needed code there, and then inherit from them, something like this:
public class WidgetProvider2x1 extends WidgetProvider {
#Override
int getWidgetStyle() {
return WidgetProvider.WIDGET_STYLE_2x1;
}}
call getWidgetStyle() in the base class when you need to know the size of your widget.

Related

Inspect widget font, margin, padding and other properties

Using flutter inspector I'm not able to find a list of widget's properties like font size, font family, border color, padding, margin ...
For example, in a Text widget the available properties are textDirection, textAlign, size, and a few more, like in screenshot below:
I would like to see all computed properties, like browsers do:
Of course they are different tools, but i would like to know if there is a way to check more properties.
I also found a code-based solution, to access widget properties after it has been rendered, like in this question:
How to get the TextFormField text color,fontsize, etc using controller in flutter?
Is that the best way to achieve the result? Is it possible to use Keys in a way which allows to access widget properties without using a custom widget (i would like to save the reference to a Text, Row, etc. widgets and print all their properties)?
I also tried to use toDiagnosticsNode and toStringDeep methods as follows (_textWidget is of course a Text widget created above, this code is called when i click a button):
var test = _textWidget.toDiagnosticsNode().getProperties();
if (test != null && test.isNotEmpty) {
test.forEach((element) {
print(element.toStringDeep());
});
}
Is it possible to play a bit with a recursive function to get all the properties? All i can see with that code is the text displayed.

How to change the content of a gwt panel?

Assume I have a view named A and its xml is something like:
<g:HTMLPanel>
<my:widgetA>
....
</my:widgetA>
</g:HTMLPanel>
Also, I have another widget named widgetB. I'd like to change the content of view A based on some condition, like:
if (...is true) {
A.clear();
A.add(widgetA);
} else {
A.clear();
A.add(widgetB);
}
Now the problem is view A cannot display widgetA correctly. View A becomes blank when adding widgetA into it. What's the problem with the implementation above?
You might be adding a widget, that implements RequiresResize or at least needs to be given a fixed size.
To find out if that is the case, just call [setSize](http://www.gwtproject.org/javadoc/latest/com/google/gwt/user/client/ui/UIObject.html#setSize(java.lang.String, java.lang.String)) on that widget with a fixed size like that: widgetA.setSize('50px','50px);'
If that works, you either need to provide a size or use a panel, which implements ProvidesResize.

View size not match with layoutPanel container in GWT MVP and SmartGWT

I'm new in GWT, and have problem with view implementation... I use MVP, and SmartGWT. I'll expose this by defining how I settle my MVP and what its weird.
In my onModule, I define class builded with UIbinder. I've declared a LayoutPanel and set it like this in the constructor of the class.
layoutPanel = binder.createAndBindUi(this);
I have container in this class:
public void setBodyLayout() {
panel.setWidgetLeftWidth(menuPanel, xx, PCT, xxx, PCT);
panel.setWidgetRightWidth(bodyPanel, xx, PCT, xx, PCT);
}
menuPanel and bodyPanel are both simplePanel declared in the class above(UIfield use with UIbinder). There are in LayoutPanel. For the method display of my ActivityMapper I've got this method (In reality I have two ActivityMappers, two method that like below and two containers, for menu and body)
public AcceptsOneWidget getBodyContainer() {
return new AcceptsOneWidget() {
#Override
public void setWidget(IsWidget w) {
Widget widget = Widget.asWidgetOrNull(w);
bodyPanel.setWidget(widget);
}
};}
return in my onModule, I declared my ActivityMapper like this
BodyActivityMapper bodyContainerActivityMapper = new BodyActivityMapper(clientFactory);
ActivityManager bodyContainerActivityManager = new ActivityManager(bodyContainerActivityMapper, eventBus);
bodyContainerActivityManager.setDisplay(my_class_described_above.getBodyContainer());
the same work was done with MenuActivityMapper...
Finally
RootLayoutPanel.get().add(my_class_described_above.getLayoutPanel());
when getLayoutPanel() return my layoutPanel declared in the class that I have declared above.
So, each region have its own ActivityMapper.ActivityMapper for the menu have only one activity, and "ActivityMapperBody" have sevral activities triggered by menu.
Utility of container are to settle my layout for different "action". I defined zone with it, in order to receive view started with activity.
But this configuration work only with view builded with UIbinder... In each view, I declare a Layout and return it like this
public Widget asWidget() {
return my_layout_declared;
}
When I return my layout, nothing works. I really don't understand why, and I figure that its worse with smartgwt. All I want its just retrieve my layout and put it in my container... Work with smartgwt can save a lot of time...
I've more detailed my issue to make sure that anyone understand. And ask to you Chris Lercher if your post can help me.
Thank for reading
The Smart GWT FAQ mentions a solution:
If you absolutely must place a Smart GWT interface inside a GWT container and you want it to
fill the container, the best approach is to listen for a window-level resize event and run
your own layout calculations that ultimately call resizeTo() on your topmost Smart GWT
widget.
However, it is wrong by saying that
...GWT containers [do not] fire events when they are resized
Layout panels (the "new" panels since GWT 2.0, which was released on Dec 08, 2009) actually do (see the ProvidesResize and RequiresResize interfaces). So if you have such a panel as your MVP body container (and if its parents are also LayoutPanels up to a top RootLayoutPanel), then you can also override the body container's onResize() method instead of listening to the Window resize event.
So how can you solve your concrete problem?
You need to call resizeTo(width, height) on your topmost Smart GWT layout
When you put in a (new) Smart GWT layout, e.g. maybe you put in a new one when the Place changes.
When the window resizes, or when other things happen that change the size of the container (alternatively, if you're using Layout Panels, you can use its onResize())
For the resizeTo(width, height) call, you'll have to determine the width and height by asking the surrounding container, e.g. by using
container.getElement().getClientWidth()

GWT Widget not properly set in the DOM

I would like to print a GWT widget which extends Composite. This widget is composed of a grid whose cells are built with a ListDataProvider. When the user clic on a button print, the widget to print is built. Once this is done, I launch the print:
Element element = widgetToPrint.getElement();
String content = element.getInnerHTML();
print(content);
public static native boolean print(String content)
/*-{
var mywindow = window.open('', 'Printing', '');
mywindow.document.write('<html><head><title>Test</title>');
mywindow.document.write('<link rel="stylesheet" href="/public/stylesheets/ToPrintWidget.css" type="text/css" media="all"/></head><body>');
mywindow.document.write(content);
mywindow.document.write('</body></html>');
mywindow.print();
return true;
}-*/;
So, here is my problem:
The window which is opened by this method contains the core of the widget (built by the UI Binder), but some children are missing...
If I look inside the ListDataProvider and its related FlowPanel, the data are consistent, i.e. I've got several item in my list and in the flowPanel.
Consequently, it should be visible on the printing window...
I thought that maybe the problem was related to the method used to print the widget, so I also tried to add this widget into a dialogbox just before launching the print, to see if the widget was properly built... and it was.
So my widget displays well on a dialogbox, but if I try to give its innerHTML to the print method, by using getElement(), some widgets are missing... I've the feeling that the widgets which should have been built when the ListDataProvider changes are not properly set in the DOM... Somehow it works when I add the widget to a regular component, but it doesn't work when I have to give directly its innerHTML...
Do you have any idea ?
Thanks in advance.
Widgets are not just the sum of their elements, and DOM elements are not just the string that they are serialized to. Widgets are the element, and all events sunk to the dom to listen for any changes or interactions by the user. Elements then have callback functions or handlers they invoke when the user interacts with them.
By serializing the element (i.e. invoking getInnerHTML()), you are only reading out the structure of the dom, not the callbacks, and additionally not the styles set by CSS. This probably shouldn't be expected to work correctly, and as your experience is demonstrating, it doesn't.
As this is just a print window you are trying to create, event handling is probably not a concern. You just want the ability to see, but not interact with, the content that would be in that set of widgets. Styles are probably the main problem here then (though your question doesn't specify 'some children are missing' doesn't tell us what is missing, or give us any more clues as to why...) - you are adding one stylesheet in your JSNI code, but CellTable (which I assume you are using since you reference ListDataProvider) needs additional CssResource instances to appear correctly. I'm not sure how you can hijack those to draw in a new window.
Are you only using this to print content, not to let the user directly interact with the data? If so, consider another approach - use a SafeHtmlBuilder to create a giant, properly escaped string of content to draw in the new window.
String content = element.toString();
This will include all hierarchy elements in the node.
Just a reminder, all the GWT handlers will not work, and you have to sink all the events using DOM.
You might want to grab the outer HTML rather than the inner one.
GWT unfortunately has no getOuterHTML, but it's relatively easy to emulate.
If your widget is the only child within an element, then simply get the inner HTML of the parent element (w.getElement().getParentElement().getInnerHTML())
Otherwise, clone your widget's node add it to a newly created parent element, from which you'll be able to get the inner HTML:
DivElement temp = Document.get().createDivElement();
temp.appendChild(w.getElement().cloneNode(true));
return temp.getInnerHTML();
First thank you for your answers, it helped me to work out this problem.
I've almost solve the problem:
First, I do not use ListDataProvider anymore, because it wasn't clear for me when and how the view was refreshed. Instead I add my widgets by hand, which makes sense since, they are not going to move anyway.
Then, I define the style of my widgets using a common CSS stylesheet. However, in order to do it, I can't rely on CssResource, which was the way I was used to do it with GWT. I think that this comes from the JS method which gets lost by this kind of styles... Instead, I have to specify everything in a static CSS stylesheet, and to give it to the JS.
It works perfectly well, ie, I have my widgets, with thei styles, and I can print it.
But...
The color of some widgets depends on the color of the object that they represent. Consequently, I cannot write a generic CSS stylesheet... And as I said, I can't add a style using CssResource... Do you have any ideas on the way to handle that ?
To make sure I'm clear on the way I'm adding styles, here is an example:
Label l = new Label("Here is a cell in my grid to be printed");
l.addStyleName("PrintLineCell-kind_1");
With, in a public CSS stylesheet:
.PrintLineCell-kind_1{
background-color: red;
}
I hope there is a better way than to write 300 styles to cover 300 different colors...

GWT Accessing Widget Methods without knowing the name of the Widget

This may have been asked before but I have no idea how to word it to search for it.
I have a composite widget that has methods to update some of the widgets that make up the composite widget. When I add this composite widget to my panel I use a do while loop to pull data from an XML file and populate the composite data. When I instantiate the object each time to add the data it has a scope local to the do-while loop and I cannot call methods to update the data in the composite widget later on. Is there maybe a way to make an array of these composite widgets or another solution to be able to access the Widget?
Eric
Sure... use
List<Composite> widgetList = new ArrayList<Composite>();
// loop
widgetList.add(widget);
// end loop
widgetList.get(3).toString();
You'll want to use your custom class instead of Composite in the list generic... there's nothing stopping you from making data structures using widgets, just like you would with any other Java class.
If you are putting all your Widgets in that loop into one panel (presumably on of the subclasses of ComplexPanel, since you are adding many Widgets to one panel), then you could use one of the methods to access Widgets contained within a panel (assuming you add only those XML generated Widgets to the panel and nothing more):
com.google.gwt.user.client.ui.ComplexPanel.iterator() - returns an java.util.Iterator<Widget> you can use to traverse the list of Widgets within that Panel
com.google.gwt.user.client.ui.ComplexPanel.getWidgetCount() and getWidget(int index) can be used in a for loop to go through all the Widgets within a panel
So, let's look at an example:
VerticalPanel vPanel = new VerticalPanel();
// Fill up the vPanel using XML
Iterator<Widget> iterator = vPanel.iterator();
while(iterator.hasNext()) {
Widget w = iterator.next();
// Do something with w
}
// Or...
for (int i = 0; i < vPanel.getWidgetCount(); i++) {
Widget w = vPanel.getWidget(i);
// Do something with w
}
Of course, substitute VerticalPanel with the one you are you using :)
I definately recommend that you watch "Best Practices for Architecting GWT App" (from Google I/O 2009):
http://www.youtube.com/watch?v=PDuhR18-EdM
At about 24 minutes through it talks about how to write composite widgets using the MVP design pattern - although you should watch it all. Unfortunately it does not provide ready to use code snipets, but it does show you how to construct a framework to decouple your XML and UI objects nicely.