empire-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From doeb...@apache.org
Subject [3/3] empire-db git commit: EMPIREDB-235
Date Mon, 01 Feb 2016 13:18:32 GMT
EMPIREDB-235

Project: http://git-wip-us.apache.org/repos/asf/empire-db/repo
Commit: http://git-wip-us.apache.org/repos/asf/empire-db/commit/9176b225
Tree: http://git-wip-us.apache.org/repos/asf/empire-db/tree/9176b225
Diff: http://git-wip-us.apache.org/repos/asf/empire-db/diff/9176b225

Branch: refs/heads/master
Commit: 9176b225f4c3816486b05146a22167e0a0d5b851
Parents: 1f1259b
Author: Rainer Döbele <doebele@apache.org>
Authored: Mon Feb 1 14:18:21 2016 +0100
Committer: Rainer Döbele <doebele@apache.org>
Committed: Mon Feb 1 14:18:21 2016 +0100

----------------------------------------------------------------------
 .../empire-db-example-jsf2/pom.xml              |   2 +-
 .../jsf2/custom/controls/FileInputControl.java  |  14 +
 .../websample/web/pages/EmployeeDetailPage.java |  18 +
 .../main/resources/lang/messages_de.properties  |  14 +-
 .../main/resources/lang/messages_en.properties  |   3 +
 .../src/main/webapp/WEB-INF/faces-config.xml    |  20 +-
 .../src/main/webapp/css/content.css             |  51 +-
 .../main/webapp/pages/employeeDetailPage.xhtml  |  35 +-
 .../main/webapp/resources/empire/mitem.xhtml    |  19 +
 .../main/webapp/resources/empire/mlist.xhtml    |  19 +
 .../main/webapp/resources/empire/select.xhtml   |  21 +
 .../main/webapp/resources/empire/tabPage.xhtml  |  15 +
 .../main/webapp/resources/empire/tabView.xhtml  |  17 +
 .../apache/empire/jsf2/app/WebApplication.java  |   4 +-
 .../empire/jsf2/components/ControlTag.java      | 464 +++++++++++--------
 .../apache/empire/jsf2/components/InputTag.java | 149 ++++--
 .../apache/empire/jsf2/components/LabelTag.java |  56 ++-
 .../apache/empire/jsf2/components/LinkTag.java  |  86 +++-
 .../empire/jsf2/components/MenuItemTag.java     |  52 ++-
 .../empire/jsf2/components/MenuListTag.java     |  91 +++-
 .../empire/jsf2/components/SelectTag.java       | 110 ++++-
 .../empire/jsf2/components/TabPageTag.java      |  92 ++++
 .../empire/jsf2/components/TabViewTag.java      | 387 ++++++++++++++++
 .../jsf2/controls/CheckboxInputControl.java     |  65 +--
 .../empire/jsf2/controls/InputControl.java      | 304 +++++++-----
 .../jsf2/controls/InputControlManager.java      | 111 ++++-
 .../empire/jsf2/controls/RadioInputControl.java | 437 +++++++++++++++++
 .../jsf2/controls/SelectInputControl.java       | 252 +++++++---
 .../jsf2/controls/TextAreaInputControl.java     |  28 +-
 .../empire/jsf2/controls/TextInputControl.java  | 359 ++++++++------
 .../pageelements/StaticListPageElement.java     |   2 +-
 .../java/org/apache/empire/jsf2/pages/Page.java |  24 +-
 .../apache/empire/jsf2/pages/PageOutcome.java   |   6 +-
 .../empire/jsf2/pages/PagesELResolver.java      |   2 +-
 .../apache/empire/jsf2/utils/SessionMap.java    |  66 +++
 .../empire/jsf2/utils/TagEncodingHelper.java    | 227 ++++++---
 .../java/org/apache/empire/data/Column.java     |  20 +
 .../java/org/apache/empire/db/DBColumn.java     |  26 +-
 .../org/apache/empire/db/DBTableColumn.java     |  31 +-
 39 files changed, 2904 insertions(+), 795 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/empire-db/blob/9176b225/empire-db-examples/empire-db-example-jsf2/pom.xml
----------------------------------------------------------------------
diff --git a/empire-db-examples/empire-db-example-jsf2/pom.xml b/empire-db-examples/empire-db-example-jsf2/pom.xml
index 98f1131..fbf3328 100644
--- a/empire-db-examples/empire-db-example-jsf2/pom.xml
+++ b/empire-db-examples/empire-db-example-jsf2/pom.xml
@@ -50,7 +50,7 @@
 		</dependency>
 
 		<!-- Sun Mojarra -->
-		<!-- 
+		<!--
 		<dependency>
 			<groupId>com.sun.faces</groupId>
 			<artifactId>jsf-api</artifactId>

http://git-wip-us.apache.org/repos/asf/empire-db/blob/9176b225/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/custom/controls/FileInputControl.java
----------------------------------------------------------------------
diff --git a/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/custom/controls/FileInputControl.java b/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/custom/controls/FileInputControl.java
index 68555d7..b062dcf 100644
--- a/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/custom/controls/FileInputControl.java
+++ b/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/custom/controls/FileInputControl.java
@@ -25,6 +25,7 @@ import javax.faces.component.html.HtmlInputText;
 import javax.faces.context.FacesContext;
 
 import org.apache.empire.exceptions.InternalException;
+import org.apache.empire.exceptions.UnexpectedReturnValueException;
 import org.apache.empire.jsf2.controls.InputControl;
 
 public class FileInputControl extends InputControl
@@ -68,6 +69,19 @@ public class FileInputControl extends InputControl
         compList.add(input);
     }
 
+    @Override
+    protected void updateInputState(List<UIComponent> compList, InputInfo ii, FacesContext context)
+    {
+        UIComponent comp = compList.get(0);
+        if (!(comp instanceof HtmlInputFile))
+        {
+            throw new UnexpectedReturnValueException(comp.getClass().getName(), "compList.get(0)");
+        }
+        // update state
+        HtmlInputFile input = (HtmlInputFile) comp;
+        input.setDisabled(ii.isDisabled());
+    }
+
     public class HtmlInputFile extends HtmlInputText
     {
         public static final String RENDER_TYPE = "org.apache.empire.jsf2.custom.controls.FileInputRenderer";

http://git-wip-us.apache.org/repos/asf/empire-db/blob/9176b225/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/websample/web/pages/EmployeeDetailPage.java
----------------------------------------------------------------------
diff --git a/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/websample/web/pages/EmployeeDetailPage.java b/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/websample/web/pages/EmployeeDetailPage.java
index b2f19eb..3a19f89 100644
--- a/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/websample/web/pages/EmployeeDetailPage.java
+++ b/empire-db-examples/empire-db-example-jsf2/src/main/java/org/apache/empire/jsf2/websample/web/pages/EmployeeDetailPage.java
@@ -37,6 +37,8 @@ public class EmployeeDetailPage extends SamplePage
 
     private RecordPageElement<EmployeeRecord> employee;
 
+    private int                               activeTab         = 0;
+    
     public EmployeeDetailPage()
     {
         log.trace("EmployeeDetailPage created");
@@ -67,6 +69,16 @@ public class EmployeeDetailPage extends SamplePage
         return employee.getRecord();
     }
 
+    public int getActiveTab()
+    {
+        return activeTab;
+    }
+
+    public void setActiveTab(int activeTab)
+    {
+        this.activeTab = activeTab;
+    }
+
     @Override
     public void doInit()
     { // Notify Elements
@@ -108,4 +120,10 @@ public class EmployeeDetailPage extends SamplePage
     {
         return getParentOutcome(true);
     }
+
+    public void onTabChanged(int newPage)
+    {
+        log.debug("onTabChanged " + newPage);
+    }
+    
 }

http://git-wip-us.apache.org/repos/asf/empire-db/blob/9176b225/empire-db-examples/empire-db-example-jsf2/src/main/resources/lang/messages_de.properties
----------------------------------------------------------------------
diff --git a/empire-db-examples/empire-db-example-jsf2/src/main/resources/lang/messages_de.properties b/empire-db-examples/empire-db-example-jsf2/src/main/resources/lang/messages_de.properties
index dbbde7b..8d3c8da 100644
--- a/empire-db-examples/empire-db-example-jsf2/src/main/resources/lang/messages_de.properties
+++ b/empire-db-examples/empire-db-example-jsf2/src/main/resources/lang/messages_de.properties
@@ -72,20 +72,12 @@ employeeList_search=Suchen
 employeeList_resetSearch=Suche zur�cksetzen
 
 employeeDetail_title = Mitarbeiterdetails
+employeeDetail_tab_basic = Grunddaten
+employeeDetail_tab_extended = Weitere Daten
+employeeDetail_msg_extended = Hier k�nnen weitere Daten angezeigt werden
 employeeDetail_save = Speichern
 employeeDetail_back = Zur�ck
 employeeDetail_delete = L�schen
-employeeDetail_field_employeeId = Mitarbeiter ID
-employeeDetail_field_salutation = Anrede
-employeeDetail_field_firstName=Vorname
-employeeDetail_field_lastName=Nachname
-employeeDetail_field_gender=Geschlecht
-employeeDetail_field_dateOfBirth=Geburtstag
-employeeDetail_field_phone=Telefon
-employeeDetail_field_email=Emailadresse
-employeeDetail_field_department=Abteilung
-employeeDetail_field_retired=im Ruhestand
-employeeDetail_field_updateTimestamp=Letzte �nderung
 
 ## Old stuff
 

http://git-wip-us.apache.org/repos/asf/empire-db/blob/9176b225/empire-db-examples/empire-db-example-jsf2/src/main/resources/lang/messages_en.properties
----------------------------------------------------------------------
diff --git a/empire-db-examples/empire-db-example-jsf2/src/main/resources/lang/messages_en.properties b/empire-db-examples/empire-db-example-jsf2/src/main/resources/lang/messages_en.properties
index 3150db5..62fc4ed 100644
--- a/empire-db-examples/empire-db-example-jsf2/src/main/resources/lang/messages_en.properties
+++ b/empire-db-examples/empire-db-example-jsf2/src/main/resources/lang/messages_en.properties
@@ -72,6 +72,9 @@ employeeList_search = Search
 employeeList_resetSearch=Search reset
 
 employeeDetail_title = Employee Detail
+employeeDetail_tab_basic = Basic data
+employeeDetail_tab_extended = Other data
+employeeDetail_msg_extended = Please display additional information here
 employeeDetail_save = Save
 employeeDetail_back = Back
 employeeDetail_delete = Delete

http://git-wip-us.apache.org/repos/asf/empire-db/blob/9176b225/empire-db-examples/empire-db-example-jsf2/src/main/webapp/WEB-INF/faces-config.xml
----------------------------------------------------------------------
diff --git a/empire-db-examples/empire-db-example-jsf2/src/main/webapp/WEB-INF/faces-config.xml b/empire-db-examples/empire-db-example-jsf2/src/main/webapp/WEB-INF/faces-config.xml
index 7e7d8b2..e97605b 100644
--- a/empire-db-examples/empire-db-example-jsf2/src/main/webapp/WEB-INF/faces-config.xml
+++ b/empire-db-examples/empire-db-example-jsf2/src/main/webapp/WEB-INF/faces-config.xml
@@ -87,6 +87,10 @@
 		<component-class>org.apache.empire.jsf2.components.InputTag</component-class>
 	</component>
 	<component>
+		<component-type>components.LabelTag</component-type>
+		<component-class>org.apache.empire.jsf2.components.LabelTag</component-class>
+	</component>
+	<component>
 		<component-type>components.LinkTag</component-type>
 		<component-class>org.apache.empire.jsf2.components.LinkTag</component-class>
 	</component>
@@ -99,8 +103,20 @@
 		<component-class>org.apache.empire.jsf2.components.ValueTag</component-class>
 	</component>
 	<component>
-		<component-type>components.LabelTag</component-type>
-		<component-class>org.apache.empire.jsf2.components.LabelTag</component-class>
+		<component-type>components.MenuListTag</component-type>
+		<component-class>org.apache.empire.jsf2.components.MenuListTag</component-class>
+	</component>
+	<component>
+		<component-type>components.MenuItemTag</component-type>
+		<component-class>org.apache.empire.jsf2.components.MenuItemTag</component-class>
+	</component>
+	<component>
+		<component-type>components.TabViewTag</component-type>
+		<component-class>org.apache.empire.jsf2.components.TabViewTag</component-class>
+	</component>
+	<component>
+		<component-type>components.TabPageTag</component-type>
+		<component-class>org.apache.empire.jsf2.components.TabPageTag</component-class>
 	</component>
 
 </faces-config>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/empire-db/blob/9176b225/empire-db-examples/empire-db-example-jsf2/src/main/webapp/css/content.css
----------------------------------------------------------------------
diff --git a/empire-db-examples/empire-db-example-jsf2/src/main/webapp/css/content.css b/empire-db-examples/empire-db-example-jsf2/src/main/webapp/css/content.css
index 585006e..bbd719e 100644
--- a/empire-db-examples/empire-db-example-jsf2/src/main/webapp/css/content.css
+++ b/empire-db-examples/empire-db-example-jsf2/src/main/webapp/css/content.css
@@ -49,7 +49,7 @@ div.buttonBar {
 .buttonBar a,
 .buttonBar a:visited {
 	display: inline-block;
-	border: 1px gray solid;
+	border: 1px #8F99EF solid;
 	padding: 4px 12px;
 	color: black;
 	text-decoration: none;
@@ -68,7 +68,7 @@ span.searchResult {
 }
 .searchResult table {
 	width: 100%;
-	border: 1px gray solid;
+	border: 1px #8F99EF solid;
 	border-collapse: collapse;
 }
 .searchResult table tr th,
@@ -77,7 +77,7 @@ span.searchResult {
 }
 .searchResult table tr th {
 	background-color: #EFFBEF;
-	border-bottom: 1px gray solid;
+	border-bottom: 1px #8F99EF solid;
 }
 .searchResult table a.eLink,
 .searchResult table a.eLink:visited {
@@ -127,4 +127,49 @@ div.eTypeBoolTrue {
 	background-image:url('../img/boxes.gif');
 	background-repeat: no-repeat;
 	background-position: -12px 0;
+}
+div.eTabView {
+	width: 500px;
+}
+table.eTabBar {
+	width: 100%;
+	border-spacing: 0;
+	border-collapse: collapse;
+	table-layout: auto;
+	padding: 0;
+}
+table.eTabBar tr td.eTabLabel {
+	border: 1px #8F99EF solid;
+	padding: 8px;	
+	white-space: nowrap;
+}
+table.eTabBar tr td.eTabLabel.eTabActive {
+	border-bottom: 1px #F8F8F8 solid;
+	background-color: #F8F8F8;	
+}
+table.eTabBar tr td.eTabLabel.eTabDisabled {
+	color: gray;
+	font-style: italic;
+}
+table.eTabBar tr td.eTabBarEmpty {
+	width: 99%;
+	border-bottom: 1px #8F99EF solid;	
+}
+table.eTabPanel {
+	width: 100%;
+	border-spacing: 0;
+	border-collapse: collapse;
+	border: 1px #8F99EF solid;
+	border-top: 0px;	
+}
+table.eTabPanel tr td.eTabPage {
+	padding: 8px;
+	background-color: #F8F8F8;
+}
+table.eTabPanel tr td.eTabPage div.formPanel {
+	border: 0;
+}
+div.info-msg {
+	padding: 12px;
+	background-color: #FFFFCA;
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/empire-db/blob/9176b225/empire-db-examples/empire-db-example-jsf2/src/main/webapp/pages/employeeDetailPage.xhtml
----------------------------------------------------------------------
diff --git a/empire-db-examples/empire-db-example-jsf2/src/main/webapp/pages/employeeDetailPage.xhtml b/empire-db-examples/empire-db-example-jsf2/src/main/webapp/pages/employeeDetailPage.xhtml
index f6d163c..84498d9 100644
--- a/empire-db-examples/empire-db-example-jsf2/src/main/webapp/pages/employeeDetailPage.xhtml
+++ b/empire-db-examples/empire-db-example-jsf2/src/main/webapp/pages/employeeDetailPage.xhtml
@@ -34,10 +34,14 @@
 
 	<!-- content -->
 	<ui:define name="content">
-			<e:record value="#{page.employeeRecord}">
-			<!-- input form -->
-			
-			<h:form id="employeeDetail">
+
+		<h:form id="employeeDetail">
+
+		<e:tabView minHeight="400px" activeIndex="#{page.activeTab}" tabChangedListener="#{page.onTabChanged}">
+			<e:tabPage title="#{msg.employeeDetail_tab_basic}" id="tabBasic">
+
+				<e:record value="#{page.employeeRecord}">
+				<!-- input form -->
 				<sample:formPanel>
 					<tr><e:control column="#{db.EMPLOYEES.SALUTATION}" /></tr>
 					<tr><e:control column="#{db.EMPLOYEES.FIRST_NAME}" /></tr>
@@ -50,15 +54,24 @@
 					<tr><e:control column="#{db.EMPLOYEES.RETIRED}" /></tr>
 					<tr><e:control column="#{db.EMPLOYEES.UPDATE_TIMESTAMP}" format="date-format:full" readonly="true" rendered="#{page.idParam != null}" /></tr> 
 				</sample:formPanel>
-				<!-- button bar -->
-				<h:panelGroup styleClass="buttonBar" layout="block">
-					<h:commandLink value="#{msg.employeeDetail_back}" action="#{page.doCancel}" immediate="true" />
-					<h:commandLink value="#{msg.employeeDetail_delete}" action="#{page.doDelete}" immediate="true" rendered="#{page.employeeRecord.exists}" />
-					<h:commandLink value="#{msg.employeeDetail_save}" action="#{page.doSave}" />
+				</e:record>
+				
+			</e:tabPage>
+			<e:tabPage title="#{msg.employeeDetail_tab_extended}" id="tabExtended" disabled="#{not page.employeeRecord.exists}">
+				<h:panelGroup layout="block" styleClass="info-msg">
+					<h:outputText value="#{msg.employeeDetail_msg_extended}"/>
 				</h:panelGroup>
-			</h:form>
+			</e:tabPage>
+		</e:tabView>	
 		
-		</e:record>
+		<!-- button bar -->
+		<h:panelGroup styleClass="buttonBar" layout="block">
+			<h:commandLink value="#{msg.employeeDetail_back}" action="#{page.doCancel}" immediate="true" />
+			<h:commandLink value="#{msg.employeeDetail_delete}" action="#{page.doDelete}" immediate="true" rendered="#{page.employeeRecord.exists}" />
+			<h:commandLink value="#{msg.employeeDetail_save}" action="#{page.doSave}" />
+		</h:panelGroup>
+
+		</h:form>
 
 	</ui:define>
 </ui:composition>

http://git-wip-us.apache.org/repos/asf/empire-db/blob/9176b225/empire-db-examples/empire-db-example-jsf2/src/main/webapp/resources/empire/mitem.xhtml
----------------------------------------------------------------------
diff --git a/empire-db-examples/empire-db-example-jsf2/src/main/webapp/resources/empire/mitem.xhtml b/empire-db-examples/empire-db-example-jsf2/src/main/webapp/resources/empire/mitem.xhtml
new file mode 100644
index 0000000..c7db84c
--- /dev/null
+++ b/empire-db-examples/empire-db-example-jsf2/src/main/webapp/resources/empire/mitem.xhtml
@@ -0,0 +1,19 @@
+<html xmlns="http://www.w3.org/1999/xhtml"
+	xmlns:h="http://java.sun.com/jsf/html"
+	xmlns:c="http://java.sun.com/jsp/jstl/core"
+	xmlns:cc="http://java.sun.com/jsf/composite">
+
+	<!-- Interface -->
+	<cc:interface componentType="components.MenuItemTag">
+		<cc:attribute name="menuId" required="true"/>
+		<cc:attribute name="page" required="true" />
+		<cc:attribute name="idparam"/>
+		<cc:attribute name="currentOnly" type="java.lang.Boolean" default="false" />
+	</cc:interface>
+
+	<!-- Implementation -->
+	<cc:implementation>
+		<cc:insertChildren/>
+	</cc:implementation>
+	
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/empire-db/blob/9176b225/empire-db-examples/empire-db-example-jsf2/src/main/webapp/resources/empire/mlist.xhtml
----------------------------------------------------------------------
diff --git a/empire-db-examples/empire-db-example-jsf2/src/main/webapp/resources/empire/mlist.xhtml b/empire-db-examples/empire-db-example-jsf2/src/main/webapp/resources/empire/mlist.xhtml
new file mode 100644
index 0000000..9e66b02
--- /dev/null
+++ b/empire-db-examples/empire-db-example-jsf2/src/main/webapp/resources/empire/mlist.xhtml
@@ -0,0 +1,19 @@
+<html xmlns="http://www.w3.org/1999/xhtml"
+	xmlns:h="http://java.sun.com/jsf/html"
+	xmlns:c="http://java.sun.com/jsp/jstl/core"
+	xmlns:cc="http://java.sun.com/jsf/composite">
+
+	<!-- Interface -->
+	<cc:interface componentType="components.MenuListTag">
+		<cc:attribute name="currentId" />
+		<cc:attribute name="currentClass"/>
+		<cc:attribute name="expandedClass"/>
+		<cc:attribute name="disabledClass"/>
+	</cc:interface>
+
+	<!-- Implementation -->
+	<cc:implementation>
+		<cc:insertChildren/>
+	</cc:implementation>
+	
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/empire-db/blob/9176b225/empire-db-examples/empire-db-example-jsf2/src/main/webapp/resources/empire/select.xhtml
----------------------------------------------------------------------
diff --git a/empire-db-examples/empire-db-example-jsf2/src/main/webapp/resources/empire/select.xhtml b/empire-db-examples/empire-db-example-jsf2/src/main/webapp/resources/empire/select.xhtml
new file mode 100644
index 0000000..dabc56b
--- /dev/null
+++ b/empire-db-examples/empire-db-example-jsf2/src/main/webapp/resources/empire/select.xhtml
@@ -0,0 +1,21 @@
+<html xmlns="http://www.w3.org/1999/xhtml"
+	xmlns:h="http://java.sun.com/jsf/html"
+	xmlns:c="http://java.sun.com/jsp/jstl/core"
+	xmlns:cc="http://java.sun.com/jsf/composite">
+
+	<!-- Interface -->
+	<cc:interface componentType="components.SelectTag">
+		<cc:attribute name="options" required="true" />
+		<cc:attribute name="allowNull"/>	
+		<cc:attribute name="nullText"/>	
+		<cc:attribute name="disabled" />
+		<cc:attribute name="update"/>	
+		<cc:attribute name="listener" type="javax.el.MethodExpression"/>
+		<cc:clientBehavior name="change" event="change" targets="#{cc.clientId}:select" default="true"/>
+	</cc:interface>
+	
+	<!-- Implementation -->
+	<cc:implementation>
+	</cc:implementation>
+	
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/empire-db/blob/9176b225/empire-db-examples/empire-db-example-jsf2/src/main/webapp/resources/empire/tabPage.xhtml
----------------------------------------------------------------------
diff --git a/empire-db-examples/empire-db-example-jsf2/src/main/webapp/resources/empire/tabPage.xhtml b/empire-db-examples/empire-db-example-jsf2/src/main/webapp/resources/empire/tabPage.xhtml
new file mode 100644
index 0000000..dcb22f2
--- /dev/null
+++ b/empire-db-examples/empire-db-example-jsf2/src/main/webapp/resources/empire/tabPage.xhtml
@@ -0,0 +1,15 @@
+<html xmlns="http://www.w3.org/1999/xhtml"
+	xmlns:h="http://java.sun.com/jsf/html"
+	xmlns:c="http://java.sun.com/jsp/jstl/core"
+	xmlns:cc="http://java.sun.com/jsf/composite">
+
+	<!-- Interface -->
+	<cc:interface componentType="components.TabPageTag">
+	</cc:interface>
+
+	<!-- Implementation -->
+	<cc:implementation>
+		<cc:insertChildren/>
+	</cc:implementation>
+	
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/empire-db/blob/9176b225/empire-db-examples/empire-db-example-jsf2/src/main/webapp/resources/empire/tabView.xhtml
----------------------------------------------------------------------
diff --git a/empire-db-examples/empire-db-example-jsf2/src/main/webapp/resources/empire/tabView.xhtml b/empire-db-examples/empire-db-example-jsf2/src/main/webapp/resources/empire/tabView.xhtml
new file mode 100644
index 0000000..3979187
--- /dev/null
+++ b/empire-db-examples/empire-db-example-jsf2/src/main/webapp/resources/empire/tabView.xhtml
@@ -0,0 +1,17 @@
+<html xmlns="http://www.w3.org/1999/xhtml"
+	xmlns:h="http://java.sun.com/jsf/html"
+	xmlns:c="http://java.sun.com/jsp/jstl/core"
+	xmlns:cc="http://java.sun.com/jsf/composite">
+
+	<!-- Interface -->
+	<cc:interface componentType="components.TabViewTag">
+		<cc:attribute name="activeIndex" type="java.lang.Integer" />
+		<cc:attribute name="tabChangedListener" method-signature="void method(java.lang.Integer)"/>
+	</cc:interface>
+
+	<!-- Implementation -->
+	<cc:implementation>
+		<cc:insertChildren/>
+	</cc:implementation>
+	
+</html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/empire-db/blob/9176b225/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/app/WebApplication.java
----------------------------------------------------------------------
diff --git a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/app/WebApplication.java b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/app/WebApplication.java
index 0afee55..0766b50 100644
--- a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/app/WebApplication.java
+++ b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/app/WebApplication.java
@@ -51,8 +51,6 @@ import org.apache.empire.jsf2.impl.ResourceTextResolver;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-// import com.sun.faces.application.ApplicationImpl;
-
 public abstract class WebApplication
 {
     private static final Logger log                   = LoggerFactory.getLogger(WebApplication.class);
@@ -67,7 +65,7 @@ public abstract class WebApplication
     
     private FacesImplementation facesImpl			  = null;
     
-    private static WebApplication appInstance       = null;
+    private static WebApplication appInstance         = null;
     
     public static WebApplication getInstance()
     {

http://git-wip-us.apache.org/repos/asf/empire-db/blob/9176b225/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/ControlTag.java
----------------------------------------------------------------------
diff --git a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/ControlTag.java b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/ControlTag.java
index 91d82d8..3b5c4ec 100644
--- a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/ControlTag.java
+++ b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/ControlTag.java
@@ -26,6 +26,8 @@ import javax.faces.component.UIComponentBase;
 import javax.faces.component.UIInput;
 import javax.faces.component.UINamingContainer;
 import javax.faces.component.html.HtmlOutputLabel;
+import javax.faces.component.visit.VisitCallback;
+import javax.faces.component.visit.VisitContext;
 import javax.faces.context.FacesContext;
 import javax.faces.context.ResponseWriter;
 
@@ -44,7 +46,7 @@ public class ControlTag extends UIInput implements NamingContainer
     public static String DEFAULT_CONTROL_SEPARATOR_TAG = "td";
     public static String DEFAULT_LABEL_SEPARATOR_CLASS = "eCtlLabel";
     public static String DEFAULT_INPUT_SEPARATOR_CLASS = "eCtlInput";
-    
+
     public static abstract class ControlSeparatorComponent extends javax.faces.component.UIComponentBase
     {
         private ControlTag control = null;
@@ -60,49 +62,64 @@ public class ControlTag extends UIInput implements NamingContainer
         @Override
         public String getFamily()
         {
-            return UINamingContainer.COMPONENT_FAMILY; 
+            return UINamingContainer.COMPONENT_FAMILY;
         }
         
+        /*
+        @Override
+        public String getClientId(FacesContext context)
+        {
+            String clientId = super.getClientId(context);
+            log.info("ControlSeparatorComponent-ID is {}", clientId);
+            // default behavior
+            return clientId;
+        }
+        */
+
         @Override
         public void encodeBegin(FacesContext context)
             throws IOException
         {
             super.encodeBegin(context);
-            
+
             UIComponent parent = getParent();
             if (!(parent instanceof ControlTag))
                 parent = parent.getParent();
             if (!(parent instanceof ControlTag))
-            {   log.error("Invalid parent component for "+getClass().getName());
+            {   log.error("Invalid parent component for " + getClass().getName());
                 return;
             }
-            
-            control = (ControlTag)parent;
+
+            this.control = (ControlTag) parent;
         }
-        
-        protected abstract void writeAttributes(ResponseWriter writer, TagEncodingHelper helper, String tagName) throws IOException;
-        
+
+        protected abstract void writeAttributes(ResponseWriter writer, TagEncodingHelper helper, String tagName)
+            throws IOException;
+
         @Override
         public boolean getRendersChildren()
         {
             return true;
         }
-        
+
         @Override
         public void encodeChildren(FacesContext context)
             throws IOException
         {
-            if (control!=null)
-            {   // write end tag
-                TagEncodingHelper helper = control.helper;
+            if (this.control != null)
+            { // write end tag
+                TagEncodingHelper helper = this.control.helper;
                 String tagName = helper.getTagAttributeString("tag", "td");
-                
+
                 // render components
                 ResponseWriter writer = context.getResponseWriter();
                 writer.startElement(tagName, this);
                 writeAttributes(writer, helper, tagName);
                 // write children
-                super.encodeChildren(context);
+                if (control.helper.isVisible())
+                    super.encodeChildren(context);
+                else
+                    log.debug("Field {} is not visible.", helper.getColumn().getName());
                 // end
                 writer.endElement(tagName);
             }
@@ -112,10 +129,10 @@ public class ControlTag extends UIInput implements NamingContainer
     public static class LabelSeparatorComponent extends ControlSeparatorComponent
     {
         @Override
-        protected void writeAttributes(ResponseWriter writer, TagEncodingHelper helper, String tagName) 
+        protected void writeAttributes(ResponseWriter writer, TagEncodingHelper helper, String tagName)
             throws IOException
         {
-            String styleClass = helper.getTagAttributeString("labelClass", DEFAULT_LABEL_SEPARATOR_CLASS);
+            String styleClass = helper.getTagAttributeString("labelClass", ControlTag.DEFAULT_LABEL_SEPARATOR_CLASS);
             if (StringUtils.isNotEmpty(styleClass))
                 writer.writeAttribute("class", styleClass, null);
         }
@@ -124,18 +141,21 @@ public class ControlTag extends UIInput implements NamingContainer
     public static class InputSeparatorComponent extends ControlSeparatorComponent
     {
         @Override
-        protected void writeAttributes(ResponseWriter writer, TagEncodingHelper helper, String tagName) 
+        protected void writeAttributes(ResponseWriter writer, TagEncodingHelper helper, String tagName)
             throws IOException
         {
-            String styleClass = helper.getTagAttributeString("inputClass", DEFAULT_INPUT_SEPARATOR_CLASS);
+            String styleClass = helper.getTagAttributeString("inputClass", ControlTag.DEFAULT_INPUT_SEPARATOR_CLASS);
+            // styleClass
             if (StringUtils.isNotEmpty(styleClass))
                 writer.writeAttribute("class", styleClass, null);
+            // colspan
             String colSpan = helper.getTagAttributeString("colspan");
             if (StringUtils.isNotEmpty(colSpan) && tagName.equalsIgnoreCase("td"))
                 writer.writeAttribute("colspan", colSpan, null);
         }
+        
     }
-    
+
     public static class ValueOutputComponent extends javax.faces.component.UIComponentBase
     {
         private final String tagName = "span";
@@ -151,63 +171,64 @@ public class ControlTag extends UIInput implements NamingContainer
         @Override
         public String getFamily()
         {
-            return UINamingContainer.COMPONENT_FAMILY; 
+            return UINamingContainer.COMPONENT_FAMILY;
         }
-        
+
         @Override
         public void encodeBegin(FacesContext context)
             throws IOException
         {
             super.encodeBegin(context);
-            
+
             UIComponent parent = getParent();
             if (!(parent instanceof ControlTag))
                 parent = parent.getParent();
             if (!(parent instanceof ControlTag))
                 parent = parent.getParent();
             if (!(parent instanceof ControlTag))
-            {   log.error("Invalid parent component for "+getClass().getName());
+            {   log.error("Invalid parent component for " + getClass().getName());
                 return;
             }
-            
-            ControlTag controlTag = (ControlTag)parent;
+
+            ControlTag controlTag = (ControlTag) parent;
             InputControl control = controlTag.control;
             InputControl.ValueInfo valInfo = controlTag.inpInfo;
 
             TagEncodingHelper helper = controlTag.helper;
-            if (control==null)
+            if (control == null)
                 control = helper.getInputControl(); // Oops, should not come here 
-            if (valInfo==null)
+            if (valInfo == null)
                 valInfo = helper.getValueInfo(context); // Oops, should not come here 
-            
+
             String styleClass = helper.getTagStyleClass("eInpDis");
-            String tooltip    = helper.getValueTooltip(helper.getTagAttributeString("title"));
-            
+            String tooltip = helper.getValueTooltip(helper.getTagAttributeString("title"));
+
             // render components
             ResponseWriter writer = context.getResponseWriter();
-            writer.startElement(tagName, this);
+            writer.startElement(this.tagName, this);
             if (StringUtils.isNotEmpty(styleClass))
                 writer.writeAttribute("class", styleClass, null);
             if (StringUtils.isNotEmpty(tooltip))
                 writer.writeAttribute("title", tooltip, null);
             // render Value
             control.renderValue(valInfo, writer);
-            writer.endElement(tagName);
+            writer.endElement(this.tagName);
         }
     }
-    
+
     // Logger
-    private static final Logger  log          = LoggerFactory.getLogger(ControlTag.class);
+    private static final Logger       log                = LoggerFactory.getLogger(ControlTag.class);
 
-    private static final String readOnlyState  = "readOnlyState";
-    
-    private static final boolean encodeLabel = true;
+    private static final String       readOnlyState      = "readOnlyState";
+
+    private static final boolean      encodeLabel        = true;
 
-    protected final TagEncodingHelper helper = new TagEncodingHelper(this, "eInput");
+    protected final TagEncodingHelper helper             = new TagEncodingHelper(this, "eInput");
 
-    protected InputControl control = null;
-    protected InputControl.InputInfo inpInfo = null;
-    protected boolean hasRequiredFlagSet = false;
+    protected InputControl            control            = null;
+    protected InputControl.InputInfo  inpInfo            = null;
+    protected boolean                 hasRequiredFlagSet = false;
+    private   boolean                 creatingComponents = false;
 
     public ControlTag()
     {
@@ -224,22 +245,51 @@ public class ControlTag extends UIInput implements NamingContainer
     {
         // getStateHelper().put(inpControlPropName, control);
         // getStateHelper().put(inputInfoPropName, inpInfo);
-        getStateHelper().put(readOnlyState, (inpInfo==null));
+        getStateHelper().put(ControlTag.readOnlyState, (this.inpInfo == null));
     }
 
     private boolean initState(FacesContext context)
     {
-        // Check visibility
-        if (helper.isVisible()==false)
-            return false; // not visible
         // Check read-Only
-        Boolean ros = (Boolean)getStateHelper().get(readOnlyState);
-        if (ros!=null && ros.booleanValue())
+        Boolean ros = (Boolean) getStateHelper().get(ControlTag.readOnlyState);
+        if (ros != null && ros.booleanValue())
             return false;
+        // Must have children        
+        if (getChildCount() == 0)
+        {   log.warn("InputTag has no children! Unable to init Input state for id={}", getClientId());
+            log.warn("Problem might be related to Mojarra's state context saving for dynamic components (affects all versions > 2.1.6). See com.sun.faces.context.StateContext.java:AddRemoveListener");
+            return false;
+        }
         // control = ;
-        control = helper.getInputControl();
-        inpInfo = helper.getInputInfo(context);
-        return (control!=null && inpInfo!=null);
+        this.control = helper.getInputControl();
+        this.inpInfo = helper.getInputInfo(context);
+        return (this.control != null && this.inpInfo != null);
+    }
+
+    /**
+     * remember original clientId
+     * necessary only inside UIData
+     */
+    private String treeClientId = null;
+    
+    @Override
+    public boolean visitTree(VisitContext visitContext, VisitCallback callback) 
+    {
+        FacesContext context = visitContext.getFacesContext();
+        treeClientId = this.getClientId(context);
+        return super.visitTree(visitContext, callback);
+    }
+
+    @Override
+    public String getClientId(FacesContext context)
+    {
+        // Check if dynamic components are being created
+        if (this.treeClientId!=null && (this.creatingComponents || this.control!=null && this.control.isCreatingComponents()))
+        {   // return the original tree client id
+            return treeClientId; 
+        }
+        // default behavior
+        return super.getClientId(context);
     }
 
     @Override
@@ -249,79 +299,78 @@ public class ControlTag extends UIInput implements NamingContainer
         // add label and input components when the view is loaded for the first time
         super.encodeBegin(context);
 
-        // Check visiblity
-        if (helper.isVisible()==false)
-        {   setRendered(false);
-            return; // not visible
-        }
-        
         // init
         helper.encodeBegin();
-        control = helper.getInputControl();
-        
+        this.control = helper.getInputControl();
+
         boolean isCustomInput = isCustomInput();
-        
+
         // create children
-        if (encodeLabel)
+        if (ControlTag.encodeLabel)
         {   // Create Label Separator Tag
-            ControlSeparatorComponent labelSepTag = null; 
+            ControlSeparatorComponent labelSepTag = null;
             if (getChildCount() > 0)
                 labelSepTag = (ControlSeparatorComponent) getChildren().get(0);
             if (labelSepTag == null)
-            {   labelSepTag = new LabelSeparatorComponent();
-                getChildren().add(labelSepTag);
+            {   try {
+                    creatingComponents = true;
+                    labelSepTag = new LabelSeparatorComponent();
+                    getChildren().add(labelSepTag);
+                    helper.resetComponentId(labelSepTag);
+                } finally {
+                    creatingComponents = false;
+                }
             }
             labelSepTag.setRendered(true);
             encodeLabel(context, labelSepTag);
             if (isCustomInput)
-            {   // don't render twice!
+            { // don't render twice!
                 labelSepTag.setRendered(false);
-            }    
-        }   
+            }
+        }
 
         if (!isCustomInput)
         {   // Create Input Separator Tag
-            ControlSeparatorComponent inputSepTag = null; 
+            ControlSeparatorComponent inputSepTag = null;
             if (getChildCount() > 1)
                 inputSepTag = (ControlSeparatorComponent) getChildren().get(1);
             if (inputSepTag == null)
-            {   inputSepTag = new InputSeparatorComponent();
-                getChildren().add(inputSepTag);
+            {   try {
+                    creatingComponents = true;
+                    inputSepTag = new InputSeparatorComponent();
+                    getChildren().add(inputSepTag);
+                    helper.resetComponentId(inputSepTag);
+                } finally {
+                    creatingComponents = false;
+                }
             }
             encodeInput(context, inputSepTag);
         }
-        
-        /*
-        ResponseWriter writer = context.getResponseWriter();
-        writer.startElement("td", this);
-        writer.write("hello world!");
-        writer.endElement("td");
-
-        if (!isCustomInput())
-        {
-            writer.startElement("td", this);
-            encodeInput(context, this);
-            writer.endElement("td");
-        }
-        */
-        
+        // done
         saveState();
     }
-    
+
     @Override
     public boolean getRendersChildren()
     {
         return true;
     }
-    
-    @Override 
-    public void encodeChildren(FacesContext context) 
-        throws IOException 
+
+    @Override
+    public void encodeChildren(FacesContext context)
+        throws IOException
     {
-        if (isCustomInput())
+        super.encodeChildren(context);
+    }
+
+    @Override
+    public void encodeEnd(FacesContext context)
+        throws IOException
+    {
+        if (isRendered() && isCustomInput()) // MyFaces Patch!
         {
-            String tagName  = helper.getTagAttributeString("tag", DEFAULT_CONTROL_SEPARATOR_TAG);
-            String inpClass = helper.getTagAttributeString("inputClass", DEFAULT_INPUT_SEPARATOR_CLASS);
+            String tagName  = helper.getTagAttributeString("tag", ControlTag.DEFAULT_CONTROL_SEPARATOR_TAG);
+            String inpClass = helper.getTagAttributeString("inputClass", ControlTag.DEFAULT_INPUT_SEPARATOR_CLASS);
             String colSpan  = helper.getTagAttributeString("colspan");
 
             ResponseWriter writer = context.getResponseWriter();
@@ -331,27 +380,66 @@ public class ControlTag extends UIInput implements NamingContainer
             if (StringUtils.isNotEmpty(colSpan) && tagName.equalsIgnoreCase("td"))
                 writer.writeAttribute("colspan", colSpan, null);
             // encode children
-            super.encodeChildren(context);
+            super.encodeEnd(context);
             // end of element
             writer.endElement(tagName);
-        }    
+        }
+        else
+        { // default
+            super.encodeEnd(context);
+        }
+    }
+    
+    @Override
+    public void setId(String id) 
+    {
+        super.setId(id);
+        // reset record
+        helper.setRecord(null);
     }
 
     @Override
-    public void encodeEnd(FacesContext context)
-        throws IOException 
+    public void processDecodes(FacesContext context) 
     {
-        super.encodeEnd(context);
+        if (helper.isInsideUIData())
+        {   // Check input controls
+            if (getChildCount()>1 && (getChildren().get(1) instanceof InputSeparatorComponent))
+            {   // Make sure all inputs are rendered
+                boolean hasChanged = false;
+                boolean readOnly = helper.isRecordReadOnly();
+                InputSeparatorComponent parent = (InputSeparatorComponent)getChildren().get(1);
+                // set rendered of children
+                for (UIComponent child : parent.getChildren())
+                {   // set rendered 
+                    boolean rendered = (child instanceof ValueOutputComponent) ? readOnly : !readOnly;
+                    if (child.isRendered()!=rendered)
+                    {
+                        child.setRendered(rendered);
+                        hasChanged = true;
+                    }    
+                }
+                // give control chance to update
+                if (hasChanged && log.isDebugEnabled())
+                    log.debug("Changing UIInput readOnly state for {} to {}", helper.getColumnName(), readOnly);
+                if (this.control==null)
+                    this.control = helper.getInputControl();
+                if (this.inpInfo==null)
+                    this.inpInfo = helper.getInputInfo(context);
+                this.control.updateInputState(parent, inpInfo, context);
+            }
+        }
+        // default
+        super.processDecodes(context);
     }
 
     @Override
-    public void setRequired(boolean required) 
+    public void setRequired(boolean required)
     {
         super.setRequired(required);
         // flag has been set
-        hasRequiredFlagSet = true;
+        this.hasRequiredFlagSet = true;
     }
-    
+
     public boolean isCustomInput()
     {
         Object custom = getAttributes().get("custom");
@@ -359,62 +447,71 @@ public class ControlTag extends UIInput implements NamingContainer
             return ObjectUtils.getBoolean(custom);
         return false;
     }
-    
+
     private void encodeLabel(FacesContext context, UIComponentBase parent)
         throws IOException
     {
         // render components
-        HtmlOutputLabel labelComponent = null;
-        if (parent.getChildCount() > 0)
-        {
-            labelComponent = (HtmlOutputLabel) parent.getChildren().get(0);
-            // update
-            helper.updateLabelComponent(context, labelComponent, null);
-        }
-        if (labelComponent == null)
-        {
-            String forInput = isCustomInput() ? helper.getTagAttributeString("for") : "*";
-            // createLabelComponent 
-            labelComponent = helper.createLabelComponent(context, forInput, "eLabel", null, true);
-            parent.getChildren().add(0, labelComponent);
+        try {
+            creatingComponents = true;
+            HtmlOutputLabel labelComponent = null;
+            if (parent.getChildCount() > 0)
+            {
+                labelComponent = (HtmlOutputLabel) parent.getChildren().get(0);
+                // update
+                helper.updateLabelComponent(context, labelComponent, null);
+            }
+            if (labelComponent == null)
+            {
+                String forInput = isCustomInput() ? helper.getTagAttributeString("for") : "*";
+                // createLabelComponent 
+                labelComponent = helper.createLabelComponent(context, forInput, "eLabel", null, true);
+                parent.getChildren().add(0, labelComponent);
+                helper.resetComponentId(labelComponent);
+            }
+        } finally {
+            creatingComponents = false;
         }
         // render components
         parent.encodeAll(context);
     }
-    
+
     private void encodeInput(FacesContext context, UIComponentBase parent)
         throws IOException
     {
         // render components
-        if (this.helper.isRecordReadOnly()) //  && allowValueComponent(parent))
-        {
-            UIComponent valueComp = (parent.getChildCount()>0 ? parent.getChildren().get(0) : null);
-            if (valueComp != null && !(valueComp instanceof ValueOutputComponent))
-            {	// remove InputComponent
-                parent.getChildren().clear();
-                valueComp = null;
-            }
+        try {
+            creatingComponents = true;
+            // check children
+            int count = parent.getChildCount();
+            boolean resetChildId = (count==0);
+            // continue
+            this.inpInfo = helper.getInputInfo(context);
+            // set required
+            if (this.hasRequiredFlagSet==false)
+                super.setRequired(helper.isValueRequired());
+	        // create Input Controls
+            // boolean recordReadOnly = helper.isRecordReadOnly();
+            control.renderInput(parent, inpInfo, context, false);
+            // create Value Component
+            UIComponent valueComp = (count>0 ? parent.getChildren().get(count-1) : null);
             if (valueComp == null)
-            {
+            {   // create ValueOutputComponent
                 valueComp = new ValueOutputComponent();
                 parent.getChildren().add(valueComp);
             }
-        }
-        else
-        {	// check for ValueOutputComponent	
-            UIComponent valueComp = (parent.getChildCount()>0 ? parent.getChildren().get(0) : null);
-            if (valueComp instanceof ValueOutputComponent)
-            {	// remove ValueOutputComponent
-            	parent.getChildren().clear();
+            // Walk through the list of controls
+            boolean readOnly = helper.isRecordReadOnly();
+            for (UIComponent child : parent.getChildren())
+            {   // reset child-id
+                if (resetChildId)
+                    helper.resetComponentId(child);
+                // set rendered 
+                boolean rendered = (child instanceof ValueOutputComponent) ? readOnly : !readOnly;
+                child.setRendered(rendered);
             }
-            // continue
-            inpInfo = helper.getInputInfo(context);
-            // set required
-            if (hasRequiredFlagSet==false)
-                super.setRequired(helper.isValueRequired());
-            // render input
-            control.renderInput(parent, inpInfo, context, false);
-            
+        } finally {
+            creatingComponents = false;
         }
         // render components
         parent.encodeAll(context);
@@ -424,58 +521,58 @@ public class ControlTag extends UIInput implements NamingContainer
     public Object getValue()
     {
         // check for record
-        if (helper.getRecord()!=null)
+        if (helper.getRecord() != null)
             return helper.getDataValue(true);
         // default
         Object value = super.getValue();
-        return value; 
+        return value;
     }
-
+    
     @Override
     public Object getSubmittedValue()
-    {   // Check state
-        if (control==null || inpInfo==null || helper.isReadOnly())
+    { // Check state
+        if (this.control == null || this.inpInfo == null || helper.isReadOnly())
             return null;
         // Get Input Tag
-        if (getChildCount()<=1)
+        if (getChildCount() <= 1)
             return null;
         // get Input Value
-        ControlSeparatorComponent inputSepTag = (ControlSeparatorComponent) getChildren().get(1); 
-        return control.getInputValue(inputSepTag, inpInfo, true);
+        ControlSeparatorComponent inputSepTag = (ControlSeparatorComponent) getChildren().get(1);
+        return this.control.getInputValue(inputSepTag, this.inpInfo, true);
     }
 
     @Override
     public void validateValue(FacesContext context, Object value)
-    {   // Check state
-        if (inpInfo==null || !isValid())
+    { // Check state
+        if (this.inpInfo == null || !isValid())
             return;
         // Skip Null values on partial submit
-        if (isEmpty(value) && isPartialSubmit(context)) //  && helper.isValueRequired()
-        {   // Value is null
-            log.debug("Skipping validation for {} due to Null value.", inpInfo.getColumn().getName());
+        if (UIInput.isEmpty(value) && isPartialSubmit(context)) //  && helper.isValueRequired()
+        { // Value is null
+            log.debug("Skipping validation for {} due to Null value.", this.inpInfo.getColumn().getName());
             return;
         }
         // Validate value
-        inpInfo.validate(value);
+        this.inpInfo.validate(value);
         setValid(true);
         // don't call base class!
         // super.validateValue(context, value);
-    }    
-    
+    }
+
     @Override
     public void validate(FacesContext context)
     {
-        if (initState(context)==false)
+        if (initState(context) == false)
             return;
         // get submitted value and validate
         if (log.isDebugEnabled())
-            log.debug("Validating input for {}.", inpInfo.getColumn().getName());
+            log.debug("Validating input for {}.", this.inpInfo.getColumn().getName());
         // Validate value
-        try {
-            // Will internally call getSubmittedValue() and validateValue() 
+        try
+        {   // Will internally call getSubmittedValue() and validateValue() 
             super.validate(context);
-            
-        } catch(Exception e) {
+
+        } catch (Exception e) {
             // Value is not valid
             if (!(e instanceof EmpireException))
                 e = new FieldIllegalValueException(helper.getColumn(), "", e);
@@ -488,39 +585,44 @@ public class ControlTag extends UIInput implements NamingContainer
     @Override
     public void updateModel(FacesContext context)
     {
-        if (initState(context)==false)
+        if (initState(context) == false)
             return;
         // No Action
         if (!isValid() || !isLocalValueSet())
-            return; 
+            return;
         // check required?
         Object value = getLocalValue();
         // check required
-        if (isEmpty(value) && isPartialSubmit(context) && !helper.isTempoaryNullable())
-        {   // Value is null, but required
-            log.debug("Skipping model update for {} due to Null value.", inpInfo.getColumn().getName());
+        if (UIInput.isEmpty(value) && isPartialSubmit(context) && !helper.isTempoaryNullable())
+        { // Value is null, but required
+            log.debug("Skipping model update for {} due to Null value.", this.inpInfo.getColumn().getName());
             return;
         }
         // super.updateModel(context);
-        log.debug("Updating model input for {}.", inpInfo.getColumn().getName());
-        inpInfo.setValue(value);
+        log.debug("Updating model input for {}.", this.inpInfo.getColumn().getName());
+        this.inpInfo.setValue(value);
         setValue(null);
         setLocalValueSet(false);
         // Post update
-        ControlSeparatorComponent inputSepTag = (ControlSeparatorComponent) getChildren().get(1); 
-        control.postUpdateModel(inputSepTag, inpInfo, context);
+        ControlSeparatorComponent inputSepTag = (ControlSeparatorComponent) getChildren().get(1);
+        this.control.postUpdateModel(inputSepTag, this.inpInfo, context);
     }
-    
+
+    public InputControl getInputControl()
+    {
+        return this.control;
+    }
+
     public Column getInputColumn()
     {
         return helper.getColumn();
     }
-    
+
     public boolean isInputReadOnly()
     {
         return helper.isRecordReadOnly();
     }
-    
+
     public boolean isInputRequired()
     {
         return helper.isValueRequired();
@@ -529,20 +631,10 @@ public class ControlTag extends UIInput implements NamingContainer
     private boolean isPartialSubmit(FacesContext context)
     {
         // Check Required Flag
-        if (hasRequiredFlagSet && !isRequired())
+        if (this.hasRequiredFlagSet && !isRequired())
             return true;
         // partial  
         return helper.isPartialSubmit(context);
     }
-
-    /**
-     * Check the parent allows the creation of a if the ValueOutputComponent.
-     * This method should never return false. If it does, the method "helper.isRecordReadOnly()" does not return the same value for subsequent calls as when the component was first encoded.
-     * @param parent the parent tag
-     * @return true on success or false if the parent's first child is not a instance of ValueOutputComponent
-    private boolean allowValueComponent(UIComponentBase parent)
-    {
-        return (parent.getChildCount()>0 ? (parent.getChildren().get(0) instanceof ValueOutputComponent) : true); 
-    }
-     */
+    
 }

http://git-wip-us.apache.org/repos/asf/empire-db/blob/9176b225/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/InputTag.java
----------------------------------------------------------------------
diff --git a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/InputTag.java b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/InputTag.java
index 4bc5f9a..ac6270d 100644
--- a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/InputTag.java
+++ b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/InputTag.java
@@ -23,6 +23,8 @@ import java.util.Map;
 
 import javax.faces.component.NamingContainer;
 import javax.faces.component.UIInput;
+import javax.faces.component.visit.VisitCallback;
+import javax.faces.component.visit.VisitContext;
 import javax.faces.context.FacesContext;
 import javax.faces.context.ResponseWriter;
 
@@ -37,23 +39,23 @@ import org.slf4j.LoggerFactory;
 public class InputTag extends UIInput implements NamingContainer
 {
     // Logger
-    private static final Logger log          = LoggerFactory.getLogger(InputTag.class);
-    
+    private static final Logger     log                = LoggerFactory.getLogger(InputTag.class);
+
     // private static final String inpControlPropName = InputControl.class.getSimpleName();
     // private static final String inputInfoPropName = InputControl.InputInfo.class.getSimpleName();
-    private static final String readOnlyState  = "readOnlyState";
+    private static final String     readOnlyState      = "readOnlyState";
 
-    protected final TagEncodingHelper helper = new TagEncodingHelper(this, "eInput");
+    private final TagEncodingHelper helper             = new TagEncodingHelper(this, "eInput");
 
-    private InputControl control = null;
-    private InputControl.InputInfo inpInfo = null;
-    protected boolean hasRequiredFlagSet = false;
+    private InputControl            control            = null;
+    private InputControl.InputInfo  inpInfo            = null;
+    protected boolean               hasRequiredFlagSet = false;
 
     /*
     private static int itemIdSeq = 0;
     private final int itemId;
     */
-    
+
     public InputTag()
     {
         super();
@@ -62,7 +64,7 @@ public class InputTag extends UIInput implements NamingContainer
         itemId = ++itemIdSeq;
         if (log.isDebugEnabled())
             log.debug("InputTag {} created", itemId);
-        */    
+        */
     }
 
     @Override
@@ -75,28 +77,54 @@ public class InputTag extends UIInput implements NamingContainer
     {
         // getStateHelper().put(inpControlPropName, control);
         // getStateHelper().put(inputInfoPropName, inpInfo);
-        getStateHelper().put(readOnlyState, (inpInfo==null));
+        getStateHelper().put(readOnlyState, (inpInfo == null));
     }
 
     private boolean initState(FacesContext context)
     {
         // Check visibility
-        if (helper.isVisible()==false)
+        if (helper.isVisible() == false)
             return false; // not visible
         // Read only State
-        Boolean ros = (Boolean)getStateHelper().get(readOnlyState);
-        if (ros!=null && ros.booleanValue())
+        Boolean ros = (Boolean) getStateHelper().get(readOnlyState);
+        if (ros != null && ros.booleanValue())
             return false;
         // Must have children
-        if (getChildCount()==0)
-        {   log.warn("InputTag has no children! Unable to init Input state.");
-            log.warn("Problem might be related to Mojarra 2.1.7 to 2.1.11 (and possibly later) - please use Mojarra 2.1.6!");
+        if (getChildCount() == 0)
+        {   log.warn("InputTag has no children! Unable to init Input state for id={}", getClientId());
+            log.warn("Problem might be related to Mojarra's state context saving for dynamic components (affects all versions > 2.1.6). See com.sun.faces.context.StateContext.java:AddRemoveListener");
             return false;
         }
         // Init Control and inputInfo;
         control = helper.getInputControl();
         inpInfo = helper.getInputInfo(context);
-        return (control!=null && inpInfo!=null);
+        return (control != null && inpInfo != null);
+    }
+    
+    /**
+     * remember original clientId
+     * necessary only inside UIData
+     */
+    private String treeClientId = null;
+    
+    @Override
+    public boolean visitTree(VisitContext visitContext, VisitCallback callback) 
+    {
+        FacesContext context = visitContext.getFacesContext();
+        treeClientId = getClientId(context);
+        return super.visitTree(visitContext, callback);
+    }
+
+    @Override
+    public String getClientId(FacesContext context)
+    {
+        // Check if dynamic components are being created
+        if (this.treeClientId!=null && control!=null && control.isCreatingComponents())
+        {   // return the original tree client id
+            return treeClientId; 
+        }
+        // default behavior
+        return super.getClientId(context);
     }
 
     @Override
@@ -107,15 +135,15 @@ public class InputTag extends UIInput implements NamingContainer
         super.encodeBegin(context);
 
         // Check visiblity
-        if (helper.isVisible()==false)
+        if (helper.isVisible() == false)
         {   setRendered(false);
             return; // not visible
         }
-        
+
         // init
         helper.encodeBegin();
         control = helper.getInputControl();
-        
+
         // render components
         if (helper.isRecordReadOnly())
         {
@@ -130,16 +158,46 @@ public class InputTag extends UIInput implements NamingContainer
         {
             inpInfo = helper.getInputInfo(context);
             // set required
-            if (hasRequiredFlagSet==false)
+            if (hasRequiredFlagSet == false)
                 super.setRequired(helper.isValueRequired());
             // render input
             control.renderInput(this, inpInfo, context, true);
         }
         saveState();
     }
+    
+    @Override
+    public void setId(String id) 
+    {
+        super.setId(id);
+        // reset record
+        helper.setRecord(null);
+    }
+
+    /*
+    @Override
+    public void processDecodes(FacesContext context) 
+    {
+        if (helper.isInsideUIData())
+        {   // Check input controls
+            if (getChildCount()>0)
+            {   // Change readOnly and disabled too
+                boolean readOnly = helper.isRecordReadOnly();
+                log.info("Changing UIInput readOnly state for {} to {}", helper.getColumnName(), readOnly);
+                if (control==null)
+                    control = helper.getInputControl();
+                if (inpInfo==null)
+                    inpInfo = helper.getInputInfo(context);
+                control.updateInputState(this, inpInfo, context);
+            }
+        }
+        // default
+        super.processDecodes(context);
+    }
+    */
 
     @Override
-    public void setRequired(boolean required) 
+    public void setRequired(boolean required)
     {
         super.setRequired(required);
         // flag has been set
@@ -150,17 +208,17 @@ public class InputTag extends UIInput implements NamingContainer
     public Object getValue()
     {
         // check for record
-        if (helper.getRecord()!=null)
+        if (helper.getRecord() != null)
             return helper.getDataValue(true);
         // default
-        Object value = super.getValue(); 
-        return value; 
+        Object value = super.getValue();
+        return value;
     }
 
     @Override
     public Object getSubmittedValue()
-    {   // Check state
-        if (control==null || inpInfo==null || helper.isReadOnly())
+    { // Check state
+        if (control == null || inpInfo == null || helper.isReadOnly())
             return null;
         // get Input Value
         return control.getInputValue(this, inpInfo, true);
@@ -168,12 +226,12 @@ public class InputTag extends UIInput implements NamingContainer
 
     @Override
     public void validateValue(FacesContext context, Object value)
-    {   // Check state
-        if (inpInfo==null)
+    { // Check state
+        if (inpInfo == null)
             return;
         // Skip Null values if not required
-        if (isEmpty(value) && isPartialSubmit(context)) //  && helper.isValueRequired()
-        {   // Value is null
+        if (UIInput.isEmpty(value) && isPartialSubmit(context)) //  && helper.isValueRequired()
+        { // Value is null
             log.debug("Skipping validation for {} due to Null value.", inpInfo.getColumn().getName());
             return;
         }
@@ -182,23 +240,23 @@ public class InputTag extends UIInput implements NamingContainer
         setValid(true);
         // don't call base class!
         // super.validateValue(context, value);
-    }    
-    
+    }
+
     @Override
     public void validate(FacesContext context)
     {
-        if (initState(context)==false)
+        if (initState(context) == false)
             return;
         // get submitted value and validate
         if (log.isDebugEnabled())
             log.debug("Validating input for {}.", inpInfo.getColumn().getName());
-        
+
         // Validate value
-        try {
-            // Will internally call getSubmittedValue() and validateValue() 
+        try
+        {   // Will internally call getSubmittedValue() and validateValue() 
             super.validate(context);
             
-        } catch(Exception e) {
+        } catch (Exception e) {
             // Value is not valid
             if (!(e instanceof EmpireException))
                 e = new FieldIllegalValueException(helper.getColumn(), "", e);
@@ -211,15 +269,15 @@ public class InputTag extends UIInput implements NamingContainer
     @Override
     public void updateModel(FacesContext context)
     {
-        if (initState(context)==false)
+        if (initState(context) == false)
             return;
         // No Action
         if (!isValid() || !isLocalValueSet())
-            return; 
+            return;
         // check required
         Object value = getLocalValue();
-        if (isEmpty(value) && isPartialSubmit(context) && !helper.isTempoaryNullable())
-        {   // Value is null, but required
+        if (UIInput.isEmpty(value) && isPartialSubmit(context) && !helper.isTempoaryNullable())
+        { // Value is null, but required
             log.debug("Skipping model update for {} due to Null value.", inpInfo.getColumn().getName());
             return;
         }
@@ -231,17 +289,17 @@ public class InputTag extends UIInput implements NamingContainer
         // Post update
         control.postUpdateModel(this, inpInfo, context);
     }
-    
+
     public Column getInputColumn()
     {
         return helper.getColumn();
     }
-    
+
     public boolean isInputReadOnly()
     {
         return helper.isRecordReadOnly();
     }
-    
+
     public boolean isInputRequired()
     {
         return helper.isValueRequired();
@@ -258,6 +316,7 @@ public class InputTag extends UIInput implements NamingContainer
 
     /**
      * write value element
+     * 
      * @param vi
      * @param writer
      * @return

http://git-wip-us.apache.org/repos/asf/empire-db/blob/9176b225/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/LabelTag.java
----------------------------------------------------------------------
diff --git a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/LabelTag.java b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/LabelTag.java
index f276b78..6e93ca3 100644
--- a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/LabelTag.java
+++ b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/LabelTag.java
@@ -20,8 +20,11 @@ package org.apache.empire.jsf2.components;
 
 import java.io.IOException;
 
+import javax.faces.component.NamingContainer;
 import javax.faces.component.UIOutput;
 import javax.faces.component.html.HtmlOutputLabel;
+import javax.faces.component.visit.VisitCallback;
+import javax.faces.component.visit.VisitContext;
 import javax.faces.context.FacesContext;
 
 import org.apache.empire.commons.ObjectUtils;
@@ -30,13 +33,15 @@ import org.apache.empire.jsf2.utils.TagEncodingHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class LabelTag extends UIOutput // implements NamingContainer
+public class LabelTag extends UIOutput implements NamingContainer
 {
     // Logger
     private static final Logger log = LoggerFactory.getLogger(LabelTag.class);
     
-    protected final TagEncodingHelper helper = new TagEncodingHelper(this, "eLabel");
+    private final TagEncodingHelper helper = new TagEncodingHelper(this, "eLabel");
 
+    private boolean creatingComponents = false;
+    
     public LabelTag()
     {
         log.trace("component LabelTag created");
@@ -47,6 +52,32 @@ public class LabelTag extends UIOutput // implements NamingContainer
     {
         return "javax.faces.NamingContainer";
     }
+    
+    /**
+     * remember original clientId
+     * necessary only inside UIData
+     */
+    private String treeClientId = null;
+    
+    @Override
+    public boolean visitTree(VisitContext visitContext, VisitCallback callback) 
+    {
+        FacesContext context = visitContext.getFacesContext();
+        treeClientId = this.getClientId(context);
+        return super.visitTree(visitContext, callback);
+    }
+
+    @Override
+    public String getClientId(FacesContext context)
+    {
+        // Check if dynamic components are being created
+        if (this.treeClientId!=null && this.creatingComponents)
+        {   // return the original tree client id
+            return treeClientId; 
+        }
+        // default behavior
+        return super.getClientId(context);
+    }
 
     @Override
     public void encodeBegin(FacesContext context)
@@ -65,14 +96,19 @@ public class LabelTag extends UIOutput // implements NamingContainer
             helper.updateLabelComponent(context, labelComponent, forInput);
         }
         if (labelComponent == null)
-        {
-            String forInput   = helper.getTagAttributeString("for");
-            String styleClass = helper.getTagStyleClass(DataType.UNKNOWN, null);
-            String style      = helper.getTagAttributeString("style");
-            // createLabelComponent 
-            labelComponent = helper.createLabelComponent(context, forInput, styleClass, style, getColon());
-            this.getChildren().add(labelComponent);
-        }
+        {   try {
+                creatingComponents = true;
+                String forInput   = helper.getTagAttributeString("for");
+                String styleClass = helper.getTagStyleClass(DataType.UNKNOWN, null);
+                String style      = helper.getTagAttributeString("style");
+                // createLabelComponent 
+                labelComponent = helper.createLabelComponent(context, forInput, styleClass, style, getColon());
+                this.getChildren().add(labelComponent);
+                helper.resetComponentId(labelComponent);
+            } finally {
+                creatingComponents = false;
+            }
+        } 
 
         // render components
         labelComponent.encodeAll(context);

http://git-wip-us.apache.org/repos/asf/empire-db/blob/9176b225/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/LinkTag.java
----------------------------------------------------------------------
diff --git a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/LinkTag.java b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/LinkTag.java
index 1c04306..e0f88f0 100644
--- a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/LinkTag.java
+++ b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/LinkTag.java
@@ -27,7 +27,10 @@ import javax.faces.component.UINamingContainer;
 import javax.faces.component.UIOutput;
 import javax.faces.component.UIPanel;
 import javax.faces.component.UIParameter;
+import javax.faces.component.html.HtmlGraphicImage;
 import javax.faces.component.html.HtmlOutcomeTargetLink;
+import javax.faces.component.visit.VisitCallback;
+import javax.faces.component.visit.VisitContext;
 import javax.faces.context.FacesContext;
 import javax.faces.context.ResponseWriter;
 
@@ -35,6 +38,7 @@ import org.apache.empire.commons.ObjectUtils;
 import org.apache.empire.commons.StringUtils;
 import org.apache.empire.data.DataType;
 import org.apache.empire.jsf2.controls.InputControl;
+import org.apache.empire.jsf2.controls.InputControlManager;
 import org.apache.empire.jsf2.utils.StringResponseWriter;
 import org.apache.empire.jsf2.utils.TagEncodingHelper;
 import org.slf4j.Logger;
@@ -58,6 +62,8 @@ public class LinkTag extends UIOutput // implements NamingContainer
     
     protected final TagEncodingHelper helper = new TagEncodingHelper(this, "eLink");
 
+    private boolean creatingComponents = false;
+    
     public LinkTag()
     {
         log.trace("component link created");
@@ -68,6 +74,32 @@ public class LinkTag extends UIOutput // implements NamingContainer
     {
         return UINamingContainer.COMPONENT_FAMILY; 
     }
+    
+    /**
+     * remember original clientId
+     * necessary only inside UIData
+     */
+    private String treeClientId = null;
+    
+    @Override
+    public boolean visitTree(VisitContext visitContext, VisitCallback callback) 
+    {
+        FacesContext context = visitContext.getFacesContext();
+        treeClientId = this.getClientId(context);
+        return super.visitTree(visitContext, callback);
+    }
+
+    @Override
+    public String getClientId(FacesContext context)
+    {
+        // Check if dynamic components are being created
+        if (this.treeClientId!=null && this.creatingComponents)
+        {   // return the original tree client id
+            return treeClientId; 
+        }
+        // default behavior
+        return super.getClientId(context);
+    }
 
     @Override
     public void encodeBegin(FacesContext context)
@@ -93,7 +125,18 @@ public class LinkTag extends UIOutput // implements NamingContainer
             {
                 UIComponent c = getChildren().get(0);
                 if (c instanceof HtmlOutcomeTargetLink)
+                {   // reuse
                     linkComponent = (HtmlOutcomeTargetLink)c;
+                    helper.restoreComponentId(linkComponent);
+                    // check image
+                    if (linkComponent.getChildCount()>0)
+                    {   // Check HtmlGraphicImage
+                        int last = linkComponent.getChildCount()-1;
+                        UIComponent lcc = linkComponent.getChildren().get(last);
+                        if (lcc instanceof HtmlGraphicImage)
+                            helper.restoreComponentId(lcc);
+                    }
+                }
                 else
                 {   // Something's wrong here?
                     log.info("INFO: Unexpected child node for {}! Child item type is {}.", getClass().getName(), c.getClass().getName());
@@ -102,7 +145,7 @@ public class LinkTag extends UIOutput // implements NamingContainer
                     if (facetComponent==null)
                     {
                         log.warn("WARN: component's facetComponent has not been set! Using Default (javax.faces.Panel).");
-                        log.warn("Problem might be related to Mojarra 2.1.7 to 2.1.11 (and possibly later) - please use Mojarra 2.1.6!");
+                        log.warn("Problem might be related to Mojarra's state context saving for dynamic components (affects all versions > 2.1.6). See com.sun.faces.context.StateContext.java:AddRemoveListener");
                         facetComponent = (UIPanel)context.getApplication().createComponent("javax.faces.Panel");
                         facetComponent.setRendererType("javax.faces.Group");
                         getFacets().put(UIComponent.COMPOSITE_FACET_NAME, facetComponent);
@@ -110,9 +153,23 @@ public class LinkTag extends UIOutput // implements NamingContainer
                 }    
             }
             if (linkComponent == null)
-            {
-                linkComponent = new HtmlOutcomeTargetLink();
-                this.getChildren().add(0, linkComponent);
+            {   try {
+                    creatingComponents = true;
+                    linkComponent = new HtmlOutcomeTargetLink();
+                    this.getChildren().add(0, linkComponent);
+                    helper.saveComponentId(linkComponent);
+                    // encode image
+                    String imagePath = helper.getTagAttributeString("image");
+                    if (StringUtils.isNotEmpty(imagePath))
+                    {   // Create image
+                        HtmlGraphicImage img = encodeImage(context, linkComponent, imagePath);
+                        linkComponent.getChildren().add(img);
+                        helper.saveComponentId(linkComponent);
+                    }    
+                    // done
+                } finally {
+                    creatingComponents = false;
+                }
             }
             // set params
             setLinkProperties(linkComponent);
@@ -166,6 +223,10 @@ public class LinkTag extends UIOutput // implements NamingContainer
         }
         else
         {   // An ordinary link
+            String text = helper.getTagAttributeString("text");
+            if (text!=null)
+                return helper.getTextResolver(FacesContext.getCurrentInstance()).resolveText(text);
+            // Use value
             Object value = getValue();
             return value;
         }
@@ -182,7 +243,8 @@ public class LinkTag extends UIOutput // implements NamingContainer
         // Set Attributes
         Map<String,Object> attr = getAttributes();
         // Set outcome
-        String outcome = StringUtils.toString(attr.get("page"));
+        Object page = attr.get("page");
+        String outcome = StringUtils.toString(page);
         link.setOutcome(outcome);
         // Copy attributes
         if ((value=attr.get("style"))!=null)
@@ -191,6 +253,10 @@ public class LinkTag extends UIOutput // implements NamingContainer
             link.setTabindex(StringUtils.toString(value));
         if ((value=attr.get("onclick"))!=null)
             link.setOnclick(StringUtils.toString(value));
+        // title
+        String title = helper.getTagAttributeString("title");
+        if (StringUtils.isNotEmpty(title))
+            link.setTitle(title);
         // include view param
         link.setIncludeViewParams(false);
     }
@@ -219,6 +285,7 @@ public class LinkTag extends UIOutput // implements NamingContainer
         param.setName(paramName);
         param.setValue(paramValue);
         link.getChildren().add(param);
+        helper.resetComponentId(param);
     }
 
     protected String writeStartElement(ResponseWriter writer)
@@ -228,7 +295,7 @@ public class LinkTag extends UIOutput // implements NamingContainer
         String tagName  = StringUtils.coalesce(StringUtils.toString(map.get("tag")), "span");
         String cssClass = helper.getTagStyleClass();
         Object style = map.get("style");
-        Object title = map.get("title");
+        Object title = helper.getTagAttributeValue("title");
         // Write tag
         writer.startElement(tagName, this);
         helper.writeAttribute(writer, "class", cssClass);
@@ -237,6 +304,13 @@ public class LinkTag extends UIOutput // implements NamingContainer
         return tagName;
     }
     
+    protected HtmlGraphicImage encodeImage(FacesContext context, HtmlOutcomeTargetLink parent, String imagePath)
+    {
+        HtmlGraphicImage img = InputControlManager.createComponent(context, HtmlGraphicImage.class);
+        img.setValue(imagePath);
+        return img;
+    }
+    
     /*
      * public String getLabelValue()
      * {

http://git-wip-us.apache.org/repos/asf/empire-db/blob/9176b225/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/MenuItemTag.java
----------------------------------------------------------------------
diff --git a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/MenuItemTag.java b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/MenuItemTag.java
index 4b2296e..b6982bd 100644
--- a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/MenuItemTag.java
+++ b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/MenuItemTag.java
@@ -36,8 +36,8 @@ public class MenuItemTag extends LinkTag
     // Logger
     private static final Logger log = LoggerFactory.getLogger(MenuItemTag.class);
     
-    protected MenuListTag parentMenu = null;
-    protected String menuId;
+    private MenuListTag parentMenu = null;
+    private String menuId;
 
     /*
     private static int itemIdSeq = 0;
@@ -67,7 +67,8 @@ public class MenuItemTag extends LinkTag
     {
         // Detect Parent Menu
         parentMenu = getParentMenu();
-        menuId = StringUtils.toString(getAttributes().get("menuId"));
+        menuId = helper.getTagAttributeString("menuId"); 
+        
         if(!isRendered())
             return;
         
@@ -75,11 +76,22 @@ public class MenuItemTag extends LinkTag
         ResponseWriter writer = context.getResponseWriter();
         writer.startElement("li", this);
         writer.writeAttribute("id", getClientId(context), null);
-        writer.writeAttribute("class", getStyleClass(), null);
-        // writer.writeAttribute("item", String.valueOf(itemId), null);
+        helper.writeAttribute(writer, "class", getStyleClass());
 
+        String wrap = (parentMenu!=null ? parentMenu.getItemWrapTag() : null);
+        if (StringUtils.isNotEmpty(wrap))
+        {   // Wrap-Element
+            writer.startElement(wrap, this);
+            // writer.writeAttribute("class", "item", null);
+        }
+        
         // begin
         super.encodeBegin(context);
+        
+        // End Wrapper
+        if (StringUtils.isNotEmpty(wrap))
+            writer.endElement(wrap);
+        
     }
     
     @Override
@@ -119,7 +131,7 @@ public class MenuItemTag extends LinkTag
         {
             super.encodeEnd(context);
         }
-        // end of list item
+        // EndElement
         ResponseWriter writer = context.getResponseWriter();
         writer.endElement("li");
     }
@@ -165,10 +177,19 @@ public class MenuItemTag extends LinkTag
         // All present
         return menuId.equals(parentMenu.getCurrentId());
     }
+    
+    private boolean isParent()
+    {
+        if (menuId==null || parentMenu==null || parentMenu.getCurrentId()==null)
+            return false;
+        // All present
+        String  currentId = parentMenu.getCurrentId();
+        return (currentId.length()>menuId.length() && currentId.startsWith(menuId));
+    }
 
     private boolean isDisabled()
     {
-        Object value = getAttributes().get("disabled");
+        Object value = helper.getTagAttributeValue("disabled");
         if (value!=null)
             return ObjectUtils.getBoolean(value);
         return false;
@@ -176,7 +197,7 @@ public class MenuItemTag extends LinkTag
 
     private boolean isExpanded()
     {
-        Object value = getAttributes().get("expanded");
+        Object value = helper.getTagAttributeValue("expanded");
         boolean auto = false;
         if (value!=null)
         {   // is current?
@@ -198,15 +219,15 @@ public class MenuItemTag extends LinkTag
     @Override
     public boolean isRendered()
     {
-        Object value = getAttributes().get("currentOnly");
+        Object value = helper.getTagAttributeValue("currentOnly");
         boolean currentOnly = false;
-        if(value!=null)
+        if (value!=null)
             currentOnly = ObjectUtils.getBoolean(value);
         
         // Check parent
         if (currentOnly && menuId!=null && parentMenu!=null && parentMenu.getCurrentId()!=null)
         {    
-            return isCurrent();
+            return isCurrent() || isParent();
         }
         
         return super.isRendered();
@@ -214,7 +235,7 @@ public class MenuItemTag extends LinkTag
     
     private String getStyleClass()
     {
-        String styleClass = StringUtils.toString(getAttributes().get("styleClass"));
+        String styleClass = helper.getTagAttributeString("styleClass");
         if (parentMenu!=null)
         {
             // Style Class
@@ -223,8 +244,11 @@ public class MenuItemTag extends LinkTag
             // Menu Class
             if (isCurrent())
                 styleClass = appendStyleClass(styleClass, parentMenu.getCurrentClass());
-            else if (isExpanded())
-                styleClass = appendStyleClass(styleClass, parentMenu.getExpandedClass());
+            else if (isParent())
+                styleClass = appendStyleClass(styleClass, parentMenu.getParentClass());
+            // expanded
+            if (isExpanded())
+                styleClass = appendStyleClass(styleClass, parentMenu.getExpandedClass());            
             // Disabled / enabled
             if (isDisabled())
                 styleClass = appendStyleClass(styleClass, parentMenu.getDisabledClass());


Mime
View raw message