[jboss-user] [JBoss Seam] - How to use ice:dataTable and @DataModel?

Newlukai do-not-reply at jboss.com
Thu Jan 25 11:26:55 EST 2007


Hi there,

I've a problem that's hard to explain. But give me a chance ;)

My application manages testactions. A testaction can be viewed by a tester (who executes the test), a developer (who fixes the software if a testaction failed) and a validator (who validates that the fix works). A user can now choose which page he wants to see since he is tester for this software and developer for another one and so on. Every page lists all the testactions to do for the user. The testaction objects are the same.

On such a page the user has the choice to apply a filter on that list. E g. just list all the testactions with a high priority. Those filters are realised with selectOneMenus. When the user changes a filter, the list is updated according to the new filter.

>From that list the user selects a testaction by clicking its ID and is redirected to a page where he can edit the testaction.

I hope you can follow.

Because those lists almost do the same thing I introduced a superclass that manages all the list stuff like sorting (yes, the list is sortable) or the selection of a testaction.

This superclass has three subclasses (I don't know how to phrase it, I'm German) which take care of the special things for tester, developer and validator. E. g. and especially the database query to retrieve all that testactions is different for each user role.

OK. I think it's time for some code.

Here's the superclass:
public class TestactionHandling {	
  |   protected List<Testaction> testactions;
  | //  @DataModelSelectionIndex
  | //  workaround: Seam can't handle @DataModelSelection AND
  | //  @DataModelSelectionIndex in one class
  |   protected int testactionIndex;
  |   @DataModelSelection
  |   protected Testaction testaction;
  | 
  |   @In(required=false)
  |   @Out(required=false, scope=ScopeType.SESSION)
  |   protected Testaction currentTestaction;
  | 
  |   protected List<Testaction> currentTestactions;
  |   protected int currentTestactionIndex;
  | 
  |   protected String column = "id";
  |   protected boolean ascending = true;
  | 
  |   private long lastRefreshTime;
  |   private final long REFRESH_PERIOD = 60000; //1 minute
  | 
  | 
  |   public String select() {
  |     currentTestactions = testactions;
  | //    currentTestaction.clone();
  | //    currentTestactionIndex = testactionIndex;
  | //    workaround
  | 
  |     for(Testaction ta : currentTestactions) {
  |       if(ta.getID() == currentTestaction.getID()) {
  |         currentTestactionIndex = currentTestactions.indexOf(ta);
  |         break;
  |       }
  |     }
  |     return "selected";
  |   }
  | 
  |   public String saveTestaction() {
  |     applyChanges();
  |     return currentTestactions.size() == 0 ? "backToList" : "browse";
  |   }
  | 
  |   public String saveTestactionAndNext() {
  |     applyChanges();
  |     return nextTestaction();
  |   }
  | 
  |   public String nextTestaction() {
  |     String outcome = shiftTestaction(1) ? "browse" : "backToList";
  |     return outcome;
  |   }
  | 
  |   public String prevTestaction() {
  |     String outcome = shiftTestaction(-1) ? "browse" : "backToList";
  |     return outcome;
  |   }
  | 
  |   public boolean isAscending() {
  |     return ascending;
  |   }
  | 
  |   public void setAscending(boolean ascending) {
  |     if(ascending != this.ascending) {
  |       testactions = null;
  |     }
  |     this.ascending = ascending;
  |   }
  | 
  |   public String getColumn() {
  |     return column;
  |   }
  | 
  |   public void setColumn(String column) {
  |     if(!column.equals(this.column)) {
  |       testactions = null;
  |     }
  |     this.column = column;
  |   }
  | 
  |   public int getTestactionIndexHR() {
  |     return currentTestactionIndex + 1;
  |   }
  | 
  |   public int getTestactionsSize() {
  |     int result = (currentTestactions == null) ? 0 : currentTestactions.size();
  |     return result;
  |   }
  | 
  |   protected void applyChanges() {
  |   }
  | 
  |   protected boolean shiftTestaction(int distance) {
  |     if(currentTestactions.size() == 0) {
  |       return false;
  |     }
  |     currentTestactionIndex += distance;
  |     while(currentTestactionIndex >= currentTestactions.size()) {
  |       currentTestactionIndex -= currentTestactions.size();
  |     }
  |     while(currentTestactionIndex < 0) {
  |       currentTestactionIndex += currentTestactions.size();
  |     }
  |     testaction = currentTestactions.get(currentTestactionIndex);
  |     updateTestactionForProtocol();
  |     return true;
  |   }
  | 
  |   protected boolean shouldRefresh() {
  |     if((System.currentTimeMillis() - REFRESH_PERIOD) > lastRefreshTime) {
  |       refresh();
  |       lastRefreshTime = System.currentTimeMillis();
  |       return true;
  |     }
  |     return false;
  |   }
  | 
  |   public String refresh() {
  |     testactions = null;
  |     return "";
  |   }
  | 
  |   private void updateTestactionsListAndSelectionModels() {
  |     currentTestactions.set(currentTestactionIndex, currentTestaction);
  |     testaction = currentTestaction;
  |     testactions = currentTestactions;
  |   }
  | }

And here is one of the subclasses:
@Stateful
  | @Scope(ScopeType.SESSION)
  | @LoggedIn
  | @Name("testactionDeveloper")
  | public class TestactionDeveloperAction extends TestactionHandling implements
  | TestactionDeveloper, Serializable {
  |   @In(required=false)
  |   private Release selectedRelease;
  | 
  |   @In(required=false)
  |   private Priorityclass selectedPriority;
  | 
  |   @In(required=false)
  |   private Severityclass selectedSeverity;
  | 
  |   @In(required=false)
  |   private User selectedUser;
  | 
  |   private Long lastSelectedReleaseID;
  |   private String lastSelectedPriorityID;
  |   private Integer lastSelectedSeverityID;
  |   private String lastSelectedUserID;
  | 
  | 
  |   @Factory("testactionsForDeveloper")
  |   public void initTestactions() {
  |     if(hasAFilterChanged() || shouldRefresh() || testactions == null) {
  |       testactions = EMHelper.execQuery(em, "from Testaction
  |         where (TACT_REV_ID=2 or TACT_REV_ID=9) and
  |         (TACT_BFV_ID=4 or TACT_BFV_ID=99)" + generateFilterStatements() +
  |         "order by TACT_ID asc"
  |       );
  | 
  |       updateFilterHelpers();
  |     }
  |     Collections.sort(testactions, new TestactionComparator(column, ascending));
  |   }
  | 
  |   @DataModel//(scope=ScopeType.PAGE)
  |   public List<Testaction> getTestactionsForDeveloper() {
  |     initTestactions();
  |     return testactions;
  |   }
  | }

Here is the page for that subclass:
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
  |   xmlns:ui="http://java.sun.com/jsf/facelets"
  |   xmlns:h="http://java.sun.com/jsf/html"
  |   xmlns:f="http://java.sun.com/jsf/core"
  |   xmlns:ice="http://www.icesoft.com/icefaces/component"
  |   template="template.xhtml">
  | 
  | <ui:define name="content">
  |   <h1>#{ares_messages.header_listForDeveloper}</h1>
  |   <ice:form>
  |     <div id="release">
  |       <table cellpadding="0" cellspacing="0" border="0" class="filter">
  |         <thead>
  |           <tr>
  |             <th colspan="4">
  |               <h:outputText value="#{ares_messages.filter_header}" />
  |             </th>
  |           </tr>
  |           <tr>
  |             <th><h:outputText value="#{ares_messages.filter_release}" /></th>
  |             <th><h:outputText value="#{ares_messages.filter_severity}" /></th>
  |             <th><h:outputText value="#{ares_messages.filter_priority}" /></th>
  |             <th><h:outputText value="#{ares_messages.filter_user}" /></th>
  |           </tr>
  |         </thead>
  |         <tr>
  |           <td>
  |             <ice:selectOneMenu value="#{releaseSelector.selectedReleaseNumber}"
  |               valueChangeListener="#{releaseSelector.valueChanged}"
  |               partialSubmit="true">
  |               <f:selectItems value="#{releaseSelector.releaseItems}" />
  |             </ice:selectOneMenu>
  |           </td>
  |           <td>
  |             <ice:selectOneMenu
  |               value="#{severitySelector.selectedSeverityNumber}"
  |               partialSubmit="true">
  |               <f:selectItems value="#{severitySelector.severityItems}" />
  |             </ice:selectOneMenu>
  |           </td>
  |           ...
  |         </tr>
  |       </table>
  | 
  |       <br />
  |       <ice:commandButton action="#{testactionDeveloper.refresh}"
  |         image="img/refresh.gif" styleClass="graphical"
  |         title="#{ares_messages.tooltip_refreshList}" />
  |     </div>
  | 
  |     <ice:dataTable var="testaction_var"
  |       value="#{testactionDeveloper.testactionsForDeveloper}"
  |       sortColumn="#{testactionDeveloper.column}"
  |       sortAscending="#{testactionDeveloper.ascending}">
  |       <f:facet name="header">
  |         <h:outputText value="#{ares_messages.label_ResultCount}:
  |           #{testactionsForDeveloper.rowCount}" />
  |       </f:facet>
  |       <h:column>
  |         <f:facet name="header">
  |           <ice:commandSortHeader columnName="id">
  |             <h:outputText value="#{ares_messages.label_testaction_ID}" />
  |           </ice:commandSortHeader>
  |         </f:facet>
  |         <ice:commandLink value="#{testaction_var.ID}"
  |           action="#{testactionDeveloper.select}" styleClass="rightAlignment" />
  |       </h:column>
  | ...

I think it's enough ;)
Now my problem: I don't get it working properly with ICEfaces. It worked with Tomahawk, but doesn't with ICEfaces.

There are three ways I tried:


  | *  The way described in the WIKI for Tomahawk's dataTable. The @DataModel and the @Factory are in the subclass and the dataTable refers to the @DataModel's name ("#{testactionForDevelopers}").
  | The result is that when the user changes the filter, the list applies the filter values that were applied before. E. g. the user selects priority A, the list doesn't change. The user select priority B, then the list shows priority A and so on.
  | *  The way it's done in the Seam icefaces example. @Factory in the subclass, @DataModel on the testactions member in the superclass and the dataTable refers to the @Factory's name.
  | The list is empty.
  | *  The way it's done in the ICEfaces TimeZone example. Remove @Factory and put the @DataModel on the testactions member in the superclass. The dataTable refers to "#{testactionDeveloper.testactionsForDeveloper}".
  | The list can be filtered like it should. But when the user selects a testaction always the first one in the list is displayed. I think Seam can't determine the Index in this constellation.
  | 

I've to excuse for this monster, but I don't know how to solve my problem and I don't want to give you too little information to help me.

Thanks in advance
Newlukai

BTW: Did anyone get this ice:menuBar working with more than one level?

View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4006413#4006413

Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4006413



More information about the jboss-user mailing list