1 Reply Latest reply on Aug 20, 2009 11:54 AM by Martin Frey

    Multi Tab Editor

    Martin Frey Newbie

      Hello all.


      We are currently trying to implement a so called MultiTabEditor in our application we have to maintain. The idea behind this composite should be that it works similar like the EditorPart in Eclipse.


      So for the moment i'm just trying some stuff with the TabPanel and i'm not really getting somewhere. Did anyone of you already succeed in creating a component like that?


      I'm currently evaluating some ideas we had and get to some issues listed below:




      Use NestedConversations for each Tab in the TabPanel so we can use one entityHome for holding the instance per tab:
       
      - Since the TabPanel has to be dynamically created with a c:foreach we have to rerender the whole panel.
        Is it possible to add a tab through javascript? 
        (with client side fetching of the content that would make the foreach not needed anymore)
      - How to pass the conversation of the current tab to the server so we access the right entityhome for an update?
      



      Use one conversation with an intermediate editor class which holds all instances and rerender the whole tabPanel:
      
      - Uses only one EntityHome and is responsible for setting / updating instances through entityHome.
      - Here if i switch tabs i actually loose the modifications?
      - In this case i would work with clones of the loaded instances and push the data back through 
        the entityhome the editor is holding.
      



      One other solution would be to popup as many new frames as instances currently edited but this is just not as nice as we think it could be possible. :)


      Regards
      Antibrumm

        • 1. Re: Multi Tab Editor
          Martin Frey Newbie

          Okido.
          I got something working. Let me know what you think about it. (Working code, but not yet very nice.)



          There is still one problem with this approach. Since the instance in the tab is always managed and the datatable is refreshed the entityManager will update the bean automatically, even if we don't call the update method in the entityHome. Here i'm clearly missing something. My workaround will be to work on a clone in the forms always. Is this the correct approach or is this update happening because i do something wrong with rerender, processing or whatever? Thanks for you help.


          The code is based on an application created with the Eclipse Seam Wizard.


          Testpage with New Button, MultiTabEditor and a DataTable.


          <ui:define name="body">
              <a:region>
                <a:form>
                  <a:commandButton action="#{editor.newInstance}" value="New"
                    reRender="editor" immediate="true" />
                </a:form>
              </a:region>
              <a:region>
                <a:form>
                  <rich:tabPanel switchType="ajax" id="editor"
                    selectedTab="#{editor.currentTab}">
                    <c:forEach items="#{editor.editorTabs}" var="tab">
                      <c:set var="instance" value="#{tab.instance}" />
                      <rich:tab label="#{tab.name}" name="#{tab.name}"
                        action="#{editor.setCurrentTab(tab.name)}"
                        reRender="editor">
                        <c:if test="#{tab.name == editor.currentTab}">
                          <a:commandButton action="#{editor.remove(instance)}"
                            value="X" reRender="editor" />
                          <br />
                          Id: <h:inputText value="#{instance.id}"
                            rendered="#{instance.id == null}" />
                          <br />
                          Text: <h:inputText value="#{instance.text}" />
                          <br />
                          <a:commandButton action="#{editor.dbPersist(instance)}"
                            value="Persist" reRender="editor,table" />
                          <a:commandButton action="#{editor.dbUpdate(instance)}"
                            value="Update" reRender="editor,table" />
                          <a:commandButton action="#{editor.dbRemove(instance)}"
                            value="Delete" reRender="editor" immediate="true" />
                        </c:if>
                      </rich:tab>
                    </c:forEach>
                  </rich:tabPanel>
                </a:form>
              </a:region>
              <a:region>
                <rich:panel id="table">
                  <a:form>
                    <a:commandButton reRender="table" value="Refresh" />
                    <rich:dataTable value="#{testBeanQuery.resultList}"
                      var="testBean">
                      <rich:column>
                        <a:commandButton action="#{editor.remove(testBean)}"
                          value="X" reRender="table" />
                      </rich:column>
                      <rich:column label="id">
                        <a:commandLink action="#{editor.addInstance(testBean)}"
                          value="#{testBean.id}" reRender="editor"
                          immediate="true" />
                      </rich:column>
                      <rich:column label="text">
                        <h:outputText value="#{testBean.text}" />
                      </rich:column>
                    </rich:dataTable>
                  </a:form>
                </rich:panel>
              </a:region>
            </ui:define>
          



          Editor Backingbean. Baseentity just has an Id attribte


          package org.domain.test.manager.common;
          
          import java.io.Serializable;
          import java.util.ArrayList;
          import java.util.List;
          
          import org.domain.test.entity.BaseEntity;
          import org.jboss.seam.framework.EntityHome;
          
          public abstract class Editor<E extends BaseEntity, H extends EntityHome<E>> implements Serializable {
               /**
                * 
                */
               private static final long serialVersionUID = 1L;
          
               private String currentTab;
          
               private List<EditorTab<E>> editorTabs;
          
               public void addInstance(E instance) {
                    EditorTab<E> tab = new EditorTab<E>();
                    tab.setInstance(instance);
                    List<EditorTab<E>> editorTabs = getEditorTabs();
                    if (tab.getInstance().getId() != null) {
                         tab.setName(String.valueOf(tab.getInstance().getId()));
                    } else {
                         int i = 1;
                         for (EditorTab<E> ic : editorTabs) {
                              if (ic.getName().startsWith("New")) {
                                   i++;
                              }
                         }
                         tab.setName("New " + i);
                    }
                    boolean contains = false;
                    for (EditorTab<E> ic : editorTabs) {
                         if (ic.getName().equals(tab.getName())) {
                              contains = true;
                              break;
                         }
                    }
                    if (!contains) {
                         editorTabs.add(tab);
                    }
                    setCurrentTab(tab.getName());
               }
          
               public String dbPersist(E instance) {
                    EditorTab<E> tab = getEditorTab(instance);
                    H entityHome = getEntityHome();
                    entityHome.setInstance(instance);
                    String result = entityHome.persist();
                    tab.setInstance(entityHome.getInstance());
                    return result;
               }
          
               public String dbRemove(E instance) {
                    H entityHome = getEntityHome();
                    entityHome.setId(instance.getId());
                    String result = entityHome.remove();
                    removeTab(instance);
                    return result;
               }
          
               public String dbUpdate(E instance) {
                    EditorTab<E> tab = getEditorTab(instance);
                    H entityHome = getEntityHome();
                    entityHome.setInstance(instance);
                    String result = entityHome.update();
                    tab.setInstance(entityHome.getInstance());
                    return result;
               }
          
               public String getCurrentTab() {
                    if (currentTab == null && !getEditorTabs().isEmpty()) {
                         currentTab = getEditorTabs().get(0).getName();
                    }
                    return currentTab;
               }
          
               public EditorTab<E> getEditorTab(E instance) {
                    for (EditorTab<E> tab : getEditorTabs()) {
                         if (tab.getInstance().equals(instance)) {
                              return tab;
                         }
                    }
                    return null;
               }
          
               public List<EditorTab<E>> getEditorTabs() {
                    if (editorTabs == null) {
                         editorTabs = new ArrayList<EditorTab<E>>();
                    }
                    return editorTabs;
               }
          
               protected abstract H getEntityHome();
          
               public E getInstance(Long id) {
                    for (EditorTab<E> tab : getEditorTabs()) {
                         E instance = tab.getInstance();
                         if (id.equals(instance.getId())) {
                              return instance;
                         }
                    }
                    return null;
               }
          
               public List<E> getInstances() {
                    List<E> instances = new ArrayList<E>();
                    for (EditorTab<E> tab : getEditorTabs()) {
                         instances.add(tab.getInstance());
                    }
                    return instances;
               }
          
               public void newInstance() {
                    H entityHome = getEntityHome();
                    entityHome.setId(null);
                    addInstance(entityHome.getInstance());
               }
          
               public void removeTab(E instance) {
                    EditorTab<E> tab = getEditorTab(instance);
                    getEditorTabs().remove(tab);
                    if (getEditorTabs().isEmpty()) {
                         setCurrentTab(null);
                    } else {
                         setCurrentTab(getEditorTabs().get(0).getName());
                    }
               }
          
               public void setCurrentTab(String tabName) {
                    this.currentTab = tabName;
               }
          
          }
          



          The editorTab


          /**
           * 
           */
          package org.domain.test.manager.common;
          
          import java.io.Serializable;
          
          import org.domain.test.entity.BaseEntity;
          import org.hibernate.util.SerializationHelper;
          
          public class EditorTab<E extends BaseEntity> implements Serializable {
               /**
                * 
                */
               private static final long serialVersionUID = 1L;
          
               private E instance;
          
               private String name;
          
               private E originalState;
          
               public E getInstance() {
                    return instance;
               }
          
               public String getName() {
                    return name;
               }
          
               public E getOriginalState() {
                    return originalState;
               }
          
               public void setInstance(E instance) {
                    this.instance = instance;
                    this.originalState = (E) SerializationHelper.clone(instance);
               }
          
               public void setName(String name) {
                    this.name = name;
               }
          
          }
          



          (Feel free to use this code if it's good enough)