Index: inc/admin/lib.dc.page.php
===================================================================
--- inc/admin/lib.dc.page.php	(revision 2328)
+++ inc/admin/lib.dc.page.php	(revision 2487)
@@ -665,4 +665,6 @@
 		self::jsVar('dotclear.msg.confirm_delete_plugin',
 			__('Are you sure you want to delete "%s" plugin?')).
+		self::jsVar('dotclear.msg.confirm_delete_plugins',
+			__('Are you sure you want to delete selected plugins?')).
 		self::jsVar('dotclear.msg.use_this_theme',
 			__('Use this theme')).
@@ -671,4 +673,6 @@
 		self::jsVar('dotclear.msg.confirm_delete_theme',
 			__('Are you sure you want to delete "%s" theme?')).
+		self::jsVar('dotclear.msg.confirm_delete_themes',
+			__('Are you sure you want to delete selected themes?')).
 		self::jsVar('dotclear.msg.confirm_delete_backup',
 			__('Are you sure you want to delete this backup?')).
Index: inc/admin/lib.moduleslist.php
===================================================================
--- inc/admin/lib.moduleslist.php	(revision 2469)
+++ inc/admin/lib.moduleslist.php	(revision 2487)
@@ -522,4 +522,5 @@
 	{
 		echo
+		'<form action="'.$this->getURL().'" method="post" class="modules-form-actions">'.
 		'<div class="table-outer">'.
 		'<table id="'.html::escapeHTML($this->list_id).'" class="modules'.(in_array('expander', $cols) ? ' expandable' : '').'">'.
@@ -527,6 +528,13 @@
 
 		if (in_array('name', $cols)) {
+			$colspan = 1;
+			if (in_array('checkbox', $cols)) {
+				$colspan++;
+			}
+			if (in_array('icon', $cols)) {
+				$colspan++;
+			}
 			echo
-			'<th class="first nowrap"'.(in_array('icon', $cols) ? ' colspan="2"' : '').'>'.__('Name').'</th>';
+			'<th class="first nowrap"'.($colspan > 1 ? ' colspan="'.$colspan.'"' : '').'>'.__('Name').'</th>';
 		}
 
@@ -590,4 +598,12 @@
 			$tds = 0;
 
+			if (in_array('checkbox', $cols)) {
+				$tds++;
+				echo
+				'<td class="module-icon nowrap">'.
+				form::checkbox(array('modules['.$count.']', html::escapeHTML($this->list_id).'_modules_'.html::escapeHTML($id)), html::escapeHTML($id)).
+				'</td>';
+			}
+
 			if (in_array('icon', $cols)) {
 				$tds++;
@@ -601,5 +617,25 @@
 			$tds++;
 			echo
-			'<td class="module-name nowrap" scope="row">'.html::escapeHTML($module['name']).'</td>';
+			'<td class="module-name nowrap" scope="row">';
+			if (in_array('checkbox', $cols)) {
+				if (in_array('expander', $cols)) {
+					echo
+					html::escapeHTML($module['name']);
+				}
+				else {
+					echo
+					'<label for="'.html::escapeHTML($this->list_id).'_modules_'.html::escapeHTML($id).'">'.
+					html::escapeHTML($module['name']).
+					'</label>';
+				}
+			}
+			else {
+				echo
+				html::escapeHTML($module['name']).
+				form::hidden(array('modules['.$count.']'), html::escapeHTML($id));
+			}
+			echo
+			$this->core->formNonce().
+			'</td>';
 
 			# Display score only for debug purpose
@@ -645,13 +681,5 @@
 				'<td class="module-actions nowrap">'.
 
-				'<form action="'.$this->getURL().'" method="post">'.
-				'<div>'.
-				$this->core->formNonce().
-				form::hidden(array('module'), html::escapeHTML($id)).
-
-				implode(' ', $buttons).
-
-				'</div>'.
-				'</form>'.
+				'<div>'.implode(' ', $buttons).'</div>'.
 
 				'</td>';
@@ -732,18 +760,18 @@
 		}
 
-		if ($count > 1 && !empty($actions) && $this->core->auth->isSuperAdmin()) {
-			$buttons = $this->getGlobalActions($actions);
-
-			echo
-			'<form action="'.$this->getURL().'" method="post" class="global-actions-buttons">'.
-			'<div>'.
-			$this->core->formNonce().
-			form::hidden(array('modules'), '1').
-
-			implode(' ', $buttons).
-
-			'</div>'.
-			'</form>';
-		}
+		elseif ((in_array('checkbox', $cols) || $count > 1) && !empty($actions) && $this->core->auth->isSuperAdmin()) {
+			$buttons = $this->getGlobalActions($actions, in_array('checkbox', $cols));
+
+			if (!empty($buttons)) {
+				if (in_array('checkbox', $cols)) {
+					echo 
+					'<p class="checkboxes-helpers"></p>';
+				}
+				echo
+				'<div>'.implode(' ', $buttons).'</div>';
+			}
+		}
+		echo 
+		'</form>';
 
 		return $this;
@@ -769,5 +797,5 @@
 				case 'activate': if ($module['root_writable']) {
 					$submits[] =
-					'<input type="submit" name="activate" value="'.__('Activate').'" />';
+					'<input type="submit" name="activate['.html::escapeHTML($id).']" value="'.__('Activate').'" />';
 				} break;
 
@@ -775,5 +803,5 @@
 				case 'deactivate': if ($module['root_writable']) {
 					$submits[] =
-					'<input type="submit" name="deactivate" value="'.__('Deactivate').'" class="reset" />';
+					'<input type="submit" name="deactivate['.html::escapeHTML($id).']" value="'.__('Deactivate').'" class="reset" />';
 				} break;
 
@@ -782,5 +810,5 @@
 					$dev = !preg_match('!^'.$this->path_pattern.'!', $module['root']) && defined('DC_DEV') && DC_DEV ? ' debug' : '';
 					$submits[] =
-					'<input type="submit" class="delete '.$dev.'" name="delete" value="'.__('Delete').'" />';
+					'<input type="submit" class="delete '.$dev.'" name="delete['.html::escapeHTML($id).']" value="'.__('Delete').'" />';
 				} break;
 
@@ -788,5 +816,5 @@
 				case 'install': if ($this->path_writable) {
 					$submits[] =
-					'<input type="submit" name="install" value="'.__('Install').'" />';
+					'<input type="submit" name="install['.html::escapeHTML($id).']" value="'.__('Install').'" />';
 				} break;
 
@@ -794,5 +822,5 @@
 				case 'update': if ($this->path_writable) {
 					$submits[] =
-					'<input type="submit" name="update" value="'.__('Update').'" />';
+					'<input type="submit" name="update['.html::escapeHTML($id).']" value="'.__('Update').'" />';
 				} break;
 
@@ -816,8 +844,9 @@
 	 * Get global action buttons to add to modules list.
 	 *
-	 * @param	array	$actions	Actions keys
+	 * @param	array	$actions	      Actions keys
+	 * @param boolean   $with_selection Limit action to selected modules
 	 * @return	Array of actions buttons
 	 */
-	protected function getGlobalActions($actions)
+	protected function getGlobalActions($actions, $with_selection=false)
 	{
 		$submits = array();
@@ -830,5 +859,8 @@
 				case 'activate': if ($this->path_writable) {
 					$submits[] =
-					'<input type="submit" name="activate" value="'.__('Activate all plugins from this list').'" />';
+					'<input type="submit" name="activate" value="'.($with_selection ?
+						__('Activate selected plugins') :
+						__('Activate all plugins from this list')
+					).'" />';
 				} break;
 
@@ -836,5 +868,8 @@
 				case 'deactivate': if ($this->path_writable) {
 					$submits[] =
-					'<input type="submit" name="deactivate" value="'.__('Deactivate all plugins from this list').'" class="reset" />';
+					'<input type="submit" name="deactivate" value="'.($with_selection ?
+						__('Deactivate selected plugins') :
+						__('Deactivate all plugins from this list')
+					).'" />';
 				} break;
 
@@ -842,5 +877,8 @@
 				case 'update': if ($this->path_writable) {
 					$submits[] =
-					'<input type="submit" name="update" value="'.__('Update all plugins from this list').'" />';
+					'<input type="submit" name="update" value="'.($with_selection ?
+						__('Update selected plugins') :
+						__('Update all plugins from this list')
+					).'" />';
 				} break;
 
@@ -849,5 +887,5 @@
 
 					# --BEHAVIOR-- adminModulesListGetGlobalActions
-					$tmp = $this->core->callBehavior('adminModulesListGetGlobalActions', $this);
+					$tmp = $this->core->callBehavior('adminModulesListGetGlobalActions', $this, $with_selection);
 
 					if (!empty($tmp)) {
@@ -875,57 +913,19 @@
 		}
 
-		# Actions per module
-		if (!empty($_POST['module'])) {
-
-			$id = $_POST['module'];
-
-			if (!empty($_POST['activate'])) {
-
-				$enabled = $this->modules->getDisabledModules();
-				if (!isset($enabled[$id])) {
-					throw new Exception(__('No such plugin.'));
-				}
-
-				# --BEHAVIOR-- moduleBeforeActivate
-				$this->core->callBehavior('pluginBeforeActivate', $id);
-
-				$this->modules->activateModule($id);
-
-				# --BEHAVIOR-- moduleAfterActivate
-				$this->core->callBehavior('pluginAfterActivate', $id);
-
-				dcPage::addSuccessNotice(__('Plugin has been successfully activated.'));
-				http::redirect($this->getURL());
-			}
-
-			elseif (!empty($_POST['deactivate'])) {
-
-				if (!$this->modules->moduleExists($id)) {
-					throw new Exception(__('No such plugin.'));
-				}
-
-				$module = $this->modules->getModules($id);
-				$module['id'] = $id;
-
-				if (!$module['root_writable']) {
-					throw new Exception(__('You don\'t have permissions to deactivate this plugin.'));
-				}
-
-				# --BEHAVIOR-- moduleBeforeDeactivate
-				$this->core->callBehavior('pluginBeforeDeactivate', $module);
-
-				$this->modules->deactivateModule($id);
-
-				# --BEHAVIOR-- moduleAfterDeactivate
-				$this->core->callBehavior('pluginAfterDeactivate', $module);
-
-				dcPage::addSuccessNotice(__('Plugin has been successfully deactivated.'));
-				http::redirect($this->getURL());
-			}
-
-			elseif (!empty($_POST['delete'])) {
-
-				$disabled = $this->modules->getDisabledModules();
-				if (!isset($disabled[$id])) {
+		$modules = !empty($_POST['modules']) && is_array($_POST['modules']) ? array_values($_POST['modules']) : array();
+
+		if (!empty($_POST['delete'])) {
+
+			if (is_array($_POST['delete'])) {
+				$modules = array_keys($_POST['delete']);
+			}
+
+			$list = $this->modules->getDisabledModules();
+
+			$failed = false;
+			$count = 0;
+			foreach($modules as $id)
+			{
+				if (!isset($list[$id])) {
 
 					if (!$this->modules->moduleExists($id)) {
@@ -937,5 +937,6 @@
 
 					if (!$this->isDeletablePath($module['root'])) {
-						throw new Exception(__("You don't have permissions to delete this plugin."));
+						$failed = true;
+						continue;
 					}
 
@@ -952,16 +953,39 @@
 				}
 
-				dcPage::addSuccessNotice(__('Plugin has been successfully deleted.'));
-				http::redirect($this->getURL());
-			}
-			elseif (!empty($_POST['install'])) {
-
-				$updated = $this->store->get();
-				if (!isset($updated[$id])) {
-					throw new Exception(__('No such plugin.'));
-				}
-
-				$module = $updated[$id];
-				$module['id'] = $id;
+				$count++;
+			}
+
+			if (!$count && $failed) {
+				throw new Exception(__("You don't have permissions to delete this plugin."));
+			}
+			elseif ($failed) {
+				dcPage::addWarningNotice(__('Some plugins have not been delete.'));
+			}
+			else {
+				dcPage::addSuccessNotice(
+					__('Plugin has been successfully deleted.', 'Plugins have been successuflly deleted.', $count)
+				);
+			}
+			http::redirect($this->getURL());
+		}
+
+		elseif (!empty($_POST['install'])) {
+
+			if (is_array($_POST['install'])) {
+				$modules = array_keys($_POST['install']);
+			}
+
+			$list = $this->store->get();
+
+			if (empty($list)) {
+				throw new Exception(__('No such plugin.'));
+			}
+
+			$count = 0;
+			foreach($list as $id => $module) {
+
+				if (!in_array($id, $modules)) {
+					continue;
+				}
 
 				$dest = $this->getPath().'/'.basename($module['file']);
@@ -970,31 +994,118 @@
 				$this->core->callBehavior('pluginBeforeAdd', $module);
 
-				$ret_code = $this->store->process($module['file'], $dest);
+				$this->store->process($module['file'], $dest);
 
 				# --BEHAVIOR-- moduleAfterAdd
 				$this->core->callBehavior('pluginAfterAdd', $module);
 
-				dcPage::addSuccessNotice($ret_code == 2 ?
-					__('Plugin has been successfully updated.') :
-					__('Plugin has been successfully installed.')
+				$count++;
+			}
+
+			dcPage::addSuccessNotice(
+				__('Plugin has been successfully installed.', 'Plugins have been successuflly installed.', $count)
+			);
+			http::redirect($this->getURL());
+		}
+
+		elseif (!empty($_POST['activate'])) {
+
+			if (is_array($_POST['activate'])) {
+				$modules = array_keys($_POST['activate']);
+			}
+
+			$list = $this->modules->getDisabledModules();
+			if (empty($list)) {
+				throw new Exception(__('No such plugin.'));
+			}
+
+			$count = 0;
+			foreach($list as $id => $module) {
+
+				if (!in_array($id, $modules)) {
+					continue;
+				}
+
+				# --BEHAVIOR-- moduleBeforeActivate
+				$this->core->callBehavior('pluginBeforeActivate', $id);
+
+				$this->modules->activateModule($id);
+
+				# --BEHAVIOR-- moduleAfterActivate
+				$this->core->callBehavior('pluginAfterActivate', $id);
+
+				$count++;
+			}
+
+			dcPage::addSuccessNotice(
+				__('Plugin has been successfully activated.', 'Plugins have been successuflly activated.', $count)
+			);
+			http::redirect($this->getURL());
+		}
+
+		elseif (!empty($_POST['deactivate'])) {
+
+			if (is_array($_POST['deactivate'])) {
+				$modules = array_keys($_POST['deactivate']);
+			}
+
+			$list = $this->modules->getModules();
+			if (empty($list)) {
+				throw new Exception(__('No such plugin.'));
+			}
+
+			$failed = false;
+			$count = 0;
+			foreach($list as $id => $module) {
+
+				if (!in_array($id, $modules)) {
+					continue;
+				}
+
+				if (!$module['root_writable']) {
+					$failed = true;
+					continue;
+				}
+
+				$module[$id] = $id;
+
+				# --BEHAVIOR-- moduleBeforeDeactivate
+				$this->core->callBehavior('pluginBeforeDeactivate', $module);
+
+				$this->modules->deactivateModule($id);
+
+				# --BEHAVIOR-- moduleAfterDeactivate
+				$this->core->callBehavior('pluginAfterDeactivate', $module);
+
+				$count++;
+			}
+
+			if ($failed) {
+				dcPage::addWarningNotice(__('Some plugins have not been deactivated.'));
+			}
+			else {
+				dcPage::addSuccessNotice(
+					__('Plugin has been successfully deactivated.', 'Plugins have been successuflly deactivated.', $count)
 				);
-				http::redirect($this->getURL());
-			}
-
-			elseif (!empty($_POST['update'])) {
-
-				$updated = $this->store->get(true);
-				if (!isset($updated[$id])) {
-					throw new Exception(__('No such plugin.'));
-				}
-
-				if (!$this->modules->moduleExists($id)) {
-					throw new Exception(__('No such plugin.'));
-				}
-
-				$tab = count($updated) > 1 ? '' : '#plugins';
-
-				$module = $updated[$id];
-				$module['id'] = $id;
+			}
+			http::redirect($this->getURL());
+		}
+
+		elseif (!empty($_POST['update'])) {
+
+			if (is_array($_POST['update'])) {
+				$modules = array_keys($_POST['update']);
+			}
+
+			$list = $this->store->get(true);
+			if (empty($list)) {
+				throw new Exception(__('No such plugin.'));
+			}
+
+			$count = 0;
+			foreach($list as $module) {
+
+				if (!in_array($module['id'], $modules)) {
+					continue;
+				}
 
 				if (!self::$allow_multi_install) {
@@ -1016,106 +1127,15 @@
 				$this->core->callBehavior('pluginAfterUpdate', $module);
 
-				dcPage::addSuccessNotice(__('Plugin has been successfully updated.'));
-				http::redirect($this->getURL().$tab);
-			}
-			else {
-
-				# --BEHAVIOR-- adminModulesListDoActions
-				$this->core->callBehavior('adminModulesListDoActions', $this, $id, 'plugin');
-
-			}
-		}
-		# Global actions
-		elseif (!empty($_POST['modules'])) {
-
-			if (!empty($_POST['activate'])) {
-
-				$modules = $this->modules->getDisabledModules();
-				if (empty($modules)) {
-					throw new Exception(__('No such plugin.'));
-				}
-
-				foreach($modules as $id => $module) {
-
-					# --BEHAVIOR-- moduleBeforeActivate
-					$this->core->callBehavior('pluginBeforeActivate', $id);
-
-					$this->modules->activateModule($id);
-
-					# --BEHAVIOR-- moduleAfterActivate
-					$this->core->callBehavior('pluginAfterActivate', $id);
-
-				}
-
-				dcPage::addSuccessNotice(__('Plugins have been successfully activated.'));
-				http::redirect($this->getURL());
-			}
-
-			elseif (!empty($_POST['deactivate'])) {
-
-				$modules = $this->modules->getModules();
-				if (empty($modules)) {
-					throw new Exception(__('No such plugin.'));
-				}
-
-				$failed = false;
-				foreach($modules as $id => $module) {
-					$module[$id] = $id;
-
-					if (!$module['root_writable']) {
-						$failed = true;
-						continue;
-					}
-
-					# --BEHAVIOR-- moduleBeforeDeactivate
-					$this->core->callBehavior('pluginBeforeDeactivate', $module);
-
-					$this->modules->deactivateModule($id);
-
-					# --BEHAVIOR-- moduleAfterDeactivate
-					$this->core->callBehavior('pluginAfterDeactivate', $module);
-				}
-
-				if ($failed) {
-					dcPage::addWarningNotice(__('Some plugins have not been deactivated.'));
-				}
-				else {
-					dcPage::addSuccessNotice(__('Plugins have been successfully deactivated.'));
-				}
-				http::redirect($this->getURL());
-			}
-
-			elseif (!empty($_POST['update'])) {
-
-				$updated = $this->store->get(true);
-				if (empty($updated)) {
-					throw new Exception(__('No such plugin.'));
-				}
-
-				foreach($updated as $module) {
-
-					if (!self::$allow_multi_install) {
-						$dest = $module['root'].'/../'.basename($module['file']);
-					}
-					else {
-						$dest = $this->getPath().'/'.basename($module['file']);
-						if ($module['root'] != $dest) {
-							@file_put_contents($module['root'].'/_disabled', '');
-						}
-					}
-
-					# --BEHAVIOR-- moduleBeforeUpdate
-					$this->core->callBehavior('pluginBeforeUpdate', $module);
-
-					$this->store->process($module['file'], $dest);
-
-					# --BEHAVIOR-- moduleAfterUpdate
-					$this->core->callBehavior('pluginAfterUpdate', $module);
-				}
-
-				dcPage::addSuccessNotice(__('Plugins have been successfully updated.'));
-				http::redirect($this->getURL().'#plugins');
-			}
-		}
+				$count++;
+			}
+
+			$tab = $count && $count == count($list) ? '#plugins' : '#update';
+
+			dcPage::addSuccessNotice(
+				__('Plugin has been successfully updated.', 'Plugins have been successuflly updated.', $count)
+			);
+			http::redirect($this->getURL().$tab);
+		}
+
 		# Manual actions
 		elseif (!empty($_POST['upload_pkg']) && !empty($_FILES['pkg_file'])
@@ -1153,4 +1173,11 @@
 			);
 			http::redirect($this->getURL().'#plugins');
+		}
+
+		else {
+
+			# --BEHAVIOR-- adminModulesListDoActions
+			$this->core->callBehavior('adminModulesListDoActions', $this, $modules, 'plugin');
+
 		}
 
@@ -1344,4 +1371,5 @@
 	{
 		echo
+		'<form action="'.$this->getURL().'" method="post" class="modules-form-actions">'.
 		'<div id="'.html::escapeHTML($this->list_id).'" class="modules'.(in_array('expander', $cols) ? ' expandable' : '').' one-box">';
 
@@ -1376,5 +1404,23 @@
 			if (in_array('name', $cols) && !$current) {
 				$line .=
-				'<h4 class="module-name">'.html::escapeHTML($module['name']).'</h4>';
+				'<h4 class="module-name">';
+
+				if (in_array('checkbox', $cols)) {
+					$line .=
+					'<label for="'.html::escapeHTML($this->list_id).'_modules_'.html::escapeHTML($id).'">'.
+					form::checkbox(array('modules['.$count.']', html::escapeHTML($this->list_id).'_modules_'.html::escapeHTML($id)), html::escapeHTML($id)).
+					html::escapeHTML($module['name']).
+					'</label>';
+
+				}
+				else {
+					$line .=
+					form::hidden(array('modules['.$count.']'), html::escapeHTML($id)).
+					html::escapeHTML($module['name']);
+				}
+
+				$line .=
+				$this->core->formNonce().
+				'</h4>';
 			}
 
@@ -1409,5 +1455,21 @@
 			if (in_array('name', $cols) && $current) {
 				$line .=
-				'<h4 class="module-name">'.html::escapeHTML($module['name']).'</h4>';
+				'<h4 class="module-name">';
+
+				if (in_array('checkbox', $cols)) {
+					$line .=
+					'<label for="'.html::escapeHTML($this->list_id).'_modules_'.html::escapeHTML($id).'">'.
+					form::checkbox(array('modules['.$count.']', html::escapeHTML($this->list_id).'_modules_'.html::escapeHTML($id)), html::escapeHTML($id)).
+					html::escapeHTML($module['name']).
+					'</label>';
+				}
+				else {
+					$line .=
+					form::hidden(array('modules['.$count.']'), html::escapeHTML($id)).
+					html::escapeHTML($module['name']);
+				}
+
+				$line .=
+				'</h4>';
 			}
 
@@ -1502,13 +1564,5 @@
 			if (!empty($actions)) {
 				$line .=
-				'<form action="'.$this->getURL().'" method="post" class="actions-buttons">'.
-				'<p>'.
-				$this->core->formNonce().
-				form::hidden(array('module'), html::escapeHTML($id)).
-
-				implode(' ', $this->getActions($id, $module, $actions)).
-
-				'</p>'.
-				'</form>';
+				'<p>'.implode(' ', $this->getActions($id, $module, $actions)).'</p>';
 			}
 
@@ -1523,4 +1577,5 @@
 			$res = $current ? $line.$res : $res.$line;
 		}
+
 		echo
 		$res.
@@ -1532,18 +1587,16 @@
 		}
 
-		if ($count > 1 && !empty($actions) && $this->core->auth->isSuperAdmin()) {
-			$buttons = $this->getGlobalActions($actions);
-
-			echo
-			'<form action="'.$this->getURL().'" method="post" class="global-actions-buttons">'.
-			'<div>'.
-			$this->core->formNonce().
-			form::hidden(array('modules'), '1').
-
-			implode(' ', $buttons).
-
-			'</div>'.
-			'</form>';
-		}
+		elseif ((in_array('checkbox', $cols) || $count > 1) && !empty($actions) && $this->core->auth->isSuperAdmin()) {
+			$buttons = $this->getGlobalActions($actions, in_array('checkbox', $cols));
+
+			if (!empty($buttons)) {
+				echo '<div>'.implode(' ', $buttons).'</div>';
+			}
+		}
+
+		echo
+		'</form>';
+
+		return $this;
 	}
 
@@ -1558,5 +1611,5 @@
 			if (in_array('select', $actions) && $this->path_writable) {
 				$submits[] =
-				'<input type="submit" name="select" value="'.__('Use this one').'" />';
+				'<input type="submit" name="select['.html::escapeHTML($id).']" value="'.__('Use this one').'" />';
 			}
 		}
@@ -1568,5 +1621,5 @@
 	}
 
-	protected function getGlobalActions($actions)
+	protected function getGlobalActions($actions, $with_selection=false)
 	{
 		$submits = array();
@@ -1574,10 +1627,12 @@
 		foreach($actions as $action) {
 			switch($action) {
-
 
 				# Update (from store)
 				case 'update': if ($this->path_writable) {
 					$submits[] =
-					'<input type="submit" name="update" value="'.__('Update all themes from this list').'" />';
+					'<input type="submit" name="update" value="'.($with_selection ?
+						__('Update selected themes') :
+						__('Update all themes from this list')
+					).'" />';
 				} break;
 
@@ -1605,10 +1660,12 @@
 		}
 
-		# List actions
-		if (!empty($_POST['module'])) {
-
-			$id = $_POST['module'];
-
-			if (!empty($_POST['select'])) {
+		$modules = !empty($_POST['modules']) && is_array($_POST['modules']) ? array_values($_POST['modules']) : array();
+
+		if (!empty($_POST['select'])) {
+
+			# Can select only one theme at a time!
+			if (is_array($_POST['select'])) {
+				$modules = array_keys($_POST['select']);
+				$id = $modules[0];
 
 				if (!$this->modules->moduleExists($id)) {
@@ -1623,9 +1680,22 @@
 				http::redirect($this->getURL().'#themes');
 			}
-			elseif (!empty($_POST['activate'])) {
-
-				$enabled = $this->modules->getDisabledModules();
-				if (!isset($enabled[$id])) {
-					throw new Exception(__('No such theme.'));
+		}
+
+		elseif (!empty($_POST['activate'])) {
+
+			if (is_array($_POST['activate'])) {
+				$modules = array_keys($_POST['activate']);
+			}
+
+			$list = $this->modules->getDisabledModules();
+			if (empty($list)) {
+				throw new Exception(__('No such theme.'));
+			}
+
+			$count = 0;
+			foreach($list as $id => $module) {
+
+				if (!in_array($id, $modules)) {
+					continue;
 				}
 
@@ -1638,20 +1708,38 @@
 				$this->core->callBehavior('themeAfterActivate', $id);
 
-				dcPage::addSuccessNotice(__('Theme has been successfully activated.'));
-				http::redirect($this->getURL());
-			}
-
-			elseif (!empty($_POST['deactivate'])) {
-
-				if (!$this->modules->moduleExists($id)) {
-					throw new Exception(__('No such theme.'));
-				}
-
-				$module = $this->modules->getModules($id);
-				$module['id'] = $id;
+				$count++;
+			}
+
+			dcPage::addSuccessNotice(
+				__('Theme has been successfully activated.', 'Themes have been successuflly activated.', $count)
+			);
+			http::redirect($this->getURL());
+		}
+
+		elseif (!empty($_POST['deactivate'])) {
+
+			if (is_array($_POST['deactivate'])) {
+				$modules = array_keys($_POST['deactivate']);
+			}
+
+			$list = $this->modules->getModules();
+			if (empty($list)) {
+				throw new Exception(__('No such theme.'));
+			}
+
+			$failed = false;
+			$count = 0;
+			foreach($list as $id => $module) {
+
+				if (!in_array($id, $modules)) {
+					continue;
+				}
 
 				if (!$module['root_writable']) {
-					throw new Exception(__('You don\'t have permissions to deactivate this theme.'));
-				}
+					$failed = true;
+					continue;
+				}
+
+				$module[$id] = $id;
 
 				# --BEHAVIOR-- themeBeforeDeactivate
@@ -1663,15 +1751,34 @@
 				$this->core->callBehavior('themeAfterDeactivate', $module);
 
-				dcPage::addSuccessNotice(__('Theme has been successfully deactivated.'));
-				http::redirect($this->getURL());
-			}
-
-			elseif (!empty($_POST['delete'])) {
-
-				$disabled = $this->modules->getDisabledModules();
-				if (!isset($disabled[$id])) {
+				$count++;
+			}
+
+			if ($failed) {
+				dcPage::addWarningNotice(__('Some themes have not been deactivated.'));
+			}
+			else {
+				dcPage::addSuccessNotice(
+					__('Theme has been successfully deactivated.', 'Themes have been successuflly deactivated.', $count)
+				);
+			}
+			http::redirect($this->getURL());
+		}
+
+		elseif (!empty($_POST['delete'])) {
+
+			if (is_array($_POST['delete'])) {
+				$modules = array_keys($_POST['delete']);
+			}
+
+			$list = $this->modules->getDisabledModules();
+
+			$failed = false;
+			$count = 0;
+			foreach($modules as $id)
+			{
+				if (!isset($list[$id])) {
 
 					if (!$this->modules->moduleExists($id)) {
-						throw new Exception(__('No such module.'));
+						throw new Exception(__('No such theme.'));
 					}
 
@@ -1680,5 +1787,6 @@
 
 					if (!$this->isDeletablePath($module['root'])) {
-						throw new Exception(__("You don't have permissions to delete this theme."));
+						$failed = true;
+						continue;
 					}
 
@@ -1695,17 +1803,39 @@
 				}
 
-				dcPage::addSuccessNotice(__('Theme has been successfully deleted.'));
-				http::redirect($this->getURL());
-			}
-
-			elseif (!empty($_POST['install'])) {
-
-				$updated = $this->store->get();
-				if (!isset($updated[$id])) {
-					throw new Exception(__('No such theme.'));
-				}
-
-				$module = $updated[$id];
-				$module['id'] = $id;
+				$count++;
+			}
+
+			if (!$count && $failed) {
+				throw new Exception(__("You don't have permissions to delete this theme."));
+			}
+			elseif ($failed) {
+				dcPage::addWarningNotice(__('Some themes have not been delete.'));
+			}
+			else {
+				dcPage::addSuccessNotice(
+					__('Theme has been successfully deleted.', 'Themes have been successuflly deleted.', $count)
+				);
+			}
+			http::redirect($this->getURL());
+		}
+
+		elseif (!empty($_POST['install'])) {
+
+			if (is_array($_POST['install'])) {
+				$modules = array_keys($_POST['install']);
+			}
+
+			$list = $this->store->get();
+
+			if (empty($list)) {
+				throw new Exception(__('No such theme.'));
+			}
+
+			$count = 0;
+			foreach($list as $id => $module) {
+
+				if (!in_array($id, $modules)) {
+					continue;
+				}
 
 				$dest = $this->getPath().'/'.basename($module['file']);
@@ -1714,41 +1844,37 @@
 				$this->core->callBehavior('themeBeforeAdd', $module);
 
-				$ret_code = $this->store->process($module['file'], $dest);
+				$this->store->process($module['file'], $dest);
 
 				# --BEHAVIOR-- themeAfterAdd
 				$this->core->callBehavior('themeAfterAdd', $module);
 
-				dcPage::addSuccessNotice($ret_code == 2 ?
-					__('Theme has been successfully updated.') :
-					__('Theme has been successfully installed.')
-				);
-				http::redirect($this->getURL());
-			}
-
-			elseif (!empty($_POST['update'])) {
-
-				$updated = $this->store->get(true);
-				if (!isset($updated[$id])) {
-					throw new Exception(__('No such theme.'));
-				}
-
-				if (!$this->modules->moduleExists($id)) {
-					throw new Exception(__('No such theme.'));
-				}
-
-				$tab = count($updated) > 1 ? '' : '#themes';
-
-				$module = $updated[$id];
-				$module['id'] = $id;
-
-				if (!self::$allow_multi_install) {
-					$dest = $module['root'].'/../'.basename($module['file']);
-				}
-				else {
-					$dest = $this->getPath().'/'.basename($module['file']);
-					if ($module['root'] != $dest) {
-						@file_put_contents($module['root'].'/_disabled', '');
-					}
-				}
+				$count++;
+			}
+
+			dcPage::addSuccessNotice(
+				__('Theme has been successfully installed.', 'Themes have been successuflly installed.', $count)
+			);
+			http::redirect($this->getURL());
+		}
+
+		elseif (!empty($_POST['update'])) {
+
+			if (is_array($_POST['update'])) {
+				$modules = array_keys($_POST['update']);
+			}
+
+			$list = $this->store->get(true);
+			if (empty($list)) {
+				throw new Exception(__('No such theme.'));
+			}
+
+			$count = 0;
+			foreach($list as $module) {
+
+				if (!in_array($module['id'], $modules)) {
+					continue;
+				}
+
+				$dest = $module['root'].'/../'.basename($module['file']);
 
 				# --BEHAVIOR-- themeBeforeUpdate
@@ -1760,49 +1886,15 @@
 				$this->core->callBehavior('themeAfterUpdate', $module);
 
-				dcPage::addSuccessNotice(__('Theme has been successfully updated.'));
-				http::redirect($this->getURL().$tab);
-			}
-			else {
-
-				# --BEHAVIOR-- adminModulesListDoActions
-				$this->core->callBehavior('adminModulesListDoActions', $this, $id, 'theme');
-
-			}
-		}
-		# Global actions
-		elseif (!empty($_POST['modules'])) {
-
-			if (!empty($_POST['update'])) {
-
-				$updated = $this->store->get(true);
-				if (empty($updated)) {
-					throw new Exception(__('No such theme.'));
-				}
-
-				foreach($updated as $module) {
-
-					if (!self::$allow_multi_install) {
-						$dest = $module['root'].'/../'.basename($module['file']);
-					}
-					else {
-						$dest = $this->getPath().'/'.basename($module['file']);
-						if ($module['root'] != $dest) {
-							@file_put_contents($module['root'].'/_disabled', '');
-						}
-					}
-
-					# --BEHAVIOR-- moduleBeforeUpdate
-					$this->core->callBehavior('themesBeforeUpdate', $module);
-
-					$this->store->process($module['file'], $dest);
-
-					# --BEHAVIOR-- moduleAfterUpdate
-					$this->core->callBehavior('themesAfterUpdate', $module);
-				}
-
-				dcPage::addSuccessNotice(__('Themes have been successfully updated.'));
-				http::redirect($this->getURL().'#themes');
-			}
-		}
+				$count++;
+			}
+
+			$tab = $count && $count == count($list) ? '#themes' : '#update';
+
+			dcPage::addSuccessNotice(
+				__('Theme has been successfully updated.', 'Themes have been successuflly updated.', $count)
+			);
+			http::redirect($this->getURL().$tab);
+		}
+
 		# Manual actions
 		elseif (!empty($_POST['upload_pkg']) && !empty($_FILES['pkg_file'])
@@ -1842,4 +1934,11 @@
 		}
 
+		else {
+
+			# --BEHAVIOR-- adminModulesListDoActions
+			$this->core->callBehavior('adminModulesListDoActions', $this, $modules, 'theme');
+
+		}
+
 		return null;
 	}
