Project: activiti-explorer
/* Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 *  
 *      http://www.apache.org/licenses/LICENSE-2.0 
 *  
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 */
 
package org.activiti.explorer.ui.custom; 
 
import java.util.Arrays; 
import java.util.Collection; 
import java.util.List; 
import java.util.Set; 
 
import org.activiti.engine.identity.User; 
import org.activiti.explorer.ExplorerApp; 
import org.activiti.explorer.I18nManager; 
import org.activiti.explorer.Messages; 
import org.activiti.explorer.cache.UserCache; 
import org.activiti.explorer.identity.LoggedInUser; 
import org.activiti.explorer.ui.Images; 
import org.activiti.explorer.ui.event.SubmitEvent; 
import org.activiti.explorer.ui.event.SubmitEventListener; 
import org.activiti.explorer.ui.util.ThemeImageColumnGenerator; 
 
import com.vaadin.data.Item; 
import com.vaadin.event.FieldEvents.TextChangeEvent; 
import com.vaadin.event.FieldEvents.TextChangeListener; 
import com.vaadin.ui.Alignment; 
import com.vaadin.ui.Button; 
import com.vaadin.ui.Button.ClickEvent; 
import com.vaadin.ui.Button.ClickListener; 
import com.vaadin.ui.ComboBox; 
import com.vaadin.ui.Embedded; 
import com.vaadin.ui.HorizontalLayout; 
import com.vaadin.ui.Table; 
import com.vaadin.ui.TextField; 
import com.vaadin.ui.VerticalLayout; 
import com.vaadin.ui.themes.Reindeer; 
 
 
/**
 * A popup window that is used to select people. Two possible modes: 
 * - multiselect: displays two tables that allow to select users from the left table  
 *   to the table on the right 
 * - non-multiselect: one table where only one user can be chosen from. 
 *  
 * {@link SubmitEventListener} can be attached to listen to completion of the  
 * selection. The selected user(s) can be retrieved using {@link #getSelectedUserId()} 
 * ,{@link #getSelectedUserIds()} and {@link #getSelectedUserRole(String)}.   
 *  
 * @author Joram Barrez 
 */
 
public class SelectUsersPopupWindow extends PopupWindow { 
 
  private static final long serialVersionUID = 1L
   
  protected String title; 
  protected boolean multiSelect = true
  protected boolean showRoles = true
  protected Collection<String> ignoredUserIds; 
   
  protected UserCache userCache; 
  protected I18nManager i18nManager; 
   
  protected VerticalLayout windowLayout; 
  protected TextField searchField; 
  protected HorizontalLayout userSelectionLayout; 
  protected Table matchingUsersTable; 
  protected Button selectUserButton; 
  protected Table selectedUsersTable; 
  protected Button doneButton; 
   
  public SelectUsersPopupWindow(String title, boolean multiSelect) { 
    this.title = title; 
    this.multiSelect = multiSelect; 
    this.userCache = ExplorerApp.get().getUserCache(); 
    this.i18nManager = ExplorerApp.get().getI18nManager(); 
  } 
   
  public SelectUsersPopupWindow(String title, boolean multiSelect, Collection<String> ignoredUserIds) { 
    this(title, multiSelect); 
    this.ignoredUserIds = ignoredUserIds; 
  } 
   
  public SelectUsersPopupWindow(String title, boolean multiSelect, boolean showRoles, Collection<String> ignoredUserIds) { 
    this(title, multiSelect); 
    this.showRoles = showRoles; 
    this.ignoredUserIds = ignoredUserIds; 
  } 
   
  @Override 
  public void attach() { 
    super.attach(); 
    initUi(); 
  } 
   
  protected void initUi() { 
    setCaption(title); 
    setModal(true); 
    addStyleName(Reindeer.WINDOW_LIGHT); 
    center(); 
     
    windowLayout = (VerticalLayout) getContent(); 
    windowLayout.setSpacing(true); 
     
    if (multiSelect && showRoles) { 
      setWidth(820, UNITS_PIXELS); 
    } else if (multiSelect && !showRoles) {  
      setWidth(685, UNITS_PIXELS); 
    } else { 
      setWidth(340, UNITS_PIXELS); 
    } 
    setHeight(350, UNITS_PIXELS); 
 
    initSearchField(); 
    initUserSelection(); 
    initDoneButton(); 
  } 
   
  protected void initSearchField() { 
    HorizontalLayout searchLayout = new HorizontalLayout(); 
    searchLayout.setSpacing(true); 
    addComponent(searchLayout); 
     
    // textfield 
    searchField = new TextField(); 
    searchField.setInputPrompt(i18nManager.getMessage(Messages.PEOPLE_SEARCH)); 
    searchField.setWidth(180, UNITS_PIXELS); 
    searchField.focus(); 
    searchLayout.addComponent(searchField); 
     
    // Logic to change table according to input 
    searchField.addListener(new TextChangeListener() { 
      public void textChange(TextChangeEvent event) { 
        searchPeople(event.getText()); 
      } 
    }); 
     
    initSelectMyselfButton(searchLayout); 
  } 
 
  protected void initSelectMyselfButton(HorizontalLayout searchLayout) { 
    final LoggedInUser loggedInUser = ExplorerApp.get().getLoggedInUser(); 
    if (ignoredUserIds == null || !ignoredUserIds.contains(loggedInUser.getId())) { 
      Button meButton = new Button(i18nManager.getMessage(Messages.PEOPLE_SELECT_MYSELF)); 
      meButton.setIcon(Images.USER_16); 
      searchLayout.addComponent(meButton); 
      searchLayout.setComponentAlignment(meButton, Alignment.MIDDLE_LEFT); 
       
      if (multiSelect) { 
        meButton.addListener(new ClickListener() { 
          public void buttonClick(ClickEvent event) { 
            selectUser(loggedInUser.getId(), loggedInUser.getFullName()); 
          } 
        }); 
      } else { 
        meButton.addListener(new ClickListener() { 
          public void buttonClick(ClickEvent event) { 
            addMatchingUser(loggedInUser.getId(), loggedInUser.getFullName()); 
            matchingUsersTable.select(loggedInUser.getId()); 
            fireEvent(new SubmitEvent(doneButton, SubmitEvent.SUBMITTED)); 
            close(); 
          } 
        }); 
      } 
    } 
  } 
   
  protected void searchPeople(String searchText) { 
    if (searchText.length() >= 2) { 
      matchingUsersTable.removeAllItems(); 
      List<User> results = userCache.findMatchingUsers(searchText); 
      for (User user : results) { 
        if (!multiSelect || !selectedUsersTable.containsId(user.getId())) { 
          if (ignoredUserIds == null || !ignoredUserIds.contains(user.getId())) { 
            addMatchingUser(user.getId(), user.getFirstName() + " " + user.getLastName()); 
          } 
        } 
      } 
    } 
  } 
   
  protected void addMatchingUser(String userId, String name) { 
    if (!matchingUsersTable.containsId(userId)) { 
      Item item = matchingUsersTable.addItem(userId); 
      item.getItemProperty("userName").setValue(name); 
    } 
  } 
   
  protected void initUserSelection() { 
    userSelectionLayout = new HorizontalLayout(); 
    userSelectionLayout.setSpacing(true); 
    addComponent(userSelectionLayout); 
     
    initMatchingUsersTable(); 
     
    // If multi select: two table to move users from left to the right 
    // non-multi select: only one table 
    if (multiSelect) { 
      initSelectUserButton(); 
      initSelectedUsersTable(); 
    } 
  } 
   
  protected void initMatchingUsersTable() { 
   matchingUsersTable = new Table(); 
   matchingUsersTable.setColumnHeaderMode(Table.COLUMN_HEADER_MODE_HIDDEN); 
   matchingUsersTable.setSelectable(true); 
   matchingUsersTable.setEditable(false); 
   matchingUsersTable.setImmediate(true); 
   matchingUsersTable.setNullSelectionAllowed(false); 
   matchingUsersTable.setSortDisabled(true); 
    
   if (multiSelect) { 
     matchingUsersTable.setMultiSelect(true); 
   } 
    
   matchingUsersTable.addGeneratedColumn("icon"new ThemeImageColumnGenerator(Images.USER_16)); 
   matchingUsersTable.setColumnWidth("icon"16); 
   matchingUsersTable.addContainerProperty("userName", String.classnull); 
 
   matchingUsersTable.setWidth(300, UNITS_PIXELS); 
   matchingUsersTable.setHeight(200, UNITS_PIXELS); 
   userSelectionLayout.addComponent(matchingUsersTable); 
  } 
   
  protected void initSelectUserButton() { 
    selectUserButton = new Button(">"); 
     
    selectUserButton.addListener(new ClickListener() { 
      public void buttonClick(ClickEvent event) { 
        for (String selectedItemId : (Set<String>) matchingUsersTable.getValue()) { 
          // Remove from left table 
          Item originalItem = matchingUsersTable.getItem(selectedItemId); 
           
          // And put it in right table 
          selectUser(selectedItemId, (String) originalItem.getItemProperty("userName").getValue()); 
           
          // Remove from left table (must be done on the end, or item properties will be inaccessible)  
          matchingUsersTable.removeItem(selectedItemId); 
        } 
      } 
    }); 
     
    userSelectionLayout.addComponent(selectUserButton); 
    userSelectionLayout.setComponentAlignment(selectUserButton, Alignment.MIDDLE_CENTER); 
  } 
   
  protected void initSelectedUsersTable() { 
    selectedUsersTable = new Table(); 
    selectedUsersTable.setColumnHeaderMode(Table.COLUMN_HEADER_MODE_HIDDEN); 
    selectedUsersTable.setEditable(false); 
    selectedUsersTable.setSortDisabled(true); 
     
    // Icon column 
    selectedUsersTable.addGeneratedColumn("icon"new ThemeImageColumnGenerator(Images.USER_ADD)); 
    selectedUsersTable.setColumnWidth("icon"16); 
     
    // Name column 
    selectedUsersTable.addContainerProperty("userName", String.classnull); 
     
    // Role column 
    if (showRoles) { 
      selectedUsersTable.addContainerProperty("role", ComboBox.classnull); 
    } 
     
    // Delete icon column 
    selectedUsersTable.addGeneratedColumn("delete"new ThemeImageColumnGenerator(Images.DELETE,  
      new com.vaadin.event.MouseEvents.ClickListener() { 
        public void click(com.vaadin.event.MouseEvents.ClickEvent event) { 
          Object itemId = ((Embedded) event.getSource()).getData(); 
           
          // Add to left table (if possible) 
          String searchFieldValue = (String) searchField.getValue(); 
          if (searchFieldValue != null && searchFieldValue.length() >= 2) { 
            String userName = (String) selectedUsersTable.getItem(itemId).getItemProperty("userName").getValue(); 
            if (matchesSearchField(userName)) { 
              Item item = matchingUsersTable.addItem(itemId); 
              item.getItemProperty("userName").setValue(userName); 
            } 
          } 
             
          // Delete from right table 
          selectedUsersTable.removeItem(itemId); 
        } 
    })); 
    selectedUsersTable.setColumnWidth("icon"16); 
 
    if (showRoles) { 
      selectedUsersTable.setWidth(420, UNITS_PIXELS); 
    } else { 
      selectedUsersTable.setWidth(300, UNITS_PIXELS); 
    } 
    selectedUsersTable.setHeight(200, UNITS_PIXELS); 
    userSelectionLayout.addComponent(selectedUsersTable); 
  } 
   
  protected boolean matchesSearchField(String text) { 
    for (String userNameToken : text.split(" ")) { 
      if (userNameToken.toLowerCase().startsWith(((String) searchField.getValue()).toLowerCase())) { 
        return true
      } 
    } 
    return false
  } 
   
  protected void selectUser(String userId, String userName) { 
    if (!selectedUsersTable.containsId(userId)) { 
      Item item = selectedUsersTable.addItem(userId); 
      item.getItemProperty("userName").setValue(userName); 
       
      if (showRoles) { 
        ComboBox comboBox = new ComboBox(null, Arrays.asList( 
                i18nManager.getMessage(Messages.TASK_ROLE_CONTRIBUTOR), 
                i18nManager.getMessage(Messages.TASK_ROLE_IMPLEMENTER), 
                i18nManager.getMessage(Messages.TASK_ROLE_MANAGER), 
                i18nManager.getMessage(Messages.TASK_ROLE_SPONSOR))); 
        comboBox.select(i18nManager.getMessage(Messages.TASK_ROLE_CONTRIBUTOR)); 
        comboBox.setNewItemsAllowed(true); 
        item.getItemProperty("role").setValue(comboBox); 
      } 
    } 
  } 
   
  protected void initDoneButton() { 
    doneButton = new Button("Done"); 
     
    doneButton.addListener(new ClickListener() { 
      public void buttonClick(ClickEvent event) { 
        // Fire event such that depending UI's can be updated 
        fireEvent(new SubmitEvent(doneButton, SubmitEvent.SUBMITTED)); 
         
        // close popup window 
        close(); 
      } 
    }); 
     
    addComponent(doneButton); 
    windowLayout.setComponentAlignment(doneButton, Alignment.MIDDLE_RIGHT); 
  } 
   
  public String getSelectedUserId() { 
    if (multiSelect) { 
      throw new RuntimeException("Only use getSelectedUserId in non-multiselect mode"); 
    } 
    return (String) matchingUsersTable.getValue(); 
  } 
   
  @SuppressWarnings("unchecked"
  public Collection<String> getSelectedUserIds() { 
    if (!multiSelect) { 
      throw new RuntimeException("Only use getSelectedUserIds in multiselect mode"); 
    } 
    return (Collection<String>) selectedUsersTable.getItemIds(); 
  } 
   
  public String getSelectedUserRole(String userId) { 
    if (!multiSelect) { 
      throw new RuntimeException("Only use getSelectedUserIds in multiselect mode"); 
    } 
    return (String) ((ComboBox) selectedUsersTable.getItem(userId).getItemProperty("role").getValue()).getValue(); 
  } 
   
}