From 660cbb3b169971a2ec340c94f3bbf10ee6578e1a Mon Sep 17 00:00:00 2001
From: srosse <none@none>
Date: Fri, 26 Aug 2016 08:33:02 +0200
Subject: [PATCH] OO-2160: reload after change on repository entries like
 favorit, delete...

---
 .../olat/course/editor/PublishProcess.java    |  2 +-
 .../course/run/CourseRuntimeController.java   | 12 +++--
 .../qpool/ui/QuestionListController.java      |  2 +-
 .../olat/repository/RepositoryService.java    |  4 ++
 .../controllers/EntryChangedEvent.java        | 44 +++++++++++++-----
 .../RepositorySearchController.java           |  3 +-
 .../repository/manager/CatalogManager.java    |  2 +-
 ...ositoryEntryLifeCycleChangeController.java |  4 ++
 .../ui/RepositoryEntryRuntimeController.java  | 41 +++++++++++++++--
 .../ui/author/AuthorListController.java       | 36 ++++++++++++---
 .../author/AuthoringEditAccessController.java |  4 +-
 .../ui/author/ConfirmDeleteController.java    |  2 +-
 .../CreateRepositoryEntryController.java      |  2 +-
 .../author/OverviewAuthoringController.java   | 46 +++++++++++++++++--
 .../OverviewRepositoryListController.java     | 41 ++++++++++++++++-
 .../list/RepositoryEntryListController.java   | 20 +++++++-
 16 files changed, 222 insertions(+), 43 deletions(-)

diff --git a/src/main/java/org/olat/course/editor/PublishProcess.java b/src/main/java/org/olat/course/editor/PublishProcess.java
index 6480430d410..0298ee8b52e 100644
--- a/src/main/java/org/olat/course/editor/PublishProcess.java
+++ b/src/main/java/org/olat/course/editor/PublishProcess.java
@@ -703,7 +703,7 @@ public class PublishProcess {
 
 	public void changeGeneralAccess(Identity author, int access, boolean membersOnly){
 		RepositoryManager.getInstance().setAccess(repositoryEntry, access, membersOnly);
-		MultiUserEvent modifiedEvent = new EntryChangedEvent(repositoryEntry, author, Change.modifiedAtPublish);
+		MultiUserEvent modifiedEvent = new EntryChangedEvent(repositoryEntry, author, Change.modifiedAtPublish, "publish");
 		CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(modifiedEvent, repositoryEntry);
 	}
 	
diff --git a/src/main/java/org/olat/course/run/CourseRuntimeController.java b/src/main/java/org/olat/course/run/CourseRuntimeController.java
index 67d8b9b1c58..e3cfc51f2e2 100644
--- a/src/main/java/org/olat/course/run/CourseRuntimeController.java
+++ b/src/main/java/org/olat/course/run/CourseRuntimeController.java
@@ -719,7 +719,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 			}
 		} else if (event instanceof EntryChangedEvent ) {
 			EntryChangedEvent repoEvent = (EntryChangedEvent) event;
-			if (getRepositoryEntry().getKey().equals(repoEvent.getChangedEntryKey())) {
+			if (repoEvent.isMe(getRepositoryEntry())) {
 				processEntryChangedEvent(repoEvent);
 			}
 		//All events are MultiUserEvent, check with command at the end
@@ -728,6 +728,7 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 				updateCurrentUserCount();
 			}
 		}
+		super.event(event);
 	}
 
 	@Override
@@ -1570,7 +1571,8 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 		}
 	}
 	
-	private void processEntryChangedEvent(EntryChangedEvent repoEvent) {
+	@Override
+	protected void processEntryChangedEvent(EntryChangedEvent repoEvent) {
 		switch(repoEvent.getChange()) {
 			case modifiedAtPublish:
 			case modifiedAccess:
@@ -1579,12 +1581,14 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 			case deleted:
 				doDisposeAfterEvent();
 				break;
-			default: {}
+			default:
+				super.processEntryChangedEvent(repoEvent);
+				break;
 		}
 	}
 	
 	private void processEntryAccessChanged(EntryChangedEvent repoEvent) {
-		if(repoEvent.getAuthorKey() != null && getIdentity().getKey().equals(repoEvent.getAuthorKey())) {
+		if(repoEvent.isMe(getIdentity())) {
 			//author is not affected
 		} else {
 			loadRepositoryEntry();
diff --git a/src/main/java/org/olat/modules/qpool/ui/QuestionListController.java b/src/main/java/org/olat/modules/qpool/ui/QuestionListController.java
index de4aef3bab9..86d7fc80571 100644
--- a/src/main/java/org/olat/modules/qpool/ui/QuestionListController.java
+++ b/src/main/java/org/olat/modules/qpool/ui/QuestionListController.java
@@ -461,7 +461,7 @@ public class QuestionListController extends AbstractItemListController implement
 				cleanUp();
 				
 				EntryChangedEvent addEvent = (EntryChangedEvent)event;
-				Long repoEntryKey = addEvent.getChangedEntryKey();
+				Long repoEntryKey = addEvent.getRepositoryEntryKey();
 				doExportToRepositoryEntry(ureq, repoEntryKey);
 			} else if(event == Event.CANCELLED_EVENT) {
 				cmc.deactivate();
diff --git a/src/main/java/org/olat/repository/RepositoryService.java b/src/main/java/org/olat/repository/RepositoryService.java
index 35d9e64d5ff..6d18c2efb52 100644
--- a/src/main/java/org/olat/repository/RepositoryService.java
+++ b/src/main/java/org/olat/repository/RepositoryService.java
@@ -28,7 +28,9 @@ import java.util.Map;
 import org.olat.basesecurity.Group;
 import org.olat.basesecurity.IdentityRef;
 import org.olat.core.id.Identity;
+import org.olat.core.id.OLATResourceable;
 import org.olat.core.id.Roles;
+import org.olat.core.util.resource.OresHelper;
 import org.olat.core.util.vfs.VFSLeaf;
 import org.olat.repository.model.SearchAuthorRepositoryEntryViewParams;
 import org.olat.repository.model.SearchMyRepositoryEntryViewParams;
@@ -46,6 +48,8 @@ import org.olat.resource.OLATResource;
  */
 public interface RepositoryService {
 	
+	public static final OLATResourceable REPOSITORY_EVENT_ORES = OresHelper.createOLATResourceableInstance("REPO-CHANGE", 1l);
+	
 	
 	public RepositoryEntry create(Identity initialAuthor, String initialAuthorAlt,
 			String resourceName, String displayname, String description, OLATResource resource, int access);
diff --git a/src/main/java/org/olat/repository/controllers/EntryChangedEvent.java b/src/main/java/org/olat/repository/controllers/EntryChangedEvent.java
index c96f9c12002..c1fa7d061d1 100644
--- a/src/main/java/org/olat/repository/controllers/EntryChangedEvent.java
+++ b/src/main/java/org/olat/repository/controllers/EntryChangedEvent.java
@@ -28,6 +28,7 @@ package org.olat.repository.controllers;
 import org.olat.basesecurity.IdentityRef;
 import org.olat.core.util.event.MultiUserEvent;
 import org.olat.repository.RepositoryEntry;
+import org.olat.repository.RepositoryEntryRef;
 
 
 /**
@@ -37,9 +38,13 @@ import org.olat.repository.RepositoryEntry;
 public class EntryChangedEvent extends MultiUserEvent {
 
 	private static final long serialVersionUID = 8339474599787388699L;
-	private Change change;
-	private Long changedEntryKey;
-	private Long authorKey;
+	
+	public static final String CHANGE_CMD = "repo-entry-changed";
+	
+	private final Change change;
+	private final Long entryKey;
+	private final Long identityKey;
+	private final String source;
 	
 	/**
 	 * Event signaling the change of a repository entry. Use getChange to see the status of the change.
@@ -47,26 +52,39 @@ public class EntryChangedEvent extends MultiUserEvent {
 	 * @param changedEntry
 	 * @param change
 	 */
-	public EntryChangedEvent(RepositoryEntry changedEntry, IdentityRef identity, Change change) {
-		super("");
-		changedEntryKey = changedEntry.getKey();
-		authorKey = identity == null ? null : identity.getKey();
+	public EntryChangedEvent(RepositoryEntryRef entry, IdentityRef identity, Change change, String source) {
+		super(CHANGE_CMD);
+		this.source = source;
 		this.change = change;
+		entryKey = entry.getKey();
+		identityKey = identity == null ? null : identity.getKey();
 	}
 	
 	/**
 	 * @return the key of the repository entry that has been changed.
 	 */
-	public Long getChangedEntryKey() {
-		return changedEntryKey;
+	public Long getRepositoryEntryKey() {
+		return entryKey;
 	}
 	
 	/**
 	 * The author of the change
 	 * @return
 	 */
-	public Long getAuthorKey() {
-		return authorKey;
+	public Long getIdentityKey() {
+		return identityKey;
+	}
+	
+	public boolean isMe(IdentityRef identity) {
+		return identityKey != null && identity != null && identityKey.equals(identity.getKey());
+	}
+	
+	public boolean isMe(RepositoryEntry entry) {
+		return entryKey != null && entry != null && entryKey.equals(entry.getKey());
+	}
+	
+	public String getSource() {
+		return source;
 	}
 
 	/**
@@ -82,6 +100,8 @@ public class EntryChangedEvent extends MultiUserEvent {
 		deleted,
 		modifiedAccess,
 		modifiedDescription,
-		modifiedAtPublish
+		modifiedAtPublish,
+		addBookmark,
+		removeBookmark
 	}
 }
diff --git a/src/main/java/org/olat/repository/controllers/RepositorySearchController.java b/src/main/java/org/olat/repository/controllers/RepositorySearchController.java
index 5b6f5733100..0eb0d1e3fe1 100644
--- a/src/main/java/org/olat/repository/controllers/RepositorySearchController.java
+++ b/src/main/java/org/olat/repository/controllers/RepositorySearchController.java
@@ -604,8 +604,9 @@ public class RepositorySearchController extends BasicController implements Activ
 				List<RepositoryEntry> newEntries = new ArrayList<RepositoryEntry>();
 				for (int i = 0; i < repoTableModel.getRowCount(); i++) {
 					RepositoryEntry foo = repoTableModel.getObject(i);
-					if (!foo.getKey().equals(ecv.getChangedEntryKey()))
+					if (!foo.getKey().equals(ecv.getRepositoryEntryKey())) {
 						newEntries.add(foo);
+					}
 				}
 				repoTableModel.setObjects(newEntries);
 				tableCtr.modelChanged();
diff --git a/src/main/java/org/olat/repository/manager/CatalogManager.java b/src/main/java/org/olat/repository/manager/CatalogManager.java
index b8ddd2ae746..91576a25925 100644
--- a/src/main/java/org/olat/repository/manager/CatalogManager.java
+++ b/src/main/java/org/olat/repository/manager/CatalogManager.java
@@ -700,7 +700,7 @@ public class CatalogManager implements UserDataDeletable, InitializingBean {
 	 */
 	public void notifyReferencedRepositoryEntryChanges(RepositoryEntry re) {
 		// inform anybody interested about this change
-		MultiUserEvent modifiedEvent = new EntryChangedEvent(re, null, Change.modifiedDescription);
+		MultiUserEvent modifiedEvent = new EntryChangedEvent(re, null, Change.modifiedDescription, "CatalogManager");
 		CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(modifiedEvent, re);
 	}
 	
diff --git a/src/main/java/org/olat/repository/ui/RepositoryEntryLifeCycleChangeController.java b/src/main/java/org/olat/repository/ui/RepositoryEntryLifeCycleChangeController.java
index cb129b25f2d..83d1e337989 100644
--- a/src/main/java/org/olat/repository/ui/RepositoryEntryLifeCycleChangeController.java
+++ b/src/main/java/org/olat/repository/ui/RepositoryEntryLifeCycleChangeController.java
@@ -41,6 +41,8 @@ import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryEntryManagedFlag;
 import org.olat.repository.RepositoryManager;
 import org.olat.repository.RepositoryService;
+import org.olat.repository.controllers.EntryChangedEvent;
+import org.olat.repository.controllers.EntryChangedEvent.Change;
 import org.olat.repository.handlers.RepositoryHandler;
 import org.olat.repository.model.RepositoryEntrySecurity;
 import org.olat.repository.ui.author.ConfirmDeleteController;
@@ -135,6 +137,8 @@ public class RepositoryEntryLifeCycleChangeController extends BasicController{
 			} else if (event == Event.DONE_EVENT || event == Event.CHANGED_EVENT) {
 				cleanUp();
 				fireEvent(ureq, deletedEvent);
+				EntryChangedEvent e = new EntryChangedEvent(re, getIdentity(), Change.deleted, "runtime");
+				ureq.getUserSession().getSingleUserEventCenter().fireEventToListenersOf(e, RepositoryService.REPOSITORY_EVENT_ORES);
 			}
 			
 		} else if(cmc == source) {
diff --git a/src/main/java/org/olat/repository/ui/RepositoryEntryRuntimeController.java b/src/main/java/org/olat/repository/ui/RepositoryEntryRuntimeController.java
index 2024e316a4d..e0595a4bd24 100644
--- a/src/main/java/org/olat/repository/ui/RepositoryEntryRuntimeController.java
+++ b/src/main/java/org/olat/repository/ui/RepositoryEntryRuntimeController.java
@@ -56,6 +56,8 @@ import org.olat.core.util.StringHelper;
 import org.olat.core.util.UserSession;
 import org.olat.core.util.Util;
 import org.olat.core.util.coordinate.LockResult;
+import org.olat.core.util.event.EventBus;
+import org.olat.core.util.event.GenericEventListener;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.course.CourseModule;
 import org.olat.course.assessment.AssessmentMode;
@@ -67,6 +69,8 @@ import org.olat.repository.RepositoryEntryRef;
 import org.olat.repository.RepositoryManager;
 import org.olat.repository.RepositoryModule;
 import org.olat.repository.RepositoryService;
+import org.olat.repository.controllers.EntryChangedEvent;
+import org.olat.repository.controllers.EntryChangedEvent.Change;
 import org.olat.repository.handlers.EditionSupport;
 import org.olat.repository.handlers.RepositoryHandler;
 import org.olat.repository.handlers.RepositoryHandlerFactory;
@@ -97,7 +101,8 @@ import org.springframework.beans.factory.annotation.Autowired;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class RepositoryEntryRuntimeController extends MainLayoutBasicController implements Activateable2 {
+public class RepositoryEntryRuntimeController extends MainLayoutBasicController implements Activateable2, GenericEventListener {
+
 
 	private Controller runtimeController;
 	protected final TooledStackedPanel toolbarPanel;
@@ -141,6 +146,7 @@ public class RepositoryEntryRuntimeController extends MainLayoutBasicController
 	private AssessmentMode assessmentMode;
 	private final RepositoryHandler handler;
 	
+	private final EventBus eventBus;
 	private HistoryPoint launchedFromPoint;
 	
 	@Autowired
@@ -221,6 +227,9 @@ public class RepositoryEntryRuntimeController extends MainLayoutBasicController
 		doRun(ureq, reSecurity);
 		loadRights(reSecurity);
 		initToolbar();
+		
+		eventBus = ureq.getUserSession().getSingleUserEventCenter();
+		eventBus.registerFor(this, getIdentity(), RepositoryService.REPOSITORY_EVENT_ORES);
 	}
 	
 	protected boolean isCorrupted(RepositoryEntry entry) {
@@ -481,6 +490,22 @@ public class RepositoryEntryRuntimeController extends MainLayoutBasicController
 		if(runtimeController != null && !runtimeController.isDisposed()) {
 			runtimeController.dispose();
 		}
+		eventBus.deregisterFor(this, RepositoryService.REPOSITORY_EVENT_ORES);
+	}
+
+	@Override
+	public void event(Event event) {
+		//
+	}
+	
+	protected void processEntryChangedEvent(EntryChangedEvent repoEvent) {
+		if(repoEvent.isMe(getIdentity()) &&
+				(repoEvent.getChange() == Change.addBookmark || repoEvent.getChange() == Change.removeBookmark)) {
+			boolean marked = markManager.isMarked(OresHelper.clone(re), getIdentity(), null);
+			String css = "o_icon " + (marked ? Mark.MARK_CSS_ICON : Mark.MARK_ADD_CSS_ICON);
+			bookmarkLink.setIconLeftCSS(css);
+			bookmarkLink.setTitle( translate(marked ? "details.bookmark.remove" : "details.bookmark"));
+		}
 	}
 
 	@Override
@@ -502,7 +527,7 @@ public class RepositoryEntryRuntimeController extends MainLayoutBasicController
 		} else if(detailsLink == source) {
 			doDetails(ureq);
 		} else if(bookmarkLink == source) {
-			boolean marked = doMark();
+			boolean marked = doMark(ureq);
 			String css = "o_icon " + (marked ? Mark.MARK_CSS_ICON : Mark.MARK_ADD_CSS_ICON);
 			bookmarkLink.setIconLeftCSS(css);
 			bookmarkLink.setTitle( translate(marked ? "details.bookmark.remove" : "details.bookmark"));
@@ -582,7 +607,7 @@ public class RepositoryEntryRuntimeController extends MainLayoutBasicController
 		} else if (lifeCycleChangeCtr == source) {
 			if (event == RepositoryEntryLifeCycleChangeController.deletedEvent) {
 				doClose(ureq);
-				cleanUp();				
+				cleanUp();	
 			} else if (event == RepositoryEntryLifeCycleChangeController.closedEvent) {
 				if(editLink != null) {
 					editLink.setVisible(false);
@@ -597,6 +622,9 @@ public class RepositoryEntryRuntimeController extends MainLayoutBasicController
 				RepositoryEntryRef copy = copyCtrl.getCopiedEntry();
 				String businessPath = "[RepositoryEntry:" + copy.getKey() + "][EditDescription:0]";
 				NewControllerFactory.getInstance().launch(businessPath, ureq, getWindowControl());
+				
+				EntryChangedEvent e = new EntryChangedEvent(getRepositoryEntry(), getIdentity(), Change.added, "runtime");
+				ureq.getUserSession().getSingleUserEventCenter().fireEventToListenersOf(e, RepositoryService.REPOSITORY_EVENT_ORES);
 			}
 			cleanUp();
 		}
@@ -791,14 +819,19 @@ public class RepositoryEntryRuntimeController extends MainLayoutBasicController
 		return new ACResultAndSecurity(acResult, security);
 	}
 	
-	protected boolean doMark() {
+	protected boolean doMark(UserRequest ureq) {
 		OLATResourceable item = OresHelper.clone(re);
 		if(markManager.isMarked(item, getIdentity(), null)) {
 			markManager.removeMark(item, getIdentity(), null);
+			
+			EntryChangedEvent e = new EntryChangedEvent(getRepositoryEntry(), getIdentity(), Change.removeBookmark, "runtime");
+			ureq.getUserSession().getSingleUserEventCenter().fireEventToListenersOf(e, RepositoryService.REPOSITORY_EVENT_ORES);
 			return false;
 		} else {
 			String businessPath = "[RepositoryEntry:" + item.getResourceableId() + "]";
 			markManager.setMark(item, getIdentity(), null, businessPath);
+			EntryChangedEvent e = new EntryChangedEvent(getRepositoryEntry(), getIdentity(), Change.addBookmark, "runtime");
+			ureq.getUserSession().getSingleUserEventCenter().fireEventToListenersOf(e, RepositoryService.REPOSITORY_EVENT_ORES);
 			return true;
 		}
 	}
diff --git a/src/main/java/org/olat/repository/ui/author/AuthorListController.java b/src/main/java/org/olat/repository/ui/author/AuthorListController.java
index 05ac91a3bc0..50318e9ad5c 100644
--- a/src/main/java/org/olat/repository/ui/author/AuthorListController.java
+++ b/src/main/java/org/olat/repository/ui/author/AuthorListController.java
@@ -30,6 +30,7 @@ import org.olat.admin.user.UserSearchController;
 import org.olat.basesecurity.GroupRoles;
 import org.olat.basesecurity.events.MultiIdentityChosenEvent;
 import org.olat.basesecurity.events.SingleIdentityChosenEvent;
+import org.olat.core.commons.persistence.DB;
 import org.olat.core.commons.persistence.SortKey;
 import org.olat.core.commons.services.mark.Mark;
 import org.olat.core.commons.services.mark.MarkManager;
@@ -94,6 +95,8 @@ import org.olat.repository.RepositoryEntryRef;
 import org.olat.repository.RepositoryManager;
 import org.olat.repository.RepositoryModule;
 import org.olat.repository.RepositoryService;
+import org.olat.repository.controllers.EntryChangedEvent;
+import org.olat.repository.controllers.EntryChangedEvent.Change;
 import org.olat.repository.handlers.RepositoryHandler;
 import org.olat.repository.handlers.RepositoryHandlerFactory;
 import org.olat.repository.handlers.RepositoryHandlerFactory.OrderedRepositoryHandler;
@@ -147,8 +150,10 @@ public class AuthorListController extends FormBasicController implements Activat
 	private LockResult lockResult;
 	private final AtomicInteger counter = new AtomicInteger();
 	//only used as marker for dirty, model cannot load specific rows
-	private final List<Integer> dirtyRows = new ArrayList<>();
+	private final List<Long> dirtyRows = new ArrayList<>();
 	
+	@Autowired
+	private DB dbInstance;
 	@Autowired
 	private UserManager userManager;
 	@Autowired
@@ -211,6 +216,9 @@ public class AuthorListController extends FormBasicController implements Activat
 			stackPanel.addTool(createDropdown, Align.left);
 		}
 	}
+	public String getI18nName() {
+		return i18nName;
+	}
 	
 	@Override
 	public Translator getTranslator() {
@@ -391,12 +399,14 @@ public class AuthorListController extends FormBasicController implements Activat
 		} else if(copyCtrl == source) {
 			cmc.deactivate();
 			if (event == Event.DONE_EVENT) {
+				reloadRows();
 				launchEditDescription(ureq, copyCtrl.getCopiedEntry());
 			}
 			cleanUp();
 		} else if(importCtrl == source) {
 			cmc.deactivate();
 			if(Event.DONE_EVENT.equals(event)) {
+				reloadRows();
 				launchEditDescription(ureq, importCtrl.getImportedEntry());
 			}
 			cleanUp();
@@ -513,7 +523,7 @@ public class AuthorListController extends FormBasicController implements Activat
 			String cmd = link.getCmd();
 			if("mark".equals(cmd)) {
 				AuthoringEntryRow row = (AuthoringEntryRow)link.getUserObject();
-				boolean marked = doMark(row);
+				boolean marked = doMark(ureq, row);
 				link.setIconLeftCSS(marked ? "o_icon o_icon_bookmark o_icon-lg" : "o_icon o_icon_bookmark_add o_icon-lg");
 				link.setTitle(translate(marked ? "details.bookmark.remove" : "details.bookmark"));
 				link.getComponent().setDirty(true);
@@ -548,6 +558,10 @@ public class AuthorListController extends FormBasicController implements Activat
 		//do not update the 
 	}
 	
+	public void addDirtyRows(Long entryKey) {
+		dirtyRows.add(entryKey);
+	}
+	
 	protected void reloadDirtyRows() {
 		if(dirtyRows.size() > 0) {
 			reloadRows();
@@ -609,16 +623,24 @@ public class AuthorListController extends FormBasicController implements Activat
 		cmc.activate();
 	}
 	
-	protected boolean doMark(AuthoringEntryRow row) {
+	protected boolean doMark(UserRequest ureq, AuthoringEntryRow row) {
 		OLATResourceable item = OresHelper.createOLATResourceableInstance("RepositoryEntry", row.getKey());
 		if(markManager.isMarked(item, getIdentity(), null)) {
 			markManager.removeMark(item, getIdentity(), null);
+
+			dbInstance.commit();//before sending, save the changes
+			EntryChangedEvent e = new EntryChangedEvent(row, getIdentity(), Change.removeBookmark, i18nName);
+			ureq.getUserSession().getSingleUserEventCenter().fireEventToListenersOf(e, RepositoryService.REPOSITORY_EVENT_ORES);
 			return false;
-		} else {
-			String businessPath = "[RepositoryEntry:" + item.getResourceableId() + "]";
-			markManager.setMark(item, getIdentity(), null, businessPath);
-			return true;
 		}
+		
+		String businessPath = "[RepositoryEntry:" + item.getResourceableId() + "]";
+		markManager.setMark(item, getIdentity(), null, businessPath);
+		
+		dbInstance.commit();//before sending, save the changes
+		EntryChangedEvent e = new EntryChangedEvent(row, getIdentity(), Change.addBookmark, i18nName);
+		ureq.getUserSession().getSingleUserEventCenter().fireEventToListenersOf(e, RepositoryService.REPOSITORY_EVENT_ORES);
+		return true;
 	}
 	
 	private void doPostCreateWizard(UserRequest ureq, RepositoryEntry newEntry, RepositoryHandler handler) {
diff --git a/src/main/java/org/olat/repository/ui/author/AuthoringEditAccessController.java b/src/main/java/org/olat/repository/ui/author/AuthoringEditAccessController.java
index 2b0432cc887..f935f040ba4 100644
--- a/src/main/java/org/olat/repository/ui/author/AuthoringEditAccessController.java
+++ b/src/main/java/org/olat/repository/ui/author/AuthoringEditAccessController.java
@@ -134,7 +134,7 @@ public class AuthoringEditAccessController extends BasicController {
 					}
 					
 					// inform anybody interested about this change
-					MultiUserEvent modifiedEvent = new EntryChangedEvent(entry, getIdentity(), Change.modifiedAccess);
+					MultiUserEvent modifiedEvent = new EntryChangedEvent(entry, getIdentity(), Change.modifiedAccess, "authoring");
 					CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(modifiedEvent, entry);			
 					fireEvent(ureq, Event.CHANGED_EVENT);
 				}
@@ -147,7 +147,7 @@ public class AuthoringEditAccessController extends BasicController {
 					showWarning("repositoryentry.not.existing");
 					fireEvent(ureq, Event.CLOSE_EVENT);
 				} else {
-					MultiUserEvent modifiedEvent = new EntryChangedEvent(entry, getIdentity(), Change.modifiedAccess);
+					MultiUserEvent modifiedEvent = new EntryChangedEvent(entry, getIdentity(), Change.modifiedAccess, "authorings");
 					CoordinatorManager.getInstance().getCoordinator().getEventBus().fireEventToListenersOf(modifiedEvent, entry);	
 					fireEvent(ureq, Event.CHANGED_EVENT);
 				}
diff --git a/src/main/java/org/olat/repository/ui/author/ConfirmDeleteController.java b/src/main/java/org/olat/repository/ui/author/ConfirmDeleteController.java
index 45871c294db..38cba26c64a 100644
--- a/src/main/java/org/olat/repository/ui/author/ConfirmDeleteController.java
+++ b/src/main/java/org/olat/repository/ui/author/ConfirmDeleteController.java
@@ -291,7 +291,7 @@ public class ConfirmDeleteController extends FormBasicController {
 					allOk = false;
 					errorList.add(errors);
 				} else {
-					fireEvent(ureq, new EntryChangedEvent(reloadedEntry, getIdentity(), Change.deleted));
+					fireEvent(ureq, new EntryChangedEvent(reloadedEntry, getIdentity(), Change.deleted, "delete"));
 				}
 			}
 		}
diff --git a/src/main/java/org/olat/repository/ui/author/CreateRepositoryEntryController.java b/src/main/java/org/olat/repository/ui/author/CreateRepositoryEntryController.java
index 8833c0a3b5e..11e241b4b1f 100644
--- a/src/main/java/org/olat/repository/ui/author/CreateRepositoryEntryController.java
+++ b/src/main/java/org/olat/repository/ui/author/CreateRepositoryEntryController.java
@@ -146,7 +146,7 @@ public class CreateRepositoryEntryController extends FormBasicController impleme
 	protected void formOK(UserRequest ureq) {
 		doCreate();
 		fireEvent(ureq, Event.DONE_EVENT);
-		fireEvent(ureq, new EntryChangedEvent(addedEntry, getIdentity(), Change.added));
+		fireEvent(ureq, new EntryChangedEvent(addedEntry, getIdentity(), Change.added, "create"));
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/repository/ui/author/OverviewAuthoringController.java b/src/main/java/org/olat/repository/ui/author/OverviewAuthoringController.java
index f5c4e17bb88..e0934c529dd 100644
--- a/src/main/java/org/olat/repository/ui/author/OverviewAuthoringController.java
+++ b/src/main/java/org/olat/repository/ui/author/OverviewAuthoringController.java
@@ -40,8 +40,13 @@ import org.olat.core.id.context.ContextEntry;
 import org.olat.core.id.context.StateEntry;
 import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
 import org.olat.core.util.Util;
+import org.olat.core.util.event.EventBus;
+import org.olat.core.util.event.GenericEventListener;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.repository.RepositoryManager;
+import org.olat.repository.RepositoryService;
+import org.olat.repository.controllers.EntryChangedEvent;
+import org.olat.repository.controllers.EntryChangedEvent.Change;
 import org.olat.repository.model.SearchAuthorRepositoryEntryViewParams;
 import org.olat.util.logging.activity.LoggingResourceable;
 
@@ -51,7 +56,7 @@ import org.olat.util.logging.activity.LoggingResourceable;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class OverviewAuthoringController extends BasicController implements Activateable2 {
+public class OverviewAuthoringController extends BasicController implements Activateable2, GenericEventListener {
 	
 	private MainPanel mainPanel;
 	private final VelocityContainer mainVC;
@@ -60,7 +65,9 @@ public class OverviewAuthoringController extends BasicController implements Acti
 	private final Link myEntriesLink, searchLink;
 	private AuthorListController currentCtrl, markedCtrl, myEntriesCtrl, searchEntriesCtrl;
 
-	private boolean isGuestonly;
+	private final boolean isGuestonly;
+	private boolean favoritDirty, myDirty;
+	private final EventBus eventBus;
 	
 	public OverviewAuthoringController(UserRequest ureq, WindowControl wControl) {
 		super(ureq, wControl);
@@ -84,14 +91,33 @@ public class OverviewAuthoringController extends BasicController implements Acti
 		searchLink = LinkFactory.createLink("search.generic", mainVC, this);
 		segmentView.addSegment(searchLink, false);
 
+		eventBus = ureq.getUserSession().getSingleUserEventCenter();
+		eventBus.registerFor(this, getIdentity(), RepositoryService.REPOSITORY_EVENT_ORES);
+
 		putInitialPanel(mainPanel);
 	}
 	
 	@Override
 	protected void doDispose() {
-		//
+		eventBus.deregisterFor(this, RepositoryService.REPOSITORY_EVENT_ORES);
 	}
 	
+	@Override
+	public void event(Event event) {
+		if(EntryChangedEvent.CHANGE_CMD.equals(event.getCommand()) && event instanceof EntryChangedEvent) {
+			EntryChangedEvent ece = (EntryChangedEvent)event;
+			if(ece.getChange() == Change.addBookmark || ece.getChange() == Change.removeBookmark
+					|| ece.getChange() == Change.added || ece.getChange() == Change.deleted) {
+				if(markedCtrl != null && !markedCtrl.getI18nName().equals(ece.getSource())) {
+					favoritDirty = true;
+				}
+				if(myEntriesCtrl != null && !myEntriesCtrl.getI18nName().equals(ece.getSource())) {
+					myDirty = true;
+				}
+			}
+		}
+	}
+
 	@Override
 	public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
 		if(entries == null || entries.isEmpty()) {
@@ -109,6 +135,12 @@ public class OverviewAuthoringController extends BasicController implements Acti
 					}
 				}
 			}
+			if(favoritDirty && markedCtrl != null) {
+				markedCtrl.reloadRows();
+			}
+			if(myDirty && myEntriesCtrl != null) {
+				myEntriesCtrl.reloadRows();
+			}
 			addToHistory(ureq, currentCtrl);
 		} else {
 			ContextEntry entry = entries.get(0);
@@ -165,7 +197,10 @@ public class OverviewAuthoringController extends BasicController implements Acti
 			WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl());
 			markedCtrl = new AuthorListController(ureq, bwControl, "search.mark", searchParams, false);
 			listenTo(markedCtrl);
+		} else if(favoritDirty) {
+			markedCtrl.reloadRows();
 		}
+		favoritDirty = false;
 		
 		currentCtrl = markedCtrl;
 		addToHistory(ureq, markedCtrl);
@@ -183,8 +218,11 @@ public class OverviewAuthoringController extends BasicController implements Acti
 			ThreadLocalUserActivityLogger.addLoggingResourceInfo(LoggingResourceable.wrapBusinessPath(ores));
 			WindowControl bwControl = BusinessControlFactory.getInstance().createBusinessWindowControl(ores, null, getWindowControl());
 			myEntriesCtrl = new AuthorListController(ureq, bwControl, "search.my", searchParams, false);
-			listenTo(myEntriesCtrl);
+			listenTo(myEntriesCtrl);	
+		} else if(myDirty) {
+			myEntriesCtrl.reloadRows();
 		}
+		myDirty = false;
 		
 		currentCtrl = myEntriesCtrl;
 		addToHistory(ureq, myEntriesCtrl);
diff --git a/src/main/java/org/olat/repository/ui/list/OverviewRepositoryListController.java b/src/main/java/org/olat/repository/ui/list/OverviewRepositoryListController.java
index 877cb324edb..8d5d297d736 100644
--- a/src/main/java/org/olat/repository/ui/list/OverviewRepositoryListController.java
+++ b/src/main/java/org/olat/repository/ui/list/OverviewRepositoryListController.java
@@ -42,10 +42,15 @@ import org.olat.core.id.context.ContextEntry;
 import org.olat.core.id.context.StateEntry;
 import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
 import org.olat.core.util.Util;
+import org.olat.core.util.event.EventBus;
+import org.olat.core.util.event.GenericEventListener;
 import org.olat.core.util.resource.OresHelper;
 import org.olat.repository.CatalogEntry;
 import org.olat.repository.RepositoryManager;
 import org.olat.repository.RepositoryModule;
+import org.olat.repository.RepositoryService;
+import org.olat.repository.controllers.EntryChangedEvent;
+import org.olat.repository.controllers.EntryChangedEvent.Change;
 import org.olat.repository.manager.CatalogManager;
 import org.olat.repository.model.SearchMyRepositoryEntryViewParams;
 import org.olat.repository.ui.catalog.CatalogNodeController;
@@ -58,7 +63,7 @@ import org.springframework.beans.factory.annotation.Autowired;
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  *
  */
-public class OverviewRepositoryListController extends BasicController implements Activateable2 {
+public class OverviewRepositoryListController extends BasicController implements Activateable2, GenericEventListener {
 
 	private final VelocityContainer mainVC;
 	private final SegmentViewComponent segmentView;
@@ -76,6 +81,9 @@ public class OverviewRepositoryListController extends BasicController implements
 	private BreadcrumbedStackedPanel searchCoursesStackPanel;
 	
 	private final boolean isGuestOnly;
+	private boolean favoritDirty, myDirty;
+	
+	private final EventBus eventBus;
 	
 	@Autowired
 	private CatalogManager catalogManager;
@@ -115,6 +123,9 @@ public class OverviewRepositoryListController extends BasicController implements
 			segmentView.addSegment(searchCourseLink, false);
 		}
 		
+		eventBus = ureq.getUserSession().getSingleUserEventCenter();
+		eventBus.registerFor(this, getIdentity(), RepositoryService.REPOSITORY_EVENT_ORES);
+		
 		putInitialPanel(mainPanel);
 	}
 	
@@ -135,6 +146,13 @@ public class OverviewRepositoryListController extends BasicController implements
 					}
 				}
 			}
+			
+			if(favoritDirty && markedCtrl != null) {
+				markedCtrl.reloadRows();
+			}
+			if(myDirty && myCoursesCtrl != null) {
+				myCoursesCtrl.reloadRows();
+			}
 			addToHistory(ureq, this);
 		} else {
 			ContextEntry entry = entries.get(0);
@@ -171,7 +189,24 @@ public class OverviewRepositoryListController extends BasicController implements
 
 	@Override
 	protected void doDispose() {
-		//
+		eventBus.deregisterFor(this, RepositoryService.REPOSITORY_EVENT_ORES);
+	}
+
+	
+	@Override
+	public void event(Event event) {
+		if(EntryChangedEvent.CHANGE_CMD.equals(event.getCommand()) && event instanceof EntryChangedEvent) {
+			EntryChangedEvent ece = (EntryChangedEvent)event;
+			if(ece.getChange() == Change.addBookmark || ece.getChange() == Change.removeBookmark
+					|| ece.getChange() == Change.added || ece.getChange() == Change.deleted) {
+				if(markedCtrl != null && !markedCtrl.getName().equals(ece.getSource())) {
+					favoritDirty = true;
+				}
+				if(myCoursesCtrl != null && !myCoursesCtrl.getName().equals(ece.getSource())) {
+					myDirty = true;
+				}
+			}
+		}
 	}
 
 	@Override
@@ -221,6 +256,7 @@ public class OverviewRepositoryListController extends BasicController implements
 		markedStackPanel.pushController(translate("search.mark"), markedCtrl);
 		listenTo(markedCtrl);
 		currentCtrl = markedCtrl;
+		favoritDirty = false;
 
 		addToHistory(ureq, markedCtrl);
 		mainVC.put("segmentCmp", markedStackPanel);
@@ -242,6 +278,7 @@ public class OverviewRepositoryListController extends BasicController implements
 		myCoursesStackPanel.pushController(translate("search.mycourses.student"), myCoursesCtrl);
 		listenTo(myCoursesCtrl);
 		currentCtrl = myCoursesCtrl;
+		myDirty = false;
 
 		addToHistory(ureq, myCoursesCtrl);
 		mainVC.put("segmentCmp", myCoursesStackPanel);
diff --git a/src/main/java/org/olat/repository/ui/list/RepositoryEntryListController.java b/src/main/java/org/olat/repository/ui/list/RepositoryEntryListController.java
index da338b3d62f..fa5ba92d6c7 100644
--- a/src/main/java/org/olat/repository/ui/list/RepositoryEntryListController.java
+++ b/src/main/java/org/olat/repository/ui/list/RepositoryEntryListController.java
@@ -77,6 +77,8 @@ import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryManager;
 import org.olat.repository.RepositoryModule;
 import org.olat.repository.RepositoryService;
+import org.olat.repository.controllers.EntryChangedEvent;
+import org.olat.repository.controllers.EntryChangedEvent.Change;
 import org.olat.repository.model.SearchMyRepositoryEntryViewParams;
 import org.olat.repository.model.SearchMyRepositoryEntryViewParams.Filter;
 import org.olat.repository.model.SearchMyRepositoryEntryViewParams.OrderBy;
@@ -150,6 +152,14 @@ public class RepositoryEntryListController extends FormBasicController
 	public boolean isEmpty() {
 		return dataSource.getRowCount() == 0;
 	}
+	
+	public String getName() {
+		return name;
+	}
+	
+	public void reloadRows() {
+		tableEl.reloadData();
+	}
 
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
@@ -298,7 +308,7 @@ public class RepositoryEntryListController extends FormBasicController
 			
 			if("mark".equals(cmd)) {
 				RepositoryEntryRow row = (RepositoryEntryRow)link.getUserObject();
-				boolean marked = doMark(row);
+				boolean marked = doMark(ureq, row);
 				link.setIconLeftCSS(marked ? "o_icon o_icon_bookmark o_icon-lg" : "o_icon o_icon_bookmark_add o_icon-lg");
 				link.setTitle(translate(marked ? "details.bookmark.remove" : "details.bookmark"));
 				link.getComponent().setDirty(true);
@@ -535,14 +545,20 @@ public class RepositoryEntryListController extends FormBasicController
 		cmc.activate();
 	}
 	
-	protected boolean doMark(RepositoryEntryRow row) {
+	protected boolean doMark(UserRequest ureq, RepositoryEntryRow row) {
 		OLATResourceable item = OresHelper.createOLATResourceableInstance("RepositoryEntry", row.getKey());
 		if(markManager.isMarked(item, getIdentity(), null)) {
 			markManager.removeMark(item, getIdentity(), null);
+			
+			EntryChangedEvent e = new EntryChangedEvent(row, getIdentity(), Change.removeBookmark, name);
+			ureq.getUserSession().getSingleUserEventCenter().fireEventToListenersOf(e, RepositoryService.REPOSITORY_EVENT_ORES);
 			return false;
 		} else {
 			String businessPath = "[RepositoryEntry:" + item.getResourceableId() + "]";
 			markManager.setMark(item, getIdentity(), null, businessPath);
+			
+			EntryChangedEvent e = new EntryChangedEvent(row, getIdentity(), Change.addBookmark, name);
+			ureq.getUserSession().getSingleUserEventCenter().fireEventToListenersOf(e, RepositoryService.REPOSITORY_EVENT_ORES);
 			return true;
 		}
 	}
-- 
GitLab