001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.wicket.markup.html.panel; 018 019import java.io.Serializable; 020import java.util.Collections; 021import java.util.Comparator; 022import java.util.List; 023 024import org.apache.wicket.AttributeModifier; 025import org.apache.wicket.Component; 026import org.apache.wicket.feedback.FeedbackMessage; 027import org.apache.wicket.feedback.FeedbackMessagesModel; 028import org.apache.wicket.feedback.IFeedback; 029import org.apache.wicket.feedback.IFeedbackMessageFilter; 030import org.apache.wicket.markup.html.WebMarkupContainer; 031import org.apache.wicket.markup.html.basic.Label; 032import org.apache.wicket.markup.html.list.ListItem; 033import org.apache.wicket.markup.html.list.ListView; 034import org.apache.wicket.model.IModel; 035 036 037/** 038 * A panel that displays {@link org.apache.wicket.feedback.FeedbackMessage}s in a list view. The 039 * maximum number of messages to show can be set with setMaxMessages(). 040 * 041 * @see org.apache.wicket.feedback.FeedbackMessage 042 * @see org.apache.wicket.feedback.FeedbackMessages 043 * @author Jonathan Locke 044 * @author Eelco Hillenius 045 */ 046public class FeedbackPanel extends Panel implements IFeedback 047{ 048 /** 049 * List for messages. 050 */ 051 private final class MessageListView extends ListView<FeedbackMessage> 052 { 053 private static final long serialVersionUID = 1L; 054 055 /** 056 * @see org.apache.wicket.Component#Component(String) 057 */ 058 public MessageListView(final String id) 059 { 060 super(id); 061 setDefaultModel(newFeedbackMessagesModel()); 062 } 063 064 @Override 065 protected IModel<FeedbackMessage> getListItemModel( 066 final IModel<? extends List<FeedbackMessage>> listViewModel, final int index) 067 { 068 return new IModel<FeedbackMessage>() 069 { 070 private static final long serialVersionUID = 1L; 071 072 /** 073 * WICKET-4258 Feedback messages might be cleared already. 074 * 075 * @see org.apache.wicket.settings.ApplicationSettings#setFeedbackMessageCleanupFilter(org.apache.wicket.feedback.IFeedbackMessageFilter) 076 */ 077 @Override 078 public FeedbackMessage getObject() 079 { 080 if (index >= listViewModel.getObject().size()) 081 { 082 return null; 083 } 084 else 085 { 086 return listViewModel.getObject().get(index); 087 } 088 } 089 }; 090 } 091 092 @Override 093 protected void populateItem(final ListItem<FeedbackMessage> listItem) 094 { 095 final FeedbackMessage message = listItem.getModelObject(); 096 message.markRendered(); 097 final Component label = newMessageDisplayComponent("message", message); 098 final AttributeModifier levelModifier = AttributeModifier.append("class", 099 getCSSClass(message)); 100 listItem.add(levelModifier); 101 listItem.add(label); 102 } 103 104 /** 105 * WICKET-4831 - Overridable to allow customization 106 * 107 * @param index 108 * The index of the item 109 * @param itemModel 110 * object in the list that the item represents 111 * @return 112 */ 113 @Override 114 protected ListItem<FeedbackMessage> newItem(int index, IModel<FeedbackMessage> itemModel) 115 { 116 return FeedbackPanel.this.newMessageItem(index, itemModel); 117 } 118 } 119 120 private static final long serialVersionUID = 1L; 121 122 /** Message view */ 123 private final MessageListView messageListView; 124 125 /** 126 * @see org.apache.wicket.Component#Component(String) 127 */ 128 public FeedbackPanel(final String id) 129 { 130 this(id, null); 131 } 132 133 /** 134 * @see org.apache.wicket.Component#Component(String) 135 * 136 * @param id 137 * @param filter 138 */ 139 public FeedbackPanel(final String id, IFeedbackMessageFilter filter) 140 { 141 super(id); 142 WebMarkupContainer messagesContainer = new WebMarkupContainer("feedbackul") 143 { 144 private static final long serialVersionUID = 1L; 145 146 @Override 147 protected void onConfigure() 148 { 149 super.onConfigure(); 150 setVisible(anyMessage()); 151 } 152 }; 153 add(messagesContainer); 154 messageListView = new MessageListView("messages"); 155 messageListView.setVersioned(false); 156 messagesContainer.add(messageListView); 157 158 if (filter != null) 159 { 160 setFilter(filter); 161 } 162 } 163 164 /** 165 * Search messages that this panel will render, and see if there is any message of level ERROR 166 * or up. This is a convenience method; same as calling 'anyMessage(FeedbackMessage.ERROR)'. 167 * 168 * @return whether there is any message for this panel of level ERROR or up 169 */ 170 public final boolean anyErrorMessage() 171 { 172 return anyMessage(FeedbackMessage.ERROR); 173 } 174 175 /** 176 * Search messages that this panel will render, and see if there is any message. 177 * 178 * @return whether there is any message for this panel 179 */ 180 public final boolean anyMessage() 181 { 182 return anyMessage(FeedbackMessage.UNDEFINED); 183 } 184 185 /** 186 * Search messages that this panel will render, and see if there is any message of the given 187 * level. 188 * 189 * @param level 190 * the level, see FeedbackMessage 191 * @return whether there is any message for this panel of the given level 192 */ 193 public final boolean anyMessage(int level) 194 { 195 List<FeedbackMessage> msgs = getCurrentMessages(); 196 197 for (FeedbackMessage msg : msgs) 198 { 199 if (msg.isLevel(level)) 200 { 201 return true; 202 } 203 } 204 205 return false; 206 } 207 208 /** 209 * @return Model for feedback messages on which you can install filters and other properties 210 */ 211 public final FeedbackMessagesModel getFeedbackMessagesModel() 212 { 213 return (FeedbackMessagesModel)messageListView.getDefaultModel(); 214 } 215 216 /** 217 * @return The current message filter 218 */ 219 public final IFeedbackMessageFilter getFilter() 220 { 221 return getFeedbackMessagesModel().getFilter(); 222 } 223 224 /** 225 * @return The current sorting comparator 226 */ 227 public final Comparator<FeedbackMessage> getSortingComparator() 228 { 229 return getFeedbackMessagesModel().getSortingComparator(); 230 } 231 232 /** 233 * @see org.apache.wicket.Component#isVersioned() 234 */ 235 @Override 236 public boolean isVersioned() 237 { 238 return false; 239 } 240 241 /** 242 * Sets a filter to use on the feedback messages model 243 * 244 * @param filter 245 * The message filter to install on the feedback messages model 246 * 247 * @return FeedbackPanel this. 248 */ 249 public final FeedbackPanel setFilter(IFeedbackMessageFilter filter) 250 { 251 getFeedbackMessagesModel().setFilter(filter); 252 return this; 253 } 254 255 /** 256 * @param maxMessages 257 * The maximum number of feedback messages that this feedback panel should show at 258 * one time 259 * 260 * @return FeedbackPanel this. 261 */ 262 public final FeedbackPanel setMaxMessages(int maxMessages) 263 { 264 messageListView.setViewSize(maxMessages); 265 return this; 266 } 267 268 /** 269 * Sets the comparator used for sorting the messages. 270 * 271 * @param sortingComparator 272 * comparator used for sorting the messages. 273 * 274 * @return FeedbackPanel this. 275 */ 276 public final FeedbackPanel setSortingComparator(Comparator<FeedbackMessage> sortingComparator) 277 { 278 getFeedbackMessagesModel().setSortingComparator(sortingComparator); 279 return this; 280 } 281 282 /** 283 * Gets the css class for the given message. 284 * 285 * @param message 286 * the message 287 * @return the css class; by default, this returns feedbackPanel + the message level, eg 288 * 'feedbackPanelERROR', but you can override this method to provide your own 289 */ 290 protected String getCSSClass(final FeedbackMessage message) 291 { 292 String cssClass; 293 switch (message.getLevel()) 294 { 295 case FeedbackMessage.UNDEFINED: 296 cssClass = getString(FeedbackMessage.UNDEFINED_CSS_CLASS_KEY); 297 break; 298 case FeedbackMessage.DEBUG: 299 cssClass = getString(FeedbackMessage.DEBUG_CSS_CLASS_KEY); 300 break; 301 case FeedbackMessage.INFO: 302 cssClass = getString(FeedbackMessage.INFO_CSS_CLASS_KEY); 303 break; 304 case FeedbackMessage.SUCCESS: 305 cssClass = getString(FeedbackMessage.SUCCESS_CSS_CLASS_KEY); 306 break; 307 case FeedbackMessage.WARNING: 308 cssClass = getString(FeedbackMessage.WARNING_CSS_CLASS_KEY); 309 break; 310 case FeedbackMessage.ERROR: 311 cssClass = getString(FeedbackMessage.ERROR_CSS_CLASS_KEY); 312 break; 313 case FeedbackMessage.FATAL: 314 cssClass = getString(FeedbackMessage.FATAL_CSS_CLASS_KEY); 315 break; 316 default: 317 cssClass = "feedbackPanel" + message.getLevelAsString(); 318 } 319 return cssClass; 320 } 321 322 /** 323 * Gets the currently collected messages for this panel. 324 * 325 * @return the currently collected messages for this panel, possibly empty 326 */ 327 protected final List<FeedbackMessage> getCurrentMessages() 328 { 329 final List<? extends FeedbackMessage> messages = messageListView.getModelObject(); 330 return Collections.unmodifiableList(messages); 331 } 332 333 /** 334 * Gets a new instance of FeedbackMessagesModel to use. 335 * 336 * @return Instance of FeedbackMessagesModel to use 337 */ 338 protected FeedbackMessagesModel newFeedbackMessagesModel() 339 { 340 return new FeedbackMessagesModel(this); 341 } 342 343 /** 344 * Generates a component that is used to display the message inside the feedback panel. This 345 * component must handle being attached to <code>span</code> tags. 346 * 347 * By default a {@link Label} is used. 348 * 349 * Note that the created component is expected to respect feedback panel's 350 * {@link #getEscapeModelStrings()} value 351 * 352 * @param id 353 * parent id 354 * @param message 355 * feedback message 356 * @return component used to display the message 357 */ 358 protected Component newMessageDisplayComponent(String id, FeedbackMessage message) 359 { 360 Serializable rawMessage = message.getMessage(); 361 Label label = new Label(id, rawMessage); 362 label.setEscapeModelStrings(FeedbackPanel.this.getEscapeModelStrings()); 363 return label; 364 } 365 366 /** 367 * Allows to define the listItem to use in the feedback's message list. 368 * 369 * @param index 370 * The index of the item 371 * @param itemModel 372 * The model object of the item 373 * @return Container that holds components of the feedback MessageListView. 374 */ 375 protected ListItem<FeedbackMessage> newMessageItem(int index, IModel<FeedbackMessage> itemModel) { 376 return new ListItem<>(index, itemModel); 377 } 378}