Scarab commit: svn commit: r10768 - trunk/src: conf/conf java/org/tigris/scarab/actions java/org/tigris/scarab/om schema sql/upgrade webapp/WEB-INF/templates/screens/admin webapp/WEB-INF/templates/viewIssue

Hussayn Dabbous <[email protected]>
Newsgroups gmane.comp.java.scarab.cvs
Message-ID <[email protected]>
Author: dabbous
Date: 2009-07-03 11:19:26-0700
New Revision: 10768

Modified:
   trunk/src/conf/conf/intake.xml
   trunk/src/java/org/tigris/scarab/actions/AssignIssue.java
   trunk/src/java/org/tigris/scarab/om/AbstractScarabModule.java
   trunk/src/java/org/tigris/scarab/om/Attribute.java
   trunk/src/java/org/tigris/scarab/om/AttributeValue.java
   trunk/src/java/org/tigris/scarab/om/ScarabUserImpl.java
   trunk/src/schema/scarab-schema.xml
   trunk/src/sql/upgrade/upgrade-0.23-attribute.sql
   trunk/src/webapp/WEB-INF/templates/screens/admin/ModuleAttributeEdit.vm
   trunk/src/webapp/WEB-INF/templates/screens/admin/UserAttributeEdit.vm
   trunk/src/webapp/WEB-INF/templates/viewIssue/ViewIssueTab2.vm

Log:
SCB2977: Aded new flag to support 'only one single assigned to' user per issue. rewrote the AssignIssue template to allow much simpler user interaction.Note: You must run the upgrade-0.23-attribute.sql to get the new feature up and running

Modified: trunk/src/conf/conf/intake.xml
Url: http://scarab.tigris.org/source/browse/scarab/trunk/src/conf/conf/intake.xml?view=diff&pathrev=10768&r1=10767&r2=10768
==============================================================================
--- trunk/src/conf/conf/intake.xml	(original)
+++ trunk/src/conf/conf/intake.xml	2009-07-03 11:19:26-0700
@@ -50,7 +50,8 @@
             <rule name="minLength" value="1">intake_ActionNotAllowedEmpty</rule>
             <rule name="maxLength" value="255">intake_ActionMustBeLessThan255Characters</rule>
         </field>
-        <field name="Deleted" key="del" type="boolean" />
+        <field name="Deleted"    key="del"      type="boolean" />
+        <field name="MultiValue" key="multival" type="boolean" />
 </group>
 
 <group name="ConditionEdit" key="cndtn" mapToObject="om.Condition">

Modified: trunk/src/java/org/tigris/scarab/actions/AssignIssue.java
Url: http://scarab.tigris.org/source/browse/scarab/trunk/src/java/org/tigris/scarab/actions/AssignIssue.java?view=diff&pathrev=10768&r1=10767&r2=10768
==============================================================================
--- trunk/src/java/org/tigris/scarab/actions/AssignIssue.java	(original)
+++ trunk/src/java/org/tigris/scarab/actions/AssignIssue.java	2009-07-03 11:19:26-0700
@@ -47,12 +47,14 @@
  */ 
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.logging.Logger;
 
 import org.apache.fulcrum.parser.ParameterParser;
 import org.apache.torque.TorqueException;
@@ -67,6 +69,7 @@
 import org.tigris.scarab.om.AttributeManager;
 import org.tigris.scarab.om.AttributeValue;
 import org.tigris.scarab.om.Issue;
+import org.tigris.scarab.om.IssueManager;
 import org.tigris.scarab.om.Module;
 import org.tigris.scarab.om.ScarabUser;
 import org.tigris.scarab.om.ScarabUserManager;
@@ -109,24 +112,12 @@
             {
                 userAttributes.put(userIds[i], params.get("user_attr_" + userIds[i]));
             }
-            returnCode = addUsersToList(user, module, userAttributes, msg);
-            if (returnCode == USERS_ADDED)
-            {
-                scarabR.setConfirmMessage(L10NKeySet.SelectedUsersWereAdded);
-            }
-            if (returnCode == USERS_REMOVED)
-            {
-                L10NMessage l10nMsg = new L10NMessage(L10NKeySet.UserAttributeRemoved,
-                        msg.toString());
-                scarabR.setAlertMessage(l10nMsg);
-            }
-            if (returnCode == ERR_NO_USERS_SELECTED)
-            {
-                scarabR.setAlertMessage(L10NKeySet.NoUsersSelected);
-            }
+            returnCode = addUsersToList(user, module, userAttributes, msg);        
+            setGUIMessage(returnCode, scarabR, msg);
         }
     }
 
+
     /**
      * Adds the current user to the temporary working list.
      * @param data
@@ -137,13 +128,36 @@
         throws Exception
     {
         ScarabRequestTool scarabR = getScarabRequestTool(context);
+        Issue issue = scarabR.getIssue();
         ScarabUser user = (ScarabUser)data.getUser();
+        
+        // clean up first. I may already be in the list
+        // [HD]Note: Here i assume, that one user may only show up ONCE
+        //     in the list. Apparently it does not make sense to
+        //     assign someone AND let the same person observe an issue
+        //     at the same time. But OTOH it might be possible, that
+        //     other use cases exist, which make it necessary to
+        //     have multiple assignments of the same user in the list.
+        //     (to be discussed?)
+        removeUserFromIssue(user, issue); 
+
         String attributeId = data.getParameters().get("myself_attribute");
         String userId = user.getUserId().toString();
         Map map = new HashMap();
         map.put(userId, attributeId);
         StringBuffer msg = new StringBuffer();
         int returnCode = addUsersToList(user, scarabR.getCurrentModule(), map, msg);
+        setGUIMessage(returnCode, scarabR, msg);       
+    }
+
+    /**
+     * Set the appropriate GUI message for the given returnCode.
+     * @param returnCode
+     * @param scarabR
+     * @param msg
+     */
+    private void setGUIMessage(int returnCode, ScarabRequestTool scarabR, StringBuffer msg) 
+    {
         if (returnCode == USERS_ADDED)
         {
             scarabR.setConfirmMessage(L10NKeySet.SelectedUsersWereAdded);
@@ -157,37 +171,22 @@
         if (returnCode == ERR_NO_USERS_SELECTED)
         {
             scarabR.setAlertMessage(L10NKeySet.NoUsersSelected);
-        }       
+        }
     }
     
     /**
-     * Adds the current user to the temporary working list.
+     * Removes the current user from the temporary working list.
      * @param data
      * @param context
      * @throws Exception
      */
     public void doRemovemyself(RunData data, TemplateContext context)
-        throws Exception
+    throws Exception
     {
         ScarabRequestTool scarabR = this.getScarabRequestTool(context);
         ScarabUser user = (ScarabUser) data.getUser();
-        Integer myUid = user.getUserId();
         Issue issue = scarabR.getIssue();
-        Set userSet = issue.getAssociatedUsers();
-        Iterator iter = userSet.iterator();
-        int removeCounter = 0;
-        int index = 0;
-        while(iter.hasNext())
-        {
-            ArrayList entry = (ArrayList)iter.next();
-            ScarabUser su = (ScarabUser)entry.get(1);
-            if (su.getUserId().equals(myUid))
-            {
-                userSet.remove(entry);     // now the iterator is potentially invalid
-                iter = userSet.iterator(); // rebuild the iterator (suboptimal)
-                removeCounter++;
-            }
-        }
+        int removeCounter = removeUserFromIssue(user, issue);
         if(removeCounter>0)
         {
             scarabR.setConfirmMessage(L10NKeySet.SelectedUsersWereRemoved);
@@ -197,7 +196,52 @@
             scarabR.setAlertMessage(L10NKeySet.NoUsersSelected);
         }
     }
+
+    private int removeUserFromIssue(ScarabUser user, Issue issue) throws TorqueException
+    {
+        return removeUserFromIssue(user, null, issue);
+    }
+    
     
+    private int removeUserFromIssue(ScarabUser user, Attribute attribute, Issue issue) throws TorqueException
+    {
+        Set<ArrayList> userSet = issue.getAssociatedUsers();
+        return removeUserFromUserSet(user, attribute, userSet);
+   }
+
+    private int removeUserFromUserSet(ScarabUser user, Attribute attribute, Set<ArrayList> userSet) throws TorqueException
+    {
+        Integer userId = user.getUserId();
+        Iterator<ArrayList> iter = userSet.iterator();
+        Collection toBeRemoved = new ArrayList();
+
+        while(iter.hasNext())
+        {
+            ArrayList entry = iter.next();
+            ScarabUser su = (ScarabUser)entry.get(1);
+
+            if (su.equals(user))
+            {
+                if(attribute != null)
+                {
+                    Attribute entryAttribute = (Attribute)entry.get(0);
+                    if (!entryAttribute.equals(attribute))
+                    {
+                        continue;
+                    }
+                }
+                toBeRemoved.add(entry);
+            }
+
+        }
+        
+
+        userSet.removeAll(toBeRemoved);
+        int removeCounter = toBeRemoved.size();
+        
+        return removeCounter;
+   }
+
     /**
      * Decoupled method that adds users to the temporary working list of the AssignIssue screen.
      * @param user Currently connected user
@@ -237,7 +281,7 @@
                     {
                         userList = new HashSet();
                     }
-                    List attributeList = module
+                    List<Attribute> attributeList = module
                         .getUserAttributes(issue.getIssueType(), true);
                     if (!attributeList.contains(attribute))
                     {
@@ -258,6 +302,8 @@
                     }
                     else
                     {
+                        removeUserFromUserSet(su, null, userList); // remove all user entries from set.
+                        cleanupMultiAssignEntries(attribute, userList, attributeList);
                         userList.add(item);
                         // userMap.put(issueId, userList);
                         // user.setAssociatedUsersMap(userMap);
@@ -279,8 +325,72 @@
         }
         return returnCode;
     }
+
+    /**
+     * Reassigns all user in the list with given attribute to the first available
+     * multiValue enabled attribute.
+     * @param attribute
+     * @param userList
+     * @param attributeList
+     */
+    private void cleanupMultiAssignEntries(Attribute attribute, Set userList, List<Attribute> attributeList) 
+    {
+        // If attribute is marked multiValue, this is interpreted here as
+        // "multiple users may be assigned to this attribute"
+        // So here we only need to take care of non singleValue attributes
+        if (attribute.getMultiValue()==false)
+        {
+
+            // well, sort of a hack...
+            // If the list already contains this user attribute
+            // replace that one by "the first available multiValue user attribute"
+            // uhhh... i don't like that. Any better ideas around ???
+            
+            Iterator iter = userList.iterator();
+            Collection toBeRemoved = new ArrayList();
+            while(iter.hasNext())
+            {
+                List entry = (List)iter.next();
+                Attribute  entryAttr = (Attribute)entry.get(0);
+                
+                if(entryAttr.getAttributeId() == attribute.getAttributeId())
+                {
+                    Attribute newAttrib = findFirstMultiAssignAttribute(attributeList);
+                    if (newAttrib == null)
+                    {
+                        toBeRemoved.add(entry); // remember entry for removement (see below)
+                    }
+                    else
+                    {
+                        entry.remove(0);        // remove the old attribute
+                        entry.add(0,newAttrib); // and move the new attribute in place
+                    }
+                }
+            }
+            userList.remove(toBeRemoved); // remove all collected entries
+        }
+    }
         
     /**
+     * Find the first multiValue enabled attribute in the list.
+     * @param attributeList
+     * @return
+     */
+    private Attribute findFirstMultiAssignAttribute(List<Attribute> attributeList) 
+    {
+        Iterator<Attribute> iter = attributeList.iterator();
+        while(iter.hasNext())
+        {
+            Attribute att = iter.next();
+            if (att.getMultiValue())
+            {
+                return att;
+            }
+        }
+        return null;
+    }
+
+    /**
      * Removes users from temporary working list.
      */
     private void remove(RunData data, TemplateContext context, Long issueId) 
@@ -288,7 +398,7 @@
     {
         ScarabUser user = (ScarabUser)data.getUser();
         ScarabRequestTool scarabR = getScarabRequestTool(context);
-        Set userList = (Set) user.getAssociatedUsersMap().get(issueId);
+        Set userSet = (Set) user.getAssociatedUsersMap().get(issueId);
         ParameterParser params = data.getParameters();
         String[] selectedUsers =  params.getStrings(SELECTED_USER);
         if (selectedUsers != null && selectedUsers.length > 0) 
@@ -299,13 +409,10 @@
                 String selectedUser = selectedUsers[i];
                 String userId = selectedUser.substring(1, selectedUser.indexOf('_')-1);
                 String attrId = selectedUser.substring(selectedUser.indexOf('_')+1, selectedUser.length());
-                Attribute attribute = AttributeManager
-                    .getInstance(new Integer(attrId));
-                ScarabUser su = ScarabUserManager
-                    .getInstance(new Integer(userId));
-                item.add(attribute);
-                item.add(su);
-                userList.remove(item);
+                Attribute attribute = AttributeManager.getInstance(new Integer(attrId));
+                ScarabUser su = ScarabUserManager.getInstance(new Integer(userId));
+                Issue issue = IssueManager.getInstance(issueId);
+                removeUserFromUserSet(su, attribute, userSet);
             }
             scarabR.setConfirmMessage(L10NKeySet.SelectedUsersWereRemoved);
         }
@@ -326,29 +433,31 @@
         Set userList = (Set) user.getAssociatedUsersMap().get(issueId);
         ParameterParser params = data.getParameters();
         String[] selectedUsers =  params.getStrings(SELECTED_USER);
+        
         if (selectedUsers != null && selectedUsers.length > 0) 
         {
+            Issue issue = IssueManager.getInstance(issueId);
+            Module module = issue.getModule();
+            List<Attribute> attributeList = module.getUserAttributes(issue.getIssueType(), true);
             for (int i =0; i < selectedUsers.length; i++)
             {
                 String selectedUser = selectedUsers[i];
                 String userId = selectedUser.substring(1, selectedUser.indexOf('_')-1);
                 String attrId = selectedUser.substring(selectedUser.indexOf('_')+1, selectedUser.length());
-                Attribute attribute = AttributeManager
-                    .getInstance(new Integer(attrId));
-                ScarabUser su = ScarabUserManager
-                    .getInstance(new Integer(userId));
-                List item = new ArrayList(2);
-                List newItem = new ArrayList(2);
-                item.add(attribute);
-                item.add(su);
-                userList.remove(item);
+                Attribute attribute = AttributeManager.getInstance(new Integer(attrId));
+                ScarabUser su = ScarabUserManager.getInstance(new Integer(userId));
 
+                removeUserFromUserSet(su, attribute, userList);
+                
+                List newItem = new ArrayList(2);
                 String newKey = "asso_user_{" + userId + "}_attr_{" + attrId + "}_issue_{" + issueId + '}';
                 String newAttrId = params.get(newKey);
-                Attribute newAttribute = AttributeManager
-                     .getInstance(new Integer(newAttrId));
+                Attribute newAttribute = AttributeManager.getInstance(new Integer(newAttrId));
+                cleanupMultiAssignEntries(newAttribute, userList, attributeList);
+
                 newItem.add(newAttribute);
                 newItem.add(su);
+                
                 userList.add(newItem);
             }
             scarabR.setConfirmMessage(L10NKeySet.SelectedUsersWereModified);
@@ -556,3 +665,4 @@
     }
 
 }
+

Modified: trunk/src/java/org/tigris/scarab/om/AbstractScarabModule.java
Url: http://scarab.tigris.org/source/browse/scarab/trunk/src/java/org/tigris/scarab/om/AbstractScarabModule.java?view=diff&pathrev=10768&r1=10767&r2=10768
==============================================================================
--- trunk/src/java/org/tigris/scarab/om/AbstractScarabModule.java	(original)
+++ trunk/src/java/org/tigris/scarab/om/AbstractScarabModule.java	2009-07-03 11:19:26-0700
@@ -149,6 +149,8 @@
 
     /** set to true while the setInitialAttributesAndIssueTypes() method is in process */
     private boolean isInitializing = false;
+    
+    static private final List EmptyList = new ArrayList(); // to be used instead of null
 
     /**
      * Should be called when the parentage is modified.
@@ -1284,53 +1286,53 @@
     }
     
 
+    /**
+     * If no moduleOptions are available, this method returns a final EmptyList.
+     * @param attribute
+     * @param issueType
+     * @return
+     * @throws TorqueException
+     */
     private List getAllRModuleOptions(Attribute attribute, IssueType issueType)
         throws TorqueException
     {
-        if(attribute == null)
-        {
-          // during initilaization of a new query, no
-          // attributes are available.
-          // This check avoids a NLP
-          return null;
-        }
+        List rModOpts = EmptyList;
 
-        List rModOpts = null;
-        Object obj = getMethodResult().get(this, GET_ALL_R_MODULE_OPTIONS, 
-                                     attribute, issueType); 
-        if (obj == null) 
-        {        
-            List options = attribute.getAttributeOptions(true);
-            Integer[] optIds = null;
-            if (options == null)
-            {
-                optIds = new Integer[0];
-            }
-            else
+        if(attribute != null)
+        {
+            Object obj = getMethodResult().get(this, GET_ALL_R_MODULE_OPTIONS, attribute, issueType); 
+            if (obj == null)
             {
-                optIds = new Integer[options.size()];
+                List options = attribute.getAttributeOptions(true);
+                if (options != null && options.size() > 0)
+                {
+                    Integer[] optIds = new Integer[options.size()];
+                    for (int i=optIds.length-1; i>=0; i--)
+                    {
+                        optIds[i] = ((AttributeOption)options.get(i)).getOptionId();
+                    }
+    
+                    Criteria crit = new Criteria();
+                    crit.add(RModuleOptionPeer.ISSUE_TYPE_ID, issueType.getIssueTypeId());
+                    crit.add(RModuleOptionPeer.MODULE_ID, getModuleId());
+                    crit.addIn(RModuleOptionPeer.OPTION_ID, optIds);
+                    crit.addAscendingOrderByColumn(RModuleOptionPeer.PREFERRED_ORDER);
+                    crit.addAscendingOrderByColumn(RModuleOptionPeer.DISPLAY_VALUE);
+                    rModOpts = getRModuleOptions(crit);
+    
+                    // It would be extremely suspicious to see a null value here.
+                    assert (rModOpts != null); // for development 
+                    if(rModOpts == null)       // for production
+                    {
+                        rModOpts = EmptyList;
+                    }
+                }
+                getMethodResult().put(rModOpts, this, GET_ALL_R_MODULE_OPTIONS, attribute, issueType);
             }
-            for (int i=optIds.length-1; i>=0; i--)
+            else 
             {
-                optIds[i] = ((AttributeOption)options.get(i)).getOptionId();
+                rModOpts = (List)obj;
             }
-            
-            if (optIds.length > 0)
-            { 
-                Criteria crit = new Criteria();
-                crit.add(RModuleOptionPeer.ISSUE_TYPE_ID, issueType.getIssueTypeId());
-                crit.add(RModuleOptionPeer.MODULE_ID, getModuleId());
-                crit.addIn(RModuleOptionPeer.OPTION_ID, optIds);
-                crit.addAscendingOrderByColumn(RModuleOptionPeer.PREFERRED_ORDER);
-                crit.addAscendingOrderByColumn(RModuleOptionPeer.DISPLAY_VALUE);
-                rModOpts = getRModuleOptions(crit);
-            }
-            getMethodResult().put(rModOpts, this, GET_ALL_R_MODULE_OPTIONS, 
-                            attribute, issueType); 
-        }
-        else 
-        {
-            rModOpts = (List)obj;
         }
         return rModOpts;
     }

Modified: trunk/src/java/org/tigris/scarab/om/Attribute.java
Url: http://scarab.tigris.org/source/browse/scarab/trunk/src/java/org/tigris/scarab/om/Attribute.java?view=diff&pathrev=10768&r1=10767&r2=10768
==============================================================================
--- trunk/src/java/org/tigris/scarab/om/Attribute.java	(original)
+++ trunk/src/java/org/tigris/scarab/om/Attribute.java	2009-07-03 11:19:26-0700
@@ -722,6 +722,7 @@
         newAttribute.setCreatedBy(user.getUserId());
         newAttribute.setCreatedDate(new Date());
         newAttribute.setDeleted(getDeleted());
+        newAttribute.setMultiValue(getMultiValue());
         newAttribute.save();
 
         List attributeOptions = getAttributeOptions();
@@ -1088,5 +1089,20 @@
     	// Reuses existing cache-enabled method
     	return TransitionManager.getAllTransitions(this);
     }
+    
+    public boolean equals(Attribute other)
+    {
+        boolean result = super.equals(other);
+        
+        int oid = other.getAttributeId();
+        int tid = this.getAttributeId();
+        
+        if (result != (oid==tid))
+        {
+            int x=0; // very suspect...
+        }
+        
+        return result;
+    }
 
 }

Modified: trunk/src/java/org/tigris/scarab/om/AttributeValue.java
Url: http://scarab.tigris.org/source/browse/scarab/trunk/src/java/org/tigris/scarab/om/AttributeValue.java?view=diff&pathrev=10768&r1=10767&r2=10768
==============================================================================
--- trunk/src/java/org/tigris/scarab/om/AttributeValue.java	(original)
+++ trunk/src/java/org/tigris/scarab/om/AttributeValue.java	2009-07-03 11:19:26-0700
@@ -811,6 +811,13 @@
             .getNewInstance(getAttributeId(), getIssue());
         return copyInto(copyObj);
     }
+    
+    public AttributeValue copy(Connection con) throws TorqueException 
+    {
+        throw new RuntimeException("Unimplemented method AttributeValue:copy(Connection conn)");
+        //return copy();
+    }
+    
 
     public void save(Connection dbcon)
         throws TorqueException

Modified: trunk/src/java/org/tigris/scarab/om/ScarabUserImpl.java
Url: http://scarab.tigris.org/source/browse/scarab/trunk/src/java/org/tigris/scarab/om/ScarabUserImpl.java?view=diff&pathrev=10768&r1=10767&r2=10768
==============================================================================
--- trunk/src/java/org/tigris/scarab/om/ScarabUserImpl.java	(original)
+++ trunk/src/java/org/tigris/scarab/om/ScarabUserImpl.java	2009-07-03 11:19:26-0700
@@ -1280,5 +1280,18 @@
     {
         return ScarabUser.DELETED.equals(getConfirmed());
     }
+    
+    /**
+     * Needed to allow consistent List.remove(entry) behaviour
+     * @param other
+     * @return
+     */
+    public boolean equals(ScarabUser other)
+    {
+        int ouid = other.getUserId();
+        int uid  = getUserId();
+        
+        return (ouid == uid);
+    }
 
 }

Modified: trunk/src/schema/scarab-schema.xml
Url: http://scarab.tigris.org/source/browse/scarab/trunk/src/schema/scarab-schema.xml?view=diff&pathrev=10768&r1=10767&r2=10768
==============================================================================
--- trunk/src/schema/scarab-schema.xml	(original)
+++ trunk/src/schema/scarab-schema.xml	2009-07-03 11:19:26-0700
@@ -127,21 +127,22 @@
 		<column name="ATTACHMENT_TYPE_NAME" javaName="Name" required="true" type="VARCHAR" size="255" description="Name."/>
 		<column name="SEARCHABLE" default="0" type="BOOLEANINT" javaType="primitive" description="Flag marking text/searchable attachments"/>
 	</table>
-	<table name="SCARAB_ATTRIBUTE"    idMethod="idbroker" javaName="Attribute" description="Possible attributes of an issue. Example: Operating System. Example: Severity">
-		<column name="ATTRIBUTE_ID"   primaryKey="true"       required="true"  type="INTEGER" description="Unique identifier."/>
-        <column name="ATTRIBUTE_NAME" javaName="Name"         required="true"  type="VARCHAR" size="255" description="Name."/>
-		<column name="STYLE"          javaName="Style"        required="false" type="VARCHAR" size="255" description="optional string added as markup for css class or style information"/>
-        <column name="FORMAT"         javaName="Format"       required="false" type="VARCHAR" size="255" description="An optional Format String."/>
-        <column name="HINT"           javaName="Hint"         required="false" type="VARCHAR" size="255" description="An optional Hint string for the Format."/>
-        <column name="FIELDSIZE"      javaName="FieldSize"    required="false" type="INTEGER" default="0" description="Maximum size of Display field"/>
-        <column name="ATTRIBUTE_TYPE_ID" javaName="TypeId"    required="true"  type="INTEGER" description="Type."/>
-		<column name="PERMISSION"                             required="false" type="VARCHAR" size="255" description="A permission related to this attribute."/>
-		<column name="REQUIRED_OPTION_ID"                     required="false" type="INTEGER" description="A required option for this attribute to be active."/>
-		<column name="DESCRIPTION"     javaName="Description" required="true"  type="VARCHAR" size="255" description="Description."/>
-		<column name="ACTION"                                 required="false" type="VARCHAR" size="255" description="For user attributes, whether the user will be emailed, will get a mail as cc, or neither."/>
-		<column name="CREATED_BY"      javaName="CreatedBy"   required="false" type="INTEGER"    description="Person that set value to the column of the table initially."/>
-		<column name="CREATED_DATE"    javaName="CreatedDate" required="false" type="TIMESTAMP"  description="Date of the initial set of the column of the table."/>
-		<column name="DELETED"                                required="false" type="BOOLEANINT" default="0" javaType="primitive" description="Flag, which marks that attribute has been deleted."/>
+	<table name="SCARAB_ATTRIBUTE"       javaName="Attribute"   idMethod="idbroker" description="Possible attributes of an issue. Example: Operating System. Example: Severity">
+		<column name="ATTRIBUTE_ID"      primaryKey="true"      required="true"  type="INTEGER" description="Unique identifier."/>
+        <column name="ATTRIBUTE_NAME"    javaName="Name"        required="true"  type="VARCHAR" size="255" description="Name."/>
+		<column name="STYLE"             javaName="Style"       required="false" type="VARCHAR" size="255" description="optional string added as markup for css class or style information"/>
+        <column name="FORMAT"            javaName="Format"      required="false" type="VARCHAR" size="255" description="An optional Format String."/>
+        <column name="HINT"              javaName="Hint"        required="false" type="VARCHAR" size="255" description="An optional Hint string for the Format."/>
+        <column name="FIELDSIZE"         javaName="FieldSize"   required="false" type="INTEGER" default="0" description="Maximum size of Display field"/>
+        <column name="ATTRIBUTE_TYPE_ID" javaName="TypeId"      required="true"  type="INTEGER" description="Type."/>
+		<column name="PERMISSION"                               required="false" type="VARCHAR" size="255" description="A permission related to this attribute."/>
+		<column name="REQUIRED_OPTION_ID"                       required="false" type="INTEGER" description="A required option for this attribute to be active."/>
+		<column name="DESCRIPTION"       javaName="Description" required="true"  type="VARCHAR" size="255" description="Description."/>
+		<column name="ACTION"                                   required="false" type="VARCHAR" size="255" description="For user attributes, whether the user will be emailed, will get a mail as cc, or neither."/>
+		<column name="CREATED_BY"        javaName="CreatedBy"   required="false" type="INTEGER"    description="Person that set value to the column of the table initially."/>
+		<column name="CREATED_DATE"      javaName="CreatedDate" required="false" type="TIMESTAMP"  description="Date of the initial set of the column of the table."/>
+        <column name="MULTI_VALUE"       javaName="MultiValue"  required="false" type="BOOLEANINT" default="0" javaType="primitive" description="if set to true, the attribute may contain multiple values"/>
+		<column name="DELETED"                                  required="false" type="BOOLEANINT" default="0" javaType="primitive" description="Flag, which marks that attribute has been deleted."/>
 		<foreign-key foreignTable="SCARAB_ATTRIBUTE_TYPE">
 			<reference local="ATTRIBUTE_TYPE_ID" foreign="ATTRIBUTE_TYPE_ID"/>
 		</foreign-key>

Modified: trunk/src/sql/upgrade/upgrade-0.23-attribute.sql
Url: http://scarab.tigris.org/source/browse/scarab/trunk/src/sql/upgrade/upgrade-0.23-attribute.sql?view=diff&pathrev=10768&r1=10767&r2=10768
==============================================================================
--- trunk/src/sql/upgrade/upgrade-0.23-attribute.sql	(original)
+++ trunk/src/sql/upgrade/upgrade-0.23-attribute.sql	2009-07-03 11:19:26-0700
@@ -16,4 +16,4 @@
 ALTER TABLE SCARAB_ATTRIBUTE ADD ( FORMAT VARCHAR(255) );
 ALTER TABLE SCARAB_ATTRIBUTE ADD ( HINT VARCHAR(255) );
 ALTER TABLE SCARAB_ATTRIBUTE ADD ( FIELDSIZE INTEGER );
-
+ALTER TABLE SCARAB_ATTRIBUTE ADD ( MULTI_VALUE INTEGER NOT NULL DEFAULT 0); 

Modified: trunk/src/webapp/WEB-INF/templates/screens/admin/ModuleAttributeEdit.vm
Url: http://scarab.tigris.org/source/browse/scarab/trunk/src/webapp/WEB-INF/templates/screens/admin/ModuleAttributeEdit.vm?view=diff&pathrev=10768&r1=10767&r2=10768
==============================================================================
--- trunk/src/webapp/WEB-INF/templates/screens/admin/ModuleAttributeEdit.vm	(original)
+++ trunk/src/webapp/WEB-INF/templates/screens/admin/ModuleAttributeEdit.vm	2009-07-03 11:19:26-0700
@@ -58,6 +58,15 @@
     $format.getDate($scarabR.DateFormat, $attribute.CreatedDate)
   </td>
  </tr>
+ 
+  <tr>
+  <th>Multi Value </th>
+  <td>attribute.MultiValue</td>
+ </tr>
+ 
+ 
+ 
+ 
 #if (!$attribute.isUserAttribute())
 <tr>
   <th>$l10n.AlwaysRequired</th>

Modified: trunk/src/webapp/WEB-INF/templates/screens/admin/UserAttributeEdit.vm
Url: http://scarab.tigris.org/source/browse/scarab/trunk/src/webapp/WEB-INF/templates/screens/admin/UserAttributeEdit.vm?view=diff&pathrev=10768&r1=10767&r2=10768
==============================================================================
--- trunk/src/webapp/WEB-INF/templates/screens/admin/UserAttributeEdit.vm	(original)
+++ trunk/src/webapp/WEB-INF/templates/screens/admin/UserAttributeEdit.vm	2009-07-03 11:19:26-0700
@@ -114,6 +114,17 @@
 <h3>$l10n.UserAttributeProperties</h3>
 <div class="axial">
 <table width="100%" cellpadding="3" cellspacing="2" border="1">
+
+
+<tr>
+  <th>Multiple Instances</th>
+  #if(!$immutable)
+  <td>#booleanCheckbox ($attgroup.MultiValue)</td>
+  #else
+  <td>#booleanCheckboxLock ($attgroup.MultiValue $immutable)</td>
+  #end
+</tr>
+
 <tr>
   <th width="120">* $l10n.EmailAction</th> 
   <td class="b">

Modified: trunk/src/webapp/WEB-INF/templates/viewIssue/ViewIssueTab2.vm
Url: http://scarab.tigris.org/source/browse/scarab/trunk/src/webapp/WEB-INF/templates/viewIssue/ViewIssueTab2.vm?view=diff&pathrev=10768&r1=10767&r2=10768
==============================================================================
--- trunk/src/webapp/WEB-INF/templates/viewIssue/ViewIssueTab2.vm	(original)
+++ trunk/src/webapp/WEB-INF/templates/viewIssue/ViewIssueTab2.vm	2009-07-03 11:19:26-0700
@@ -23,6 +23,7 @@
       #set ($assignedUser = $scarabR.getUser($userId))
       #if  ($data.User.userId.equals($userId))
         #set ($myselfInList = true)
+        #set ($myattid = $attVal.AttributeId)
       #end
       <td>
         <a href="mailto:$assignedUser.Email">$!assignedUser.Name</a>
@@ -62,15 +63,44 @@
    ##<input type="submit" value="$l10n.DeleteSelected" name="eventSubmit_doUnassign" />&#160;
    #if ($scarabR.hasPermission($scarabG.Permission.ISSUE__ASSIGN, $module))
     <input type="submit" value="$l10n.EditList" name="eventSubmit_doEditassignees" />&nbsp;
-    <input type="submit" name="eventSubmit_doAddmyself" value="$l10n.AssignMyself" />
-    <select name="myself_attribute">
-     #foreach ($selectUserAttr in $module.getUserAttributes($currentIssue.issueType))
-      #if ($!data.User.hasPermission($selectUserAttr.Permission, $module))
+
+    ## ============================================================================
+    ## Find all selectable User Attributes in the given context.
+    ## Note: If a userAttribute/user combination is allready in the list, 
+    ## it can not be selected anymore here.
+    ## ============================================================================
+    #set ($options = [] )
+    #foreach ($selectUserAttr in $module.getUserAttributes($currentIssue.issueType))
+     #if ($!data.User.hasPermission($selectUserAttr.Permission, $module))
+       #set ($attid = $selectUserAttr.AttributeId)
+       #if ($myattid != $attid) ## if this attribute/user is already in list, discard it
+         #set ($selectUserAttrName = $module.getRModuleAttribute($selectUserAttr,$currentIssue.issueType).displayValue)
+         #set ($dummy = $options.add($selectUserAttr))
+       #end
+     #end
+    #end
+
+    #if ( $options.size() == 1)
+      ## Just create a button. We do not need a selector box in this case.
+      #foreach ($selectUserAttr in $options)
+        #set ($attid = $selectUserAttr.AttributeId)
         #set ($selectUserAttrName = $module.getRModuleAttribute($selectUserAttr,$currentIssue.issueType).displayValue)
-        <option value="$selectUserAttr.AttributeId">$selectUserAttrName:</option>
+        <input type="hidden" name="myself_attribute" value="$selectUserAttr.AttributeId"/>
+        <input type="submit" name="eventSubmit_doAddmyself" value="$l10n.AssignMyself $selectUserAttrName" />
       #end
-     #end
-    </select>
+         
+    #elseif ( $options.size() > 1 )
+      ## Create a selection box
+      <input type="submit" name="eventSubmit_doAddmyself" value="$l10n.AssignMyself" />
+      <select name="myself_attribute">
+        #foreach ($selectUserAttr in $options)
+          #set ($attid = $selectUserAttr.AttributeId)
+          #set ($selectUserAttrName = $module.getRModuleAttribute($selectUserAttr,$currentIssue.issueType).displayValue)
+          <option value="$selectUserAttr.AttributeId">$selectUserAttrName</option>
+        #end
+      </select>
+    #end
+    
     #if ($myselfInList)
       <input type="submit" name="eventSubmit_doRemovemyself" value="$l10n.RemoveMe" />
     #end

------------------------------------------------------
http://scarab.tigris.org/ds/viewMessage.do?dsForumId=3577&dsMessageId=2367862
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.