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 <[email protected]> Authored: Mon Feb 1 14:18:21 2016 +0100 Committer: Rainer Döbele <[email protected]> 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());
