diff --git a/src/main/java/org/olat/admin/user/groups/GroupOverviewController.java b/src/main/java/org/olat/admin/user/groups/GroupOverviewController.java
index 976ea5ba07449ac545dc6b62aa9b2768a9122371..567cbbab6934eb03974c9d9fe5b7e2d4f785a12c 100644
--- a/src/main/java/org/olat/admin/user/groups/GroupOverviewController.java
+++ b/src/main/java/org/olat/admin/user/groups/GroupOverviewController.java
@@ -21,11 +21,9 @@ package org.olat.admin.user.groups;
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.Iterator;
+import java.util.HashMap;
 import java.util.List;
-import java.util.Set;
+import java.util.Map;
 
 import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.BaseSecurityManager;
@@ -35,8 +33,11 @@ import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.link.Link;
 import org.olat.core.gui.components.link.LinkFactory;
+import org.olat.core.gui.components.table.BooleanColumnDescriptor;
+import org.olat.core.gui.components.table.ColumnDescriptor;
+import org.olat.core.gui.components.table.CustomCellRenderer;
+import org.olat.core.gui.components.table.CustomRenderColumnDescriptor;
 import org.olat.core.gui.components.table.DefaultColumnDescriptor;
-import org.olat.core.gui.components.table.StaticColumnDescriptor;
 import org.olat.core.gui.components.table.Table;
 import org.olat.core.gui.components.table.TableController;
 import org.olat.core.gui.components.table.TableEvent;
@@ -58,11 +59,17 @@ import org.olat.core.util.mail.MailerResult;
 import org.olat.core.util.mail.MailerWithTemplate;
 import org.olat.core.util.notifications.NotificationHelper;
 import org.olat.group.BusinessGroup;
+import org.olat.group.BusinessGroupMembership;
 import org.olat.group.BusinessGroupService;
 import org.olat.group.model.AddToGroupsEvent;
+import org.olat.group.model.BGMembership;
+import org.olat.group.model.SearchBusinessGroupParams;
 import org.olat.group.ui.BGControllerFactory;
 import org.olat.group.ui.BGMailHelper;
-import org.olat.group.ui.BusinessGroupTableModel;
+import org.olat.group.ui.main.BGRoleCellRenderer;
+import org.olat.group.ui.main.BGTableItem;
+import org.olat.group.ui.main.BusinessGroupTableModelWithType;
+import org.olat.group.ui.main.BusinessGroupTableModelWithType.Cols;
 
 /**
  * Description:<br>
@@ -77,9 +84,8 @@ import org.olat.group.ui.BusinessGroupTableModel;
 public class GroupOverviewController extends BasicController {
 	private static final String TABLE_ACTION_UNSUBSCRIBE = "unsubscribe";
 	private VelocityContainer vc;
-	private TableController tblCtr;
-	private GroupOverviewModel tableDataModel;
-	private WindowControl wControl;
+	private TableController groupListCtr;
+	private BusinessGroupTableModelWithType tableDataModel;
 	private Identity identity;
 	private Link addGroups;
 	private CloseableModalWindowWrapperController calloutCtrl;
@@ -88,13 +94,15 @@ public class GroupOverviewController extends BasicController {
 	private DialogBoxController sendMailDlg;
 	private static String TABLE_ACTION_LAUNCH ;
 	
+	private final BaseSecurity securityManager;
 	private final BusinessGroupService businessGroupService;
 
 	public GroupOverviewController(UserRequest ureq, WindowControl control, Identity identity, Boolean canStartGroups) {
-		super(ureq, control, Util.createPackageTranslator(BusinessGroupTableModel.class, ureq.getLocale()));
-		this.wControl = control;
-		this.identity = identity;
+		super(ureq, control, Util.createPackageTranslator(BusinessGroupTableModelWithType.class, ureq.getLocale()));
 		
+		this.identity = identity;
+	
+		securityManager = BaseSecurityManager.getInstance();
 		businessGroupService = CoreSpringFactory.getImpl(BusinessGroupService.class);
 		if (canStartGroups){
 			TABLE_ACTION_LAUNCH = "bgTblLaunch";
@@ -103,9 +111,27 @@ public class GroupOverviewController extends BasicController {
 		}		
 		
 		vc = createVelocityContainer("groupoverview");
-		buildTableController(ureq, control); 
+		
+		groupListCtr = new TableController(null, ureq, control, getTranslator());
+		listenTo(groupListCtr);
+		
+		groupListCtr.addColumnDescriptor(new DefaultColumnDescriptor(Cols.name.i18n(), Cols.name.ordinal(), TABLE_ACTION_LAUNCH, ureq.getLocale()));
+		groupListCtr.addColumnDescriptor(false, new DefaultColumnDescriptor(Cols.key.i18n(), Cols.key.ordinal(), null, getLocale()));
+		groupListCtr.addColumnDescriptor(new DefaultColumnDescriptor(Cols.firstTime.i18n(), Cols.firstTime.ordinal(), null, getLocale()));
+		groupListCtr.addColumnDescriptor(new DefaultColumnDescriptor(Cols.lastTime.i18n(), Cols.lastTime.ordinal(), null, getLocale()));
+		CustomCellRenderer roleRenderer = new BGRoleCellRenderer(getLocale());
+		groupListCtr.addColumnDescriptor(new CustomRenderColumnDescriptor(Cols.role.i18n(), Cols.role.ordinal(), null, getLocale(),  ColumnDescriptor.ALIGNMENT_LEFT, roleRenderer));
+		groupListCtr.addColumnDescriptor(new BooleanColumnDescriptor(Cols.allowLeave.i18n(), Cols.allowLeave.ordinal(), TABLE_ACTION_UNSUBSCRIBE, translate("table.header.leave"), null));
+		
+		groupListCtr.setMultiSelect(true);
+		groupListCtr.addMultiSelectAction("table.leave", TABLE_ACTION_UNSUBSCRIBE);
+		tableDataModel = new BusinessGroupTableModelWithType(getTranslator(), 4);
+		groupListCtr.setTableDataModel(tableDataModel);
+		
+		updateModel(ureq);
+		
 		addGroups = LinkFactory.createButton("add.groups", vc, this);		
-		vc.put("table.groups", tblCtr.getInitialComponent());	
+		vc.put("table.groups", groupListCtr.getInitialComponent());	
 		putInitialPanel(vc);
 	}
 
@@ -115,65 +141,47 @@ public class GroupOverviewController extends BasicController {
 	 * @param identity
 	 * @return
 	 */
-	private void buildTableController(UserRequest ureq, WindowControl control) {
-		
-		removeAsListenerAndDispose(tblCtr);
-		tblCtr = new TableController(null, ureq, control, getTranslator());
-		listenTo(tblCtr);
-		
-		tblCtr.addColumnDescriptor(new DefaultColumnDescriptor("table.group.type", 0, null, ureq.getLocale()));
-		tblCtr.addColumnDescriptor(new DefaultColumnDescriptor("table.group.name", 1, TABLE_ACTION_LAUNCH, ureq.getLocale()));
-		tblCtr.addColumnDescriptor(new DefaultColumnDescriptor("table.user.role", 2, null, ureq.getLocale()));
-		tblCtr.addColumnDescriptor(new DefaultColumnDescriptor("table.user.joindate", 3, null, ureq.getLocale()));
-		tblCtr.addColumnDescriptor(new StaticColumnDescriptor(TABLE_ACTION_UNSUBSCRIBE, "table.user.unsubscribe", translate("table.user.unsubscribe")));
-
-		//build data model
-
-		BaseSecurity sm = BaseSecurityManager.getInstance();
-		List<Object[]> userGroups = new ArrayList<Object[]>();
-		//loop over all kind of groups with all possible memberships
-
-
-		List<BusinessGroup> ownedGroups = businessGroupService.findBusinessGroupsOwnedBy(identity, null);
-		List<BusinessGroup> attendedGroups = businessGroupService.findBusinessGroupsAttendedBy(identity, null);
-		List<BusinessGroup> waitingGroups = businessGroupService.findBusinessGroupsWithWaitingListAttendedBy(identity, null);
-		//using HashSet to remove duplicate entries
-		Set<BusinessGroup> allGroups = new HashSet<BusinessGroup>();
-		allGroups.addAll(ownedGroups);
-		allGroups.addAll(attendedGroups);
-		allGroups.addAll(waitingGroups);
-		
-		Iterator<BusinessGroup> iter = allGroups.iterator();
-		while (iter.hasNext()) {
-			Object[] groupEntry = new Object[4];
-			BusinessGroup group = iter.next();
-			groupEntry[0] = translate(group.getType());
-			groupEntry[1] = group;
-			Date joinDate = null;
-			if(attendedGroups.contains(group)&&ownedGroups.contains(group)) {
-				groupEntry[2] = translate("attende.and.owner");
-				joinDate = sm.getSecurityGroupJoinDateForIdentity(group.getPartipiciantGroup(), identity);
+	private void updateModel(UserRequest ureq) {
+		SearchBusinessGroupParams params = new SearchBusinessGroupParams();
+		params.setIdentity(identity);
+		params.setOwner(true);
+		params.setAttendee(true);
+		params.setWaiting(true);
+		List<BusinessGroup> groups = businessGroupService.findBusinessGroups(params, null, 0, -1);
+		List<Long> groupKeysWithMembers;
+		if(groups.size() > 50) {
+			groupKeysWithMembers = null;
+		} else {
+			groupKeysWithMembers = new ArrayList<Long>(groups.size());
+			for(BusinessGroup view:groups) {
+				groupKeysWithMembers.add(view.getKey());
 			}
-			else if(attendedGroups.contains(group)) {
-				groupEntry[2] = translate("attende");
-				joinDate = sm.getSecurityGroupJoinDateForIdentity(group.getPartipiciantGroup(), identity);
+		}
+
+		//retrieve all user's membership if there are more than 50 groups
+		List<BusinessGroupMembership> groupsAsOwner = businessGroupService.getBusinessGroupMembership(identity, groupKeysWithMembers);
+		Map<Long, BusinessGroupMembership> memberships = new HashMap<Long, BusinessGroupMembership>();
+		for(BusinessGroupMembership membership: groupsAsOwner) {
+			if(membership.getOwnerGroupKey() != null) {
+				memberships.put(membership.getOwnerGroupKey(), membership);
 			}
-			else if(ownedGroups.contains(group)) {
-				groupEntry[2] = translate("owner");
-				joinDate = sm.getSecurityGroupJoinDateForIdentity(group.getOwnerGroup(), identity);
+			if(membership.getParticipantGroupKey() != null) {
+				memberships.put(membership.getParticipantGroupKey(), membership);
 			}
-			else if(waitingGroups.contains(group)) {
-				int waitingListPosition = businessGroupService.getPositionInWaitingListFor(identity, group);
-				groupEntry[2] = translate("waiting", String.valueOf(waitingListPosition));
-				joinDate = sm.getSecurityGroupJoinDateForIdentity(group.getWaitingGroup(), identity);
+			if(membership.getWaitingGroupKey() != null) {
+				memberships.put(membership.getWaitingGroupKey(), membership);
 			}
-			groupEntry[3] = joinDate;
-			
-			userGroups.add(groupEntry);
-		}			
+		}
 
-		tableDataModel = new GroupOverviewModel(userGroups, 4);
-		tblCtr.setTableDataModel(tableDataModel);
+		List<BGTableItem> items = new ArrayList<BGTableItem>();
+		for(BusinessGroup group:groups) {
+			BusinessGroupMembership membership =  memberships.get(group.getKey());
+			BGMembership member = membership == null ? null : membership.getMembership();
+			BGTableItem tableItem = new BGTableItem(group, false, member, Boolean.TRUE, Boolean.FALSE, null);
+			items.add(tableItem);
+		}
+		tableDataModel.setEntries(items, memberships);
+		groupListCtr.modelChanged();
 	}
 
 	/**
@@ -207,31 +215,28 @@ public class GroupOverviewController extends BasicController {
 	@Override
 	protected void event(UserRequest ureq, Controller source, Event event) {
 		super.event(ureq, source, event);
-		if (source == tblCtr){
+		if (source == groupListCtr){
 			if (event.getCommand().equals(Table.COMMANDLINK_ROWACTION_CLICKED)) {
 				TableEvent te = (TableEvent) event;
 				String actionid = te.getActionId();
 				int rowid = te.getRowId();
-				BusinessGroup currBusinessGroup = tableDataModel.getBusinessGroupAtRow(rowid);
-				if (actionid.equals(TABLE_ACTION_LAUNCH)) {
-					currBusinessGroup = CoreSpringFactory.getImpl(BusinessGroupService.class).loadBusinessGroup(currBusinessGroup);
-					if (currBusinessGroup==null) {
-						//group seems to be removed meanwhile, reload table and show error
-						showError("group.removed");
-						updateGroupsTable(ureq);	
-					}
-					else {
-						BGControllerFactory.getInstance().createRunControllerAsTopNavTab(currBusinessGroup, ureq, getWindowControl());
-					}
+				BGTableItem item = tableDataModel.getObject(rowid);
+				BusinessGroup currBusinessGroup = businessGroupService.loadBusinessGroup(item.getBusinessGroupKey());
+				if (currBusinessGroup==null) {
+					//group seems to be removed meanwhile, reload table and show error
+					showError("group.removed");
+					updateModel(ureq);	
+				} else if (actionid.equals(TABLE_ACTION_LAUNCH)) {
+					BGControllerFactory.getInstance().createRunControllerAsTopNavTab(currBusinessGroup, ureq, getWindowControl());
 				} else if (actionid.equals(TABLE_ACTION_UNSUBSCRIBE)){
 					// fxdiff: FXOLAT-101 see similar doBuddyGroupLeave() in BGMainController
 					String groupName = currBusinessGroup.getName();
-					BaseSecurity securityManager = BaseSecurityManager.getInstance();
-					List<Identity> ownerList = securityManager.getIdentitiesOfSecurityGroup(currBusinessGroup.getOwnerGroup());
-					List<Identity> partList = securityManager.getIdentitiesOfSecurityGroup(currBusinessGroup.getPartipiciantGroup());
+					
+					int numOfOwners = securityManager.countIdentitiesOfSecurityGroup(currBusinessGroup.getOwnerGroup());
+					int numOfParticipants = securityManager.countIdentitiesOfSecurityGroup(currBusinessGroup.getPartipiciantGroup());
 					
 					String rmText = translate("unsubscribe.text", new String[]{NotificationHelper.getFormatedName(identity), groupName});
-					if ((ownerList.size() == 1 && partList.size() == 0) || (ownerList.size() == 0 && partList.size() == 1)) {
+					if ((numOfOwners == 1 && numOfParticipants == 0) || (numOfOwners == 0 && numOfParticipants == 1)) {
 						rmText += " <br/>" + translate("unsubscribe.group.del");
 					}
 					removeFromGrpDlg = activateYesNoDialog(ureq, translate("unsubscribe.title"), rmText, removeFromGrpDlg);
@@ -252,7 +257,7 @@ public class GroupOverviewController extends BasicController {
 				} else {		
 					showWarning("group.add.result.none");
 				}
-				updateGroupsTable(ureq);
+				updateModel(ureq);
 			}			
 		} else if (source == removeFromGrpDlg && DialogBoxUIFactory.isYesEvent(event)){
 			//fxdiff: FXOLAT-138 let user decide to send notif-mail or not
@@ -263,7 +268,6 @@ public class GroupOverviewController extends BasicController {
 			else
 				removeUserFromGroup(ureq, false);
 		}
-			
 	}
 
 	/**
@@ -308,23 +312,11 @@ public class GroupOverviewController extends BasicController {
 				MailTemplate mailTemplate = BGMailHelper.createRemoveParticipantMailTemplate(currBusinessGroup, getIdentity());
 				MailerWithTemplate mailer = MailerWithTemplate.getInstance();
 				MailerResult mailerResult = mailer.sendMail(null, identity, null, null, mailTemplate, null);
-				MailHelper.printErrorsAndWarnings(mailerResult, wControl, getLocale());
+				MailHelper.printErrorsAndWarnings(mailerResult, getWindowControl(), getLocale());
 			}
 		}
 
-		updateGroupsTable(ureq);
+		updateModel(ureq);
 		showInfo("unsubscribe.successful", groupName);	
 	}
-	
-	/**
-	 * @param ureq
-	 * update Table
-	 */
-	private void updateGroupsTable(UserRequest ureq) {
-		buildTableController(ureq, wControl); 
-		vc.put("table.groups", tblCtr.getInitialComponent());
-	}
-
-
-	
 }
diff --git a/src/main/java/org/olat/admin/user/groups/GroupOverviewModel.java b/src/main/java/org/olat/admin/user/groups/GroupOverviewModel.java
deleted file mode 100644
index 2f97e3b750c2ba062ab6648e3096caa20d7be0a9..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/admin/user/groups/GroupOverviewModel.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/**
- * <a href="http://www.openolat.org">
- * OpenOLAT - Online Learning and Training</a><br>
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License"); <br>
- * you may not use this file except in compliance with the License.<br>
- * You may obtain a copy of the License at the
- * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
- * <p>
- * Unless required by applicable law or agreed to in writing,<br>
- * software distributed under the License is distributed on an "AS IS" BASIS, <br>
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
- * See the License for the specific language governing permissions and <br>
- * limitations under the License.
- * <p>
- * Initial code contributed and copyrighted by<br>
- * frentix GmbH, http://www.frentix.com
- * <p>
- */
-package org.olat.admin.user.groups;
-
-import java.util.Date;
-import java.util.List;
-
-import org.apache.commons.lang.StringEscapeUtils;
-import org.olat.core.gui.components.table.DefaultTableDataModel;
-import org.olat.group.BusinessGroup;
-
-/**
- * model for details about a group an user is in.
- * Details are: type of group, groupname, 
- * role of user in group (participant, owner, on waiting list), date of joining the group 
- */
-class GroupOverviewModel extends DefaultTableDataModel {
-	
-	private int columnCount = 0;
-	/**
-	 * @param objects
-	 */
-	public GroupOverviewModel(List<Object[]> objects, int columnCount) {
-		super(objects);
-		this.columnCount = columnCount;
-	}
-
-	/**
-	 * @see org.olat.core.gui.components.table.DefaultTableDataModel#getColumnCount()
-	 */
-	@Override
-	public int getColumnCount() {
-		return columnCount;
-	}
-
-	/**
-	 * @see org.olat.core.gui.components.table.DefaultTableDataModel#getValueAt(int, int)
-	 */
-	@Override
-	public Object getValueAt(int row, int col) {
-		Object o = getObject(row);
-		Object[] dataArray = null;
-		dataArray = (Object[]) o;
-		
-		Object groupColItem = dataArray[col];
-		
-		switch (col) {
-			case 0: 
-				return groupColItem;
-			case 1: 
-				String name = ((BusinessGroup) groupColItem).getName();
-				name = StringEscapeUtils.escapeHtml(name).toString();
-				return name;
-			case 2: 
-				return groupColItem;
-			case 3:
-				return (Date)groupColItem;
-			default: 
-				return "error";
-		}
-	}
-	
-/**
- * method to get the BusinessGroup-Object which is in the model, but 
- * getValueAt() would only return the name of the group.
- * @param row 
- * @return BusinessGroup from a certain row in model
- */
-	protected BusinessGroup getBusinessGroupAtRow(int row) {
-		Object o = getObject(row);
-		Object[] dataArray = null;
-		dataArray = (Object[]) o;
-		return (BusinessGroup) dataArray[1];
-	}
-
-}
diff --git a/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_de.properties
index 09ced2e0736228dd034227fa83a00286c8238f75..56a3d42120ca81a5b282082c60b572be1667f4d6 100644
--- a/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_de.properties
@@ -87,6 +87,7 @@ table.duplicate=Douplizieren
 table.merge=Zusammenführen
 table.users.management=Benutzer verwalten
 table.config=Konfigurieren
+table.leave=Verlassen
 tools.add.buddygroup=Arbeitsgruppe
 tools.add.header=Erstellen
 tools.delete.header=L\u00F6schen