Index: trunk/app/controllers/members_controller.rb
===================================================================
--- trunk/app/controllers/members_controller.rb	(revision 2634)
+++ trunk/app/controllers/members_controller.rb	(revision 2635)
@@ -21,10 +21,26 @@
   before_filter :authorize
 
   def new
-    @project.members << Member.new(params[:member]) if request.post?
+    members = []
+    if params[:member] && request.post?
+      attrs = params[:member].dup
+      if (user_ids = attrs.delete(:user_ids))
+        user_ids.each do |user_id|
+          members << Member.new(attrs.merge(:user_id => user_id))
+        end
+      else
+        members << Member.new(attrs)
+      end
+      @project.members << members
+    end
     respond_to do |format|
       format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }
-      format.js { render(:update) {|page| page.replace_html "tab-content-members", :partial => 'projects/settings/members'} }
+      format.js { 
+        render(:update) {|page| 
+          page.replace_html "tab-content-members", :partial => 'projects/settings/members'
+          members.each {|member| page.visual_effect(:highlight, "member-#{member.id}") }
+        }
+      }
     end
   end
   
Index: trunk/app/views/projects/settings/_members.rhtml
===================================================================
--- trunk/app/views/projects/settings/_members.rhtml	(revision 2634)
+++ trunk/app/views/projects/settings/_members.rhtml	(revision 2635)
@@ -3,7 +3,8 @@
 <% users = User.active.find(:all).sort - @project.users %>
 <% # members sorted by role position
    members = @project.members.find(:all, :include => [:role, :user]).sort %>
-   
+
+<div class="splitcontentleft">
 <% if members.any? %>
 <table class="list">
 	<thead>
@@ -15,7 +16,7 @@
 	<tbody>
 	<% members.each do |member| %>
 	<% next if member.new_record? %>
-	<tr class="<%= cycle 'odd', 'even' %>">
+	<tr id="member-<%= member.id %>" class="<%= cycle 'odd', 'even' %>">
 	<td><%= member.name %></td>
     <td align="center">
     <% if authorize_for('members', 'edit') %>
@@ -39,12 +40,20 @@
 <% else %>
 <p class="nodata"><%= l(:label_no_data) %></p>
 <% end %>
+</div>
 
-<% if authorize_for('members', 'new') && !users.empty? %>
+<div class="splitcontentright">
+<% if !users.empty? %>
   <% remote_form_for(:member, @member, :url => {:controller => 'members', :action => 'new', :id => @project}, :method => :post) do |f| %>
-    <p><label for="member_user_id"><%=l(:label_member_new)%></label><br />
-    <%= f.select :user_id, users.collect{|user| [user.name, user.id]} %>
-    <%= l(:label_role) %>: <%= f.select :role_id, roles.collect{|role| [role.name, role.id]}, :selected => nil %>
+    <fieldset><legend><%=l(:label_member_new)%></legend>
+		<div>
+		<% users.each do |user| -%>
+		<label><%= check_box_tag 'member[user_ids][]', user.id, false %> <%= user %></label>
+		<% end -%>
+		</div>
+    <p><%= l(:label_role) %>: <%= f.select :role_id, roles.collect{|role| [role.name, role.id]}, :selected => nil %>
     <%= submit_tag l(:button_add) %></p>
+		</fieldset>
   <% end %>
 <% end %>
+</div>
Index: trunk/public/stylesheets/application.css
===================================================================
--- trunk/public/stylesheets/application.css	(revision 2634)
+++ trunk/public/stylesheets/application.css	(revision 2635)
@@ -324,6 +324,16 @@
 
 a.atom { background: url(../images/feed.png) no-repeat 1px 50%; padding: 2px 0px 3px 16px; }
 
+/* Project members tab */
+div#tab-content-members .splitcontentleft { width: 64% }
+div#tab-content-members .splitcontentright { width: 34% }
+div#tab-content-members fieldset { margin-top: -8px; padding-top:0.6em; margin-bottom: 1em; }
+div#tab-content-members fieldset legend { font-weight: bold; }
+div#tab-content-members fieldset label { display: block; }
+div#tab-content-members fieldset div { max-height: 400px; overflow:auto; }
+
+* html div#tab-content-members fieldset div { height: 450px; }
+
 /***** Flash & error messages ****/
 #errorExplanation, div.flash, .nodata, .warning {
     padding: 4px 4px 4px 30px;
Index: trunk/test/fixtures/users.yml
===================================================================
--- trunk/test/fixtures/users.yml	(revision 2634)
+++ trunk/test/fixtures/users.yml	(revision 2635)
@@ -112,5 +112,37 @@
   mail_notification: false
   login: someone
   type: User
+users_008: 
+  id: 8
+  created_on: 2006-07-19 19:33:19 +02:00
+  status: 1
+  last_login_on: 
+  language: 'it'
+  hashed_password: 1
+  updated_on: 2006-07-19 19:33:19 +02:00
+  admin: false
+  mail: miscuser8@foo.bar
+  lastname: Misc
+  firstname: User
+  auth_source_id: 
+  mail_notification: false
+  login: miscuser8
+  type: User
+users_009: 
+  id: 9
+  created_on: 2006-07-19 19:33:19 +02:00
+  status: 1
+  last_login_on: 
+  language: 'it'
+  hashed_password: 1
+  updated_on: 2006-07-19 19:33:19 +02:00
+  admin: false
+  mail: miscuser9@foo.bar
+  lastname: Misc
+  firstname: User
+  auth_source_id: 
+  mail_notification: false
+  login: miscuser9
+  type: User
 
   
\ No newline at end of file
Index: trunk/test/functional/members_controller_test.rb
===================================================================
--- trunk/test/functional/members_controller_test.rb	(revision 2634)
+++ trunk/test/functional/members_controller_test.rb	(revision 2635)
@@ -40,7 +40,7 @@
     )
   end
   
-  def test_new
+  def test_create
     assert_difference 'Member.count' do
       post :new, :id => 1, :member => {:role_id => 1, :user_id => 7}
     end
@@ -48,6 +48,14 @@
     assert User.find(7).member_of?(Project.find(1))
   end
   
+  def test_create_multiple
+    assert_difference 'Member.count', 3 do
+      post :new, :id => 1, :member => {:role_id => 1, :user_ids => [7, 8, 9]}
+    end
+    assert_redirected_to '/projects/ecookbook/settings/members'
+    assert User.find(7).member_of?(Project.find(1))
+  end
+  
   def test_edit
     assert_no_difference 'Member.count' do
       post :edit, :id => 2, :member => {:role_id => 1, :user_id => 3}
