Hy,
I want to display a certain part (a div for example) of my wicket-template only under a certain condition (for example only if I have the data to fill it). The problem is:
If I only add the panel (filling the div) if I got the data, an exception is thrown every time I call the page without the data (because the referenced wicket-id is not added to the component-tree).
The only solution which came to my mind was to add a empty panel if there is no data. This is not an ideal solution because I got some unneeded code in the java-code and many empty divs in my rendered html.
So is there a better solution to include several parts of a wicket-template only under a condition?
Although this is an old question here could be one more solution: wicket:enclosure (and this )
Update: Now I needed this functionality by my self (for jetwick). I'm using WebMarkupContainer one for loggedIn state and one for loggedOut state and set the right visibility:
if (loggedIn()) {
WebMarkupContainer loggedInContainer = new WebMarkupContainer("loggedIn");
//## do something with the user
User user = getUserSomeWhere();
loggedInContainer.add(new UserSearchLink("userSearchLink"));
add(loggedInContainer);
add(WebMarkupContainer("loggedOut").setVisible(false));
} else {
add(new WebMarkupContainer("loggedIn").setVisible(false));
WebMarkupContainer loggedOutContainer = WebMarkupContainer("loggedOut");
loggedOutContainer.add(new LoginLink() {...});
add(loggedOutContainer);
}
The advantage of this for me is that I prevent a NullpointerExc in the //## marked line and the enclose feature of wicket would look more ugly to me in this case I think.
Like #miaubiz said, you can call setVisible(false), or you can override the isVisible() method, if the visibility is conditional to some other state (fields filled, for example).
Yup, you want to override isVisible. This will keep the isVisible=false html markup from even rendering to the final html page. Also, according to the docs (mentioned in EmptyPanel), you can use the WebMarkupContainer as the wrapping component.
this.add(new SimpleResourceModelLabel(NO_DATA_LABEL){
private static final long serialVersionUID = 1L;
#Override
public boolean isVisible() { return myList.isEmpty(); }
});
final WebMarkupContainer table = new WebMarkupContainer(MY_DATA_TABLE){
private static final long serialVersionUID = 1L;
#Override
public boolean isVisible() { return !myList.isEmpty(); }
};
I guess this is why there's EmptyPanel. Without knowing about your code more I can only say that what I think you're doing is something I'd do with combination of some child of AbstractRepeater and Fragment. If you're willing to tell more about what you want to do and maybe provide some code too, I'll be happy to help as much as I can.
you can call setVisible(false); on the component you want to hide.
Related
Wicket 6 no longer keeps feedback messages in session. Now they are attached to components, which I think is great move but I approach an issue connected with that. I used to remove all feedback messages that were related to the specific form like this :
Session.get().getFeedbackMessages().clear(new ContainerFeedbackMessageFilter(panelForm));
Unfortunetly right now I can't clear it like this:
panelForm.getFeedbackMessages().clear();
For obvious reasons - they are attached to components inside form.
So is there a way to get those feedback messages by only accesing (in my case) panelForm or my only way to go is to call getFeedbackMessages() on all of my components (panelForm.component1, panelForm.component2 etc)?
use FeedbackCollector as in example:
new FeedbackMessagesModel(this) {
#Override
protected List<FeedbackMessage> collectMessages(Component panel, IFeedbackMessageFilter filter) {
return new FeedbackCollector(YourComponent.this.getParent()) {
#Override
protected boolean shouldRecurseInto(Component component) {
return true; // your citeria here
}
}.setIncludeSession(false).collect(filter);
}
};
Yes. You should use FeedbackCollector. Collect the messages and mark them as rendered.
I am brand new to GWT and am trying to achieve the following:
Here's the code that I've cooked up:
public class MyWebApp implements EntryPoint {
// The main container for everything the user sees (the "view")
private LayoutPanel mainPanel;
// Simple HTML for the header ("MyWebApp") and subsequent <hr/>
private SafeHtml header;
// The three links "Dashboard", "Monitors" and "Help Desk"
private HorizontalPanel navMenu;
// The empty content that gets populated when user clicks one of
// the 3 links.
private Panel menuContent;
#Override
public void onModuleLoad() {
// The initial fragment contains the header, nav menu and empty "content" div.
// Each menu/screen then fills out content div.
initMainPanel();
RootPanel.get().add(mainPanel);
}
private void initMainPanel() {
SafeHtmlBuilder headerBuilder = new SafeHtmlBuilder();
navMenu = new HorizontalPanel();
// Leaving null until user clicks on one of the 3 menus.
// Then the menu will decide what panel gets injected for
// this panel.
menuContent = null;
// Create the simple HTML for the header.
headerBuilder.append("<h1>MyWebApp</h1><hr/>");
// Create the navMenu items.
Hyperlink dashboardLink, monitorsLink, helpDeskLink;
// Homepage is http://www.mywebapp.com
// I want the dashboardLink to inject menuContent and "redirect" user to
// http://www.mywebapp.com/dashboard
dashboardLink = new Hyperlink("???", "???");
// http://www.mywebapp.com/monitors
monitorsLink = new Hyperlink("???", "???");
// http://www.mywebapp.com/help-desk
helpDeskLink = new Hyperlink("???", "???");
navMenu.add(dashboardLink);
navMenu.add(monitorsLink);
navMenu.add(helpDeskLink);
// Add all widgets to the mainPanel.
mainPanel.add(new HTML(headerBuilder.toSafeHtml().toString()));
mainPanel.add(navMenu);
mainPanel.add(menuContent);
// Position and size the widgets (omitted for brevity).
// mainPanel.setWidgetHorizontalPosition(...);
}
private HTML getDashboardMenuContent() {
return new HTML("This is the dashboard.");
}
private HTML getMonitorsMenuContent() {
return new HTML("These are the monitors.");
}
private HTML getHelpDeskMenuContent() {
return new HTML("This is the help desk.");
}
}
Most importantly:
How do I "wire up" the Hyperlinks so that when the user clicks them, I can call the appropriate getXXXMenuContent() method, and then add that to menuContent?
But also:
I feel like I'm doing something wrong here: mainPanel.add(new HTML(headerBuilder.toSafeHtml().toString())); - if so what is it?!? How should I be adding a simple <h1> and <hr/> in a way that's secure (hence the use of the Safe* objects), efficient, and conforming to recommended practices?
Should I be implementing UiBinder here? If so, would I make UiBinders for each menu's content or for the entire mainPanel, or both?
Thanks in advance!
Hyperlink widgets trigger navigation. You don't want to handle clicks on them, you want to handle navigation (that could be triggered by clicking a Hyperlink or using the browser's back/forward buttons, a bookmark or link from elsewhere –including Ctrl+clicking a Hyperlink to open it in a new window/tab–, etc.)
To react to those navigation events, use History.addValueChangeHandler; and to handle the initial navigation on application start, call History.fireCurrentHistoryState() (after you add your handler of course).
More details in: https://developers.google.com/web-toolkit/doc/latest/DevGuideCodingBasicsHistory
Would be better to split other questions to... other questions, but here are the answers anyway:
I feel like I'm doing something wrong here: mainPanel.add(new HTML(headerBuilder.toSafeHtml().toString())); - if so what is it?!? How should I be adding a simple <h1> and <hr/> in a way that's secure (hence the use of the Safe* objects), efficient, and conforming to recommended practices?
The HTML widget has a constructor taking a SafeHtml so you don't need to call toString().
If you're only using a constant, you don't need a SafeHtmlBuilder; use SafeHtmlUtils instead. But constants are no more or less secure with or without SafeHtml, SafeHtml just makes it easier to find all occurrences of HTML in your code, to help in doing a security review of your app (BTW, we're doing HTML, so <hr>, not <hr/>; if you really want it to look like XML/XHTML, then use <hr /> but you're only cheating yourself here)
Should I be implementing UiBinder here? If so, would I make UiBinders for each menu's content or for the entire mainPanel, or both?
If you don't feel the need for UiBinder, you don't have to use it. But in this case it won't change anything: you're not handling widget events, but history events.
Something like
dashboardLink.addClickHandler(
new ClickHandler()
{
public void onClick( ClickEvent event )
{
mainPanel.setWidget( getDashboardMenuContent() );
}
} );
You should note that Hyperlink.addClickHandler(...) is deprecated and it is recommended to use Anchor.addClickHandler(...) instead.
As for the other questions: It is a lot more elegant and easier to build UI's with UIBinder, so definitely look into that, but do try to make "it" work first to avoid the added complexity of the .ui.xml setup :-)
Cheers,
I have one simple piece of advice to give you. Use what the framework has to offer.
The HTML widget should be your last escape. There are so many widgets that there is no need for you to write html almost anywhere in your code.
So instead of headerBuilder, you can user the following piece of code
Label header = new Label("MyWebApp");
header.setStyleName("headerStyle",true);
You can set the style properties in an external Css file and add the reference inside the base html file or the gwt.xml file. So that answers your question about mainPanel.add(new HTML(headerBuilder.toSafeHtml().toString()));
In respect to the Hyperlink. If you choose to use hyperlinks, remember that the most effective usage is with the MVP pattern better known as Places and Activities (Lots of information on the web)
If you want something simpler instead the MenuBar and MenuItem classes should do the trick.
Look here for an example on how to use the MenuBar to control your application. There are many other ways but why not use the tools provided?
Also the UIBinder Vs the Designer/Classes methods is extensively discussed on stackoverflow resulting to a matter of choice and programming familiarity/preference.
I am developing an Wicket application. But my question is not really Wicket related. In that app I have a horizontal menu. This menu is created by few links. On clicking the link you will be navigated to some page. Now based on the page you are currently viewing the css class attribute of the link of the menu will be changed to "selected". This is the description of the problem.
Now I am solving this problem by using a integer value. The value is saved in the session and it is updated when any one link has been clicked. Based on that saved value, which link will be "selected", will be determined at runtime.
I am implementing this in following way:
//On link click I set a number in session
public void onClick() {
session.setValue(1);// or 2 or 3
}
When the menu is created I switch between the value and modify the css class, as follows:
switch(session.getValue){
case 1: add css to home;
case 2: add css to profile;
// and so on.
}
I was wondering that is this the only right way to do it? Or there some other better techniques or design patterns exist which can help me to achieve this in better way?
Store the menu items in an array (or an ArrayList):
items[0] = home
items[1] = profile
And use the index of the array as menu identifier. When you receive the selected menu itentifier, retrieve the corresponding item with
items[selectedItem]
You could also use a Map if the identifiers are not numbers, or don't go from 0 to N.
For a start, use an enum or static constants instead of magic numbers (1, 2, 3).
The Visitor Pattern is commonly used to avoid this sort of switching. You might not want to implement the full pattern in your case, but it's worth knowning. JB Nizet's answer may be more practical in your situation.
See https://en.wikipedia.org/wiki/Visitor_pattern
These SO questions might give you some ideas, too
Java visitor pattern instead of instanceof switch
Java Enums - Switch statements vs Visitor Pattern on Enums - Performance benefits?
I have implemented it using EnumMap and an Enum type as its key. I have defined an Enum:
public enum NavigationStatus {
HOME,
PROFILE;
}
In session I set the value of the current navigation as:
private NavigationStatus activeUserNavigationStatus;
public NavigationStatus getActiveUserNavigationStatus() {
return activeUserNavigationStatus;
}
public void setActiveUserNavigationStatus(NavigationStatus activeUserNavigationStatus) {
this.activeUserNavigationStatus = activeUserNavigationStatus;
}
Primarily I set it to: setActiveUserNavigationStatus(NavigationStatus.HOME);
Now where the menu is building I created an EnumMap:
EnumMap<NavigationStatus, Component[]> menuMap = new EnumMap<NavigationStatus, Component[]>(NavigationStatus.class);
And added elements to it, as:
menuMap.put(NavigationStatus.HOME, new Component[] { homeContainer, home });
And also on click methods of the links I set the status value:
public void onClick() {
session.setActiveUserNavigationStatus(NavigationStatus.PROFILE);
}
Last of all I checked the current value from the session and set the css class accordingly:
Component[] menuComponents = menuMap.get(getSession().getActiveUserNavigationStatus());
menuComponents[0].add(new AttributeAppender("class", new Model<Serializable>(" active")));
menuComponents[1].add(new AttributeAppender("class", new Model<Serializable>(" active")));
This is without switch statement and combines the idea of JB Nizet's ArrayList index and Oli Charlesworth's Enum.
Thank you.
In a Wicket app, I have a modal dialog that contains a simple form and a button. User enters values (report parameters), and then clicks the button which starts the download of a report file (typically a PDF). (All form values are required, and Wicket's validation mechanism is used to make sure user entered them before the download can start.)
Maybe this is better explained with a picture:
I'm using here a jQuery UI Dialog (instead of Wicket's ModalWindow which felt a lot clumsier and uglier from user's perspective).
Everything is pretty much working, except closing the dialog when/after clicking the download button.
Current version (irrelevant bits omitted):
public class ReportDownloadLink extends Link {
public ReportDownloadLink(String id, ReportDto report) {
super(id);
this.report = report;
}
#Override
public void onClick() {
IResourceStream resourceStream = new AbstractResourceStreamWriter() {
#Override
public void write(OutputStream output) {
try {
reportService.generateReport(output, report);
} catch (ReportGenerationException e) {
// ...
}
}
#Override
public String getContentType() {
// ...
}
};
ResourceStreamRequestTarget target =
new ResourceStreamRequestTarget(resourceStream, report.getFileName());
getRequestCycle().setRequestTarget(target);
}
The dialog is a Wicket Panel (which makes use of ReportDownloadLink above), which we put in a certain div, and then when a report is selected in a list, the dialog is opened from an AjaxLink's onClick() quite simply like this:
target.appendJavascript(String.format("showReportExportDialog('%s')", ... ));
Which calls this JS function:
function showReportExportDialog(dialogTitle) {
$("#reportExportPanelContainer").dialog(
{modal:true, draggable:true, width: 320, height: 330, title: dialogTitle}
);
}
Some options:
Make ReportDownloadLink extend something else than Link, perhaps, and/or find an appropriate method to override which would allow me to execute the tiny bit of JavaScript needed to close the jQuery Dialog.
Investigate jQuery + Wicket libraries (such as jqwicket or wiquery) that supposedly make these two work better together.
Latest thing I tried was overriding method getOnClickScript() in ReportDownloadLink which seemed promising (according to the Javadocs, it returns "Any onClick JavaScript that should be used"):
#Override
protected CharSequence getOnClickScript(CharSequence url) {
return "closeDownloadDialog()";
}
Thing is, this causes onClick() not to be called at all, i.e., the download doesn't start.
Could I perhaps override some more "ajaxy" class from Wicket (than Link) to combine these things: first init the download, then call the JS for closing the dialog?
Any recommendations or experiences from similar cases? Note that I want to keep using the jQuery dialog here, even though it makes things like these more complicated. Using a DownloadLink (see related question) is fine too in case that makes things easier.
NB: if you recommend JQWicket or wiQuery, please provide an example of how to do this.
Maybe you can try to bind the close modal code to the button "click" event using only JQuery, in your modal panel page, add something similar to ${"#mySubmit").click(myCloseModalFunction). It should keep Wicket default's behavior and add modal closing in the mix.
The other way is to override the getOnClickScript(...) method but the javascript has to return true in order for the browser to call the continue link evaluation and load the corresponding href. If you return false, the evaluation stops. I would suggest something like
#Override
protected CharSequence getOnClickScript(CharSequence url) {
return "closeDownloadDialog();return true;";
}
Hope it helps...
See https://cwiki.apache.org/WICKET/ajax-update-and-file-download-in-one-blow.html for inspiration.
I am trying to write a JTextPane which supports some sort of coloring: as the user is typing the text, I am running some code that colors the text according to a certain algorithm. This works well.
The problem is that the coloring operations is registered with the undo manager (a DefaultDocumentEvent with EventType.CHANGE). So when the user clicks undo the coloring disappears. Only at the second undo request the text itself is rolled back.
(Note that the coloring algorithm is somewhat slow so I cannot color the text as it is being inserted).
If I try to prevent the CHANGE events from reaching the undo manager I get an exception after several undo requests: this is because the document contents are not conforming to what the undoable-edit object expects.
Any ideas?
You could intercept the CHANGE edits and wrap each one in another UndoableEdit whose isSignificant() method returns false, before adding it to the UndoManager. Then each Undo command will undo the most recent INSERT or REMOVE edit, plus every CHANGE edit that occurred since then.
Ultimately, I think you'll find that the styling mechanism provided by JTextPane/StyledDocument/etc. is too limited for this kind of thing. It's slow, it uses too much memory, and it's based on the same Element tree that's used to keep track of the lexical structure of the document. It's okay (I guess) for applications in which the styles are applied by the user, like word processors, but not for a syntax highlighter that has to update the styles constantly as the user types.
There are several examples out there of syntax-highlighting editors based on custom implementations of the Swing JTextComponent, View and Document classes. Some, like JEdit, re-implement practically the whole javax.swing.text package, but I don't think you need to go that far.
How are you trying to prevent the CHANGE events from reaching the undo manager?
Can you not send the UndoManager a lastEdit().die() call immediately after the CHANGE is queued?
I can only assume how you are doing the text colouring. If you are doing it in the StyledDocuments change character attribute method you can get the undo listener and temporarily deregister it from the document for that operation and then once the colour change has finshed then you can reregister the listener.
Should be fine for what you are trying to do there.
hope that helps
I have just been through this problem. Here is my solution:
private class UndoManagerFix extends UndoManager {
private static final long serialVersionUID = 5335352180435980549L;
#Override
public synchronized void undo() throws CannotUndoException {
do {
UndoableEdit edit = editToBeUndone();
if (edit instanceof AbstractDocument.DefaultDocumentEvent) {
AbstractDocument.DefaultDocumentEvent event = (AbstractDocument.DefaultDocumentEvent) edit;
if (event.getType() == EventType.CHANGE) {
super.undo();
continue;
}
}
break;
} while (true);
super.undo();
}
#Override
public synchronized void redo() throws CannotRedoException {
super.redo();
int caretPosition = getCaretPosition();
do {
UndoableEdit edit = editToBeRedone();
if (edit instanceof AbstractDocument.DefaultDocumentEvent) {
AbstractDocument.DefaultDocumentEvent event = (AbstractDocument.DefaultDocumentEvent) edit;
if (event.getType() == EventType.CHANGE) {
super.redo();
continue;
}
}
break;
} while (true);
setCaretPosition(caretPosition);
}
}
It is an inner class in my custom JTextPane, so I can fix the caret position on redo.