From e88200c94a49241500f9baf7c4649f19a1437f8f Mon Sep 17 00:00:00 2001
From: uhensler <none@none>
Date: Wed, 12 Jul 2017 11:25:18 +0200
Subject: [PATCH] OO-2834: Remove the cancel button from the edit quota dialog

---
 .../quota/GenericQuotaEditController.java     | 49 ++++++++++---------
 .../quota/GenericQuotaViewController.java     |  7 +--
 .../org/olat/admin/quota/QuotaController.java | 17 ++-----
 .../olat/admin/quota/QuotaManagerImpl.java    | 22 ++++++---
 .../org/olat/admin/quota/_content/edit.html   |  4 --
 .../olat/admin/user/UserAdminController.java  |  2 +-
 .../CollaborationToolsSettingsController.java |  4 +-
 .../modules/bc/commands/CmdEditQuota.java     |  3 +-
 .../org/olat/core/util/vfs/QuotaManager.java  |  6 +--
 .../olat/ims/cp/ui/CPRuntimeController.java   |  2 +-
 .../webFeed/ui/FeedRuntimeController.java     |  2 +-
 11 files changed, 54 insertions(+), 64 deletions(-)

diff --git a/src/main/java/org/olat/admin/quota/GenericQuotaEditController.java b/src/main/java/org/olat/admin/quota/GenericQuotaEditController.java
index 6a5b002b2f8..382943cc484 100644
--- a/src/main/java/org/olat/admin/quota/GenericQuotaEditController.java
+++ b/src/main/java/org/olat/admin/quota/GenericQuotaEditController.java
@@ -43,7 +43,6 @@ import org.olat.core.util.vfs.QuotaManager;
  * Description:<BR>
  * Generic editor controller for quotas. Can be constructed from a quota or a
  * folder path. When finished the controller fires the following events:<BR>
- * Event.CANCELLED_EVENT
  * Event.CHANGED_EVENT
  * <p>
  * Check with QuotaManager.hasQuotaEditRights if you are allowed to use this
@@ -57,11 +56,9 @@ public class GenericQuotaEditController extends BasicController {
 
 	private VelocityContainer myContent;
 	private QuotaForm quotaForm;
-	private boolean modalMode;
 	
 	private Quota currentQuota;
 	private Link delQuotaButton;
-	private Link cancelButton;
 
 
 	/**
@@ -73,12 +70,9 @@ public class GenericQuotaEditController extends BasicController {
 	 * @param ureq
 	 * @param wControl
 	 * @param quotaPath The path for which the quota should be edited
-	 * @param modalMode true: window will push to fullscreen and pop itself when finished. false: normal
-	 * controller mode, get initial component using getInitialComponent()
 	 */
-	GenericQuotaEditController(UserRequest ureq, WindowControl wControl, String relPath, boolean modalMode) {
+	GenericQuotaEditController(UserRequest ureq, WindowControl wControl, String relPath) {
 		super(ureq, wControl);
-		this.modalMode = modalMode;
 		
 		// check if quota foqf.cannot.del.defaultr this path already exists
 		QuotaManager qm = QuotaManager.getInstance();
@@ -103,7 +97,6 @@ public class GenericQuotaEditController extends BasicController {
 	 */
 	public GenericQuotaEditController(UserRequest ureq, WindowControl wControl, Quota quota) {
 		super(ureq, wControl);
-		this.modalMode = false;
 		
 		initMyContent(ureq);
 		
@@ -119,6 +112,26 @@ public class GenericQuotaEditController extends BasicController {
 		putInitialPanel(myContent);
 	}
 
+	/**
+	 * Constructor for the generic quota edit controller used when a new
+	 * existing quota should be edited.
+	 * 
+	 * @param ureq
+	 * @param wControl
+	 */
+	public GenericQuotaEditController(UserRequest ureq, WindowControl wControl) {
+		super(ureq, wControl);
+		
+		initMyContent(ureq);
+		
+		// start with new quota
+		currentQuota = QuotaManager.getInstance().createQuota(null, null, null);
+		myContent.contextPut("isEmptyQuota", true);
+		initQuotaForm(ureq, currentQuota);
+		
+		putInitialPanel(myContent);
+	}
+
 	private void initMyContent(UserRequest ureq) {
 		QuotaManager qm = QuotaManager.getInstance();
 		if (!qm.hasQuotaEditRights(ureq.getIdentity())) {
@@ -126,10 +139,8 @@ public class GenericQuotaEditController extends BasicController {
 		}
 
 		myContent = createVelocityContainer("edit");
-		myContent.contextPut("modalMode", Boolean.valueOf(modalMode));
 		LinkFactory.createButtonSmall("qf.new", myContent, this);
 		delQuotaButton = LinkFactory.createButtonSmall("qf.del", myContent, this);
-		cancelButton = LinkFactory.createButtonSmall("cancel", myContent, this);
 		
 		myContent.contextPut("users",qm.getDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_USERS));
 		myContent.contextPut("powerusers",qm.getDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_POWER));
@@ -151,9 +162,7 @@ public class GenericQuotaEditController extends BasicController {
 		myContent.contextPut("editQuota", Boolean.TRUE);
 	}
 
-	/**
-	 * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.components.Component, org.olat.core.gui.control.Event)
-	 */
+	@Override
 	public void event(UserRequest ureq, Component source, Event event) {
 		initQuotaForm(ureq, currentQuota);
 		if (source == delQuotaButton){
@@ -166,14 +175,10 @@ public class GenericQuotaEditController extends BasicController {
 			} else {
 				showError("qf.cannot.del.default");
 			}
-		} else if(source == cancelButton){
-			fireEvent(ureq, Event.CANCELLED_EVENT);		
 		}	
 	}
 	
-	/**
-	 * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.control.Controller, org.olat.core.gui.control.Event)
-	 */
+	@Override
 	public void event(UserRequest ureq, Controller source, Event event) {
 		if (source == quotaForm) {
 			if (event == Event.DONE_EVENT) {
@@ -184,17 +189,13 @@ public class GenericQuotaEditController extends BasicController {
 			}
 		}
 	}
-	/**
-	 * @return Quota the edited quota
-	 */
+
 	public Quota getQuota() {
 		if (currentQuota == null) throw new AssertException("getQuota called but currentQuota is null");
 		return currentQuota;
 	}
 		
-	/**
-	 * @see org.olat.core.gui.control.DefaultController#doDispose(boolean)
-	 */
+	@Override
 	protected void doDispose() {
 		//
 	}
diff --git a/src/main/java/org/olat/admin/quota/GenericQuotaViewController.java b/src/main/java/org/olat/admin/quota/GenericQuotaViewController.java
index 22d7d4467ed..a99dea8f064 100644
--- a/src/main/java/org/olat/admin/quota/GenericQuotaViewController.java
+++ b/src/main/java/org/olat/admin/quota/GenericQuotaViewController.java
@@ -44,7 +44,6 @@ public class GenericQuotaViewController extends BasicController {
 
 	private VelocityContainer myContent;
 	private QuotaForm quotaForm;
-	private boolean modalMode;
 	private Quota currentQuota;
 
 
@@ -57,12 +56,9 @@ public class GenericQuotaViewController extends BasicController {
 	 * @param ureq
 	 * @param wControl
 	 * @param quotaPath The path for which the quota should be edited
-	 * @param modalMode true: window will push to fullscreen and pop itself when finished. false: normal
-	 * controller mode, get initial component using getInitialComponent()
 	 */
-	GenericQuotaViewController(UserRequest ureq, WindowControl wControl, String relPath, boolean modalMode) {
+	GenericQuotaViewController(UserRequest ureq, WindowControl wControl, String relPath) {
 		super(ureq, wControl);
-		this.modalMode = modalMode;
 		
 		// check if quota foqf.cannot.del.defaultr this path already exists
 		QuotaManager qm = QuotaManager.getInstance();
@@ -86,7 +82,6 @@ public class GenericQuotaViewController extends BasicController {
 		QuotaManager qm = QuotaManager.getInstance();
 		myContent = createVelocityContainer("edit");
 		myContent.contextPut("notEnoughPrivilege", Boolean.FALSE);
-		myContent.contextPut("modalMode", Boolean.valueOf(modalMode));
 		myContent.contextPut("users",qm.getDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_USERS));
 		myContent.contextPut("powerusers",qm.getDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_POWER));
 		myContent.contextPut("groups",qm.getDefaultQuota(QuotaConstants.IDENTIFIER_DEFAULT_GROUPS));
diff --git a/src/main/java/org/olat/admin/quota/QuotaController.java b/src/main/java/org/olat/admin/quota/QuotaController.java
index 046a65fa8df..8675d98b93a 100644
--- a/src/main/java/org/olat/admin/quota/QuotaController.java
+++ b/src/main/java/org/olat/admin/quota/QuotaController.java
@@ -99,24 +99,20 @@ public class QuotaController extends BasicController {
 		putInitialPanel(main);
 	}
 
-	/**
-	 * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.components.Component, org.olat.core.gui.control.Event)
-	 */
+	@Override
 	public void event(UserRequest ureq, Component source, Event event) {
 		if(source == addQuotaButton){
 			// clean up old controller first
 			if (quotaEditCtr != null) removeAsListenerAndDispose(quotaEditCtr);
 			// start edit workflow in dedicated quota edit controller
 			removeAsListenerAndDispose(quotaEditCtr);
-			quotaEditCtr = new GenericQuotaEditController(ureq, getWindowControl(), null);
+			quotaEditCtr = new GenericQuotaEditController(ureq, getWindowControl());
 			listenTo(quotaEditCtr);
 			main.setContent(quotaEditCtr.getInitialComponent());
 		}
 	}
 
-	/**
-	 * @see org.olat.core.gui.control.DefaultController#event(org.olat.core.gui.UserRequest, org.olat.core.gui.control.Controller, org.olat.core.gui.control.Event)
-	 */
+	@Override
 	public void event(UserRequest ureq, Controller source, Event event) {
 		if (source == quotaEditCtr) {
 			if (event == Event.CHANGED_EVENT) {
@@ -146,17 +142,14 @@ public class QuotaController extends BasicController {
 						tableCtr.setTableDataModel(quotaTableModel);
 						showInfo("qf.deleted", q.getPath());
 					} else {
-						// default quotas can not be qf.cannot.del.default")deleted
+						// default quotas can not be deleted
 						showError("qf.cannot.del.default");
 					}
 				}
 			}
 		}
 
-		/**
-		 * 
-		 * @see org.olat.core.gui.control.DefaultController#doDispose(boolean)
-		 */
+		@Override
 		protected void doDispose() {
 			//
 		}
diff --git a/src/main/java/org/olat/admin/quota/QuotaManagerImpl.java b/src/main/java/org/olat/admin/quota/QuotaManagerImpl.java
index 2a66746c7d1..0a376e6bfc2 100644
--- a/src/main/java/org/olat/admin/quota/QuotaManagerImpl.java
+++ b/src/main/java/org/olat/admin/quota/QuotaManagerImpl.java
@@ -86,6 +86,7 @@ public class QuotaManagerImpl extends QuotaManager {
 	/**
 	 * @see org.olat.core.util.vfs.QuotaManager#createQuota(java.lang.String, java.lang.Long, java.lang.Long)
 	 */
+	@Override
 	public Quota createQuota(String path, Long quotaKB, Long ulLimitKB) {
 		return new QuotaImpl(path, quotaKB, ulLimitKB);
 	}
@@ -94,6 +95,7 @@ public class QuotaManagerImpl extends QuotaManager {
 	 * [called by spring]
 	 *
 	 */
+	@Override
 	public void init() {
 		quotaResource = resourceManager.findOrPersistResourceable(OresHelper.lookupType(Quota.class));
 		initDefaultQuotas(); // initialize default quotas
@@ -155,6 +157,7 @@ public class QuotaManagerImpl extends QuotaManager {
 	 * @param identifyer
 	 * @return
 	 */
+	@Override
 	public Quota getDefaultQuota(String identifyer) {
 		if (defaultQuotas == null) {
 			throw new OLATRuntimeException(QuotaManagerImpl.class, "Quota manager has not been initialized properly! Must call init() first.", null);
@@ -169,6 +172,7 @@ public class QuotaManagerImpl extends QuotaManager {
 	 * @param path
 	 * @return Quota object.
 	 */
+	@Override
 	public Quota getCustomQuota(String path) {
 		if (defaultQuotas == null) {
 			throw new OLATRuntimeException(QuotaManagerImpl.class, "Quota manager has not been initialized properly! Must call init() first.", null);
@@ -200,6 +204,7 @@ public class QuotaManagerImpl extends QuotaManager {
 	 * 
 	 * @param quota
 	 */
+	@Override
 	public void setCustomQuotaKB(Quota quota) {
 		if (defaultQuotas == null) {
 			throw new OLATRuntimeException(QuotaManagerImpl.class, "Quota manager has not been initialized properly! Must call init() first.", null);
@@ -224,6 +229,7 @@ public class QuotaManagerImpl extends QuotaManager {
 	 * @return true if quota successfully deleted or no such quota, false if quota
 	 *         not deleted because it was a default quota that can not be deleted
 	 */
+	@Override
 	public boolean deleteCustomQuota(Quota quota) {
 		if (defaultQuotas == null) {
 			throw new OLATRuntimeException(QuotaManagerImpl.class, "Quota manager has not been initialized properly! Must call init() first.", null);
@@ -299,6 +305,7 @@ public class QuotaManagerImpl extends QuotaManager {
 	 * @param identity
 	 * @return
 	 */
+	@Override
 	public Quota getDefaultQuotaDependingOnRole(Identity identity) {
 		if (BaseSecurityManager.getInstance().isIdentityPermittedOnResourceable(identity, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_AUTHOR)) { return getDefaultQuotaPowerUsers(); }
 		if (BaseSecurityManager.getInstance().isIdentityPermittedOnResourceable(identity, Constants.PERMISSION_HASROLE, Constants.ORESOURCE_ADMIN)) { return getDefaultQuotaPowerUsers(); }
@@ -312,6 +319,7 @@ public class QuotaManagerImpl extends QuotaManager {
 	 * @param identity
 	 * @return custom quota or quota depending on role
 	 */
+	@Override
 	public Quota getCustomQuotaOrDefaultDependingOnRole(Identity identity, String relPath) {
 		Quota quota = getCustomQuota(relPath);
 		if (quota == null) { // no custom quota
@@ -361,6 +369,7 @@ public class QuotaManagerImpl extends QuotaManager {
 	 * @param currentContainer2 Upload container (folder)
 	 * @return Upload limit on KB 
 	 */
+	@Override
 	public int getUploadLimitKB(long quotaKB2, long uploadLimitKB2, VFSContainer currentContainer2) {
 		if (quotaKB2 == Quota.UNLIMITED) {
 			if (uploadLimitKB2 == Quota.UNLIMITED) {
@@ -401,16 +410,13 @@ public class QuotaManagerImpl extends QuotaManager {
 		return true;
 	}
 
-	/**
-	 * @see org.olat.core.util.vfs.QuotaManager#getQuotaEditorInstance(org.olat.core.gui.UserRequest, org.olat.core.gui.control.WindowControl, java.lang.String, boolean)
-	 */
 	@Override
-	public Controller getQuotaEditorInstance(UserRequest ureq, WindowControl wControl, String relPath, boolean modalMode) {
+	public Controller getQuotaEditorInstance(UserRequest ureq, WindowControl wControl, String relPath) {
 		try {
-			return new GenericQuotaEditController(ureq, wControl, relPath, modalMode);
+			return new GenericQuotaEditController(ureq, wControl, relPath);
 		} catch (OLATSecurityException e) {
 			log.warn("Try to access the quota editor without enough privilege", e);
-			GenericQuotaViewController viewCtrl = new GenericQuotaViewController(ureq, wControl, relPath, modalMode);
+			GenericQuotaViewController viewCtrl = new GenericQuotaViewController(ureq, wControl, relPath);
 			viewCtrl.setNotEnoughPrivilegeMessage();
 			return viewCtrl;
 		}
@@ -418,8 +424,8 @@ public class QuotaManagerImpl extends QuotaManager {
 	
 
 	@Override
-	public Controller getQuotaViewInstance(UserRequest ureq, WindowControl wControl, String relPath, boolean modalMode) {
-		return new GenericQuotaViewController(ureq, wControl, relPath, modalMode);
+	public Controller getQuotaViewInstance(UserRequest ureq, WindowControl wControl, String relPath) {
+		return new GenericQuotaViewController(ureq, wControl, relPath);
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/admin/quota/_content/edit.html b/src/main/java/org/olat/admin/quota/_content/edit.html
index 12427daa48b..6a0d2a36381 100644
--- a/src/main/java/org/olat/admin/quota/_content/edit.html
+++ b/src/main/java/org/olat/admin/quota/_content/edit.html
@@ -19,10 +19,6 @@
 			<div class="o_button_group o_button_group_right">$r.render("qf.new")</div>
 		#end
 		<div class="o_info">$r.translate("qf.noquota")</div>
-		#if ($modalMode)
-			&nbsp;
-			$r.render("cancel")
-		#end
 	</fieldset>	
 #end
 <div class="panel panel-default">
diff --git a/src/main/java/org/olat/admin/user/UserAdminController.java b/src/main/java/org/olat/admin/user/UserAdminController.java
index be4c41ca2e7..9d0ca25e23d 100644
--- a/src/main/java/org/olat/admin/user/UserAdminController.java
+++ b/src/main/java/org/olat/admin/user/UserAdminController.java
@@ -410,7 +410,7 @@ public class UserAdminController extends BasicController implements Activateable
 				@Override
 				public Component create(UserRequest uureq) {
 					String relPath = FolderConfig.getUserHomes() + "/" + identity.getName();
-					quotaCtr = QuotaManager.getInstance().getQuotaEditorInstance(uureq, getWindowControl(), relPath, false);
+					quotaCtr = QuotaManager.getInstance().getQuotaEditorInstance(uureq, getWindowControl(), relPath);
 					return quotaCtr.getInitialComponent();
 				}
 			});
diff --git a/src/main/java/org/olat/collaboration/CollaborationToolsSettingsController.java b/src/main/java/org/olat/collaboration/CollaborationToolsSettingsController.java
index 16785b2389a..0c4e1c6a9fd 100644
--- a/src/main/java/org/olat/collaboration/CollaborationToolsSettingsController.java
+++ b/src/main/java/org/olat/collaboration/CollaborationToolsSettingsController.java
@@ -104,9 +104,9 @@ public class CollaborationToolsSettingsController extends BasicController {
 		if (ureq.getUserSession().getRoles().isOLATAdmin()) {
 			vc_collabtools.contextPut("isOlatAdmin", Boolean.TRUE);
 			if(managed) {
-				quotaCtr = QuotaManager.getInstance().getQuotaViewInstance(ureq, getWindowControl(), collabTools.getFolderRelPath(), false);
+				quotaCtr = QuotaManager.getInstance().getQuotaViewInstance(ureq, getWindowControl(), collabTools.getFolderRelPath());
 			} else {
-				quotaCtr = QuotaManager.getInstance().getQuotaEditorInstance(ureq, getWindowControl(), collabTools.getFolderRelPath(), false);
+				quotaCtr = QuotaManager.getInstance().getQuotaEditorInstance(ureq, getWindowControl(), collabTools.getFolderRelPath());
 			}
 			listenTo(quotaCtr);
 		} else {
diff --git a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdEditQuota.java b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdEditQuota.java
index 817a0a43271..3a629518960 100644
--- a/src/main/java/org/olat/core/commons/modules/bc/commands/CmdEditQuota.java
+++ b/src/main/java/org/olat/core/commons/modules/bc/commands/CmdEditQuota.java
@@ -63,7 +63,8 @@ public class CmdEditQuota extends DefaultController implements FolderCommand, Co
 		// cleanup old controller first
 		if (quotaEditController != null) quotaEditController.dispose();
 		// create a edit controller
-		quotaEditController = QuotaManager.getInstance().getQuotaEditorInstance(ureq, wControl, currentSecCallback.getQuota().getPath(), true);			quotaEditController.addControllerListener(this);
+		quotaEditController = QuotaManager.getInstance().getQuotaEditorInstance(ureq, wControl, currentSecCallback.getQuota().getPath());
+		quotaEditController.addControllerListener(this);
 		if (quotaEditController != null) {
 			setInitialComponent(quotaEditController.getInitialComponent());
 			return this;
diff --git a/src/main/java/org/olat/core/util/vfs/QuotaManager.java b/src/main/java/org/olat/core/util/vfs/QuotaManager.java
index f1a79eb6aaf..46e429c3e05 100644
--- a/src/main/java/org/olat/core/util/vfs/QuotaManager.java
+++ b/src/main/java/org/olat/core/util/vfs/QuotaManager.java
@@ -158,17 +158,15 @@ public abstract class QuotaManager {
 	 * The controller must fire the following events:
 	 * <ul> 
 	 * <li>Event.CANCELLED_EVENT</li>
-	 * <li>Event.CHANGED_EVENT</li>
 	 * </ul>
 	 * @param ureq
 	 * @param wControl
 	 * @param relPath
-	 * @param modalMode
 	 * @return
 	 */
-	public abstract Controller getQuotaEditorInstance(UserRequest ureq, WindowControl wControl, String relPath, boolean modalMode);
+	public abstract Controller getQuotaEditorInstance(UserRequest ureq, WindowControl wControl, String relPath);
 	
-	public abstract Controller getQuotaViewInstance(UserRequest ureq, WindowControl wControl, String relPath, boolean modalMode);
+	public abstract Controller getQuotaViewInstance(UserRequest ureq, WindowControl wControl, String relPath);
 	
 	/**
 	 * Check if a user has the rights to launch the quota editor tool
diff --git a/src/main/java/org/olat/ims/cp/ui/CPRuntimeController.java b/src/main/java/org/olat/ims/cp/ui/CPRuntimeController.java
index 0b66c48be24..e5ac3f46767 100644
--- a/src/main/java/org/olat/ims/cp/ui/CPRuntimeController.java
+++ b/src/main/java/org/olat/ims/cp/ui/CPRuntimeController.java
@@ -129,7 +129,7 @@ public class CPRuntimeController extends RepositoryEntryRuntimeController {
 			OLATResource resource = entry.getOlatResource();
 			OlatRootFolderImpl cpRoot = FileResourceManager.getInstance().unzipContainerResource(resource);
 			WindowControl bwControl = getSubWindowControl("Quota");
-			Controller quotaCtrl = quotaManager.getQuotaEditorInstance(ureq, addToHistory(ureq, bwControl), cpRoot.getRelPath(), false);
+			Controller quotaCtrl = quotaManager.getQuotaEditorInstance(ureq, addToHistory(ureq, bwControl), cpRoot.getRelPath());
 			pushController(ureq, translate("tab.quota.edit"), quotaCtrl);
 			setActiveTool(quotaLink);
 		}
diff --git a/src/main/java/org/olat/modules/webFeed/ui/FeedRuntimeController.java b/src/main/java/org/olat/modules/webFeed/ui/FeedRuntimeController.java
index c0a85a738a9..cafacc1898e 100644
--- a/src/main/java/org/olat/modules/webFeed/ui/FeedRuntimeController.java
+++ b/src/main/java/org/olat/modules/webFeed/ui/FeedRuntimeController.java
@@ -99,7 +99,7 @@ public class FeedRuntimeController extends RepositoryEntryRuntimeController {
 			RepositoryEntry entry = getRepositoryEntry();
 			OlatRootFolderImpl feedRoot = FileResourceManager.getInstance().getFileResourceRootImpl(entry.getOlatResource());
 			WindowControl bwControl = getSubWindowControl("Quota");
-			Controller quotaCtrl = quotaManager.getQuotaEditorInstance(ureq, addToHistory(ureq, bwControl), feedRoot.getRelPath(), false);
+			Controller quotaCtrl = quotaManager.getQuotaEditorInstance(ureq, addToHistory(ureq, bwControl), feedRoot.getRelPath());
 			pushController(ureq, translate("tab.quota.edit"), quotaCtrl);
 			setActiveTool(quotaLink);
 		}
-- 
GitLab