Index: /ipk/source.sh4/system_pluginsort/CONTROL/control
===================================================================
--- /ipk/source.sh4/system_pluginsort/CONTROL/control	(revision 13515)
+++ /ipk/source.sh4/system_pluginsort/CONTROL/control	(revision 13515)
@@ -0,0 +1,8 @@
+Package: enigma2-plugin-system-pluginsort
+Version: 1.0
+Architecture: sh4
+OE: PluginSort 1.0
+Section: extra
+Priority: optional
+Description: PluginSort v1.0 
+
Index: /ipk/source.sh4/system_pluginsort/CONTROL/postinst
===================================================================
--- /ipk/source.sh4/system_pluginsort/CONTROL/postinst	(revision 13515)
+++ /ipk/source.sh4/system_pluginsort/CONTROL/postinst	(revision 13515)
@@ -0,0 +1,13 @@
+#!/bin/sh
+TMP=/tmp/.system
+PLUGINDIR=/usr/lib/enigma2/python/Plugins/Extensions/PluginSort
+
+echo "successfully installed"
+echo "syncing disk"
+sync
+if [ `df | grep /dev/mtdblock | grep var | sed 's/ \+/ /g' | cut -d ' ' -f4 | tail -n1 | wc -l` -eq 1 ]; then
+	SPACE=`df | grep /dev/mtdblock | grep var | sed 's/ \+/ /g' | cut -d ' ' -f4 | tail -n1`
+	FREE=`expr $SPACE - 100`
+	echo new freespace size $FREE kb
+fi
+exit 0
Index: /ipk/source.sh4/system_pluginsort/CONTROL/postrm
===================================================================
--- /ipk/source.sh4/system_pluginsort/CONTROL/postrm	(revision 13515)
+++ /ipk/source.sh4/system_pluginsort/CONTROL/postrm	(revision 13515)
@@ -0,0 +1,14 @@
+#!/bin/sh
+TMP=/tmp/.system
+PLUGINDIR=/usr/lib/enigma2/python/Plugins/Extensions/PluginSort
+rm -r $PLUGINDIR > /dev/null 2>&1
+
+echo "successfully removed"
+echo "syncing disk"
+sync
+if [ `df | grep /dev/mtdblock | grep var | sed 's/ \+/ /g' | cut -d ' ' -f4 | tail -n1 | wc -l` -eq 1 ]; then
+	SPACE=`df | grep /dev/mtdblock | grep var | sed 's/ \+/ /g' | cut -d ' ' -f4 | tail -n1`
+	FREE=`expr $SPACE - 100`
+	echo new freespace size $FREE kb
+fi
+exit 0
Index: /ipk/source.sh4/system_pluginsort/CONTROL/preinst
===================================================================
--- /ipk/source.sh4/system_pluginsort/CONTROL/preinst	(revision 13515)
+++ /ipk/source.sh4/system_pluginsort/CONTROL/preinst	(revision 13515)
@@ -0,0 +1,46 @@
+#!/bin/sh
+#
+TMP=/tmp/.system
+echo "syncing disk"
+sync
+
+model=`cat /etc/model`
+echo""
+echo "Checking your Boxtype...."
+echo "Some Plugins will not work correctly on your $model!"
+echo ""
+if [ "$model" = "" ]; then
+	echo "Sorry! This Plugin is not available for your $model because it will not work correctly!!!"
+	echo "Aborting installation..."
+	exit 1
+else
+	echo "Boxtype: $model OK"
+fi
+
+if [ `df | grep /dev/mtdblock | grep var | sed 's/ \+/ /g' | cut -d ' ' -f4 | tail -n1 | wc -l` -eq 1 ]; then
+	SPACE=`df | grep /dev/mtdblock | grep var | sed 's/ \+/ /g' | cut -d ' ' -f4 | tail -n1`
+	FREE=`expr $SPACE - 100`
+	SIZE=65
+	echo "checking freespace"
+	echo packege size $SIZE kb
+	echo freespace size $FREE kb
+	if  [ "$FREE" -lt "$SIZE" ]; then
+		echo "sorry no freespace left on device"
+		exit 1
+	else
+		echo ok
+	fi
+fi   
+echo "installing PluginSort..."
+
+buildgroup=`cat /etc/.buildgroup`
+echo "checking OS"	 
+if  [ `cat /etc/motd | grep $buildgroup | grep M | grep rev | wc -l` -eq 0 ]; then 	 	 
+	echo --------------------------- 	 	 
+	echo DONT USE this IPK Package!! 	 	 
+	echo --- 	 	 
+	echo Only for $buildgroup Image!! 	 	 
+	echo --------------------------- 	 	 
+	exit 1 	 	 
+fi
+exit 0
Index: /ipk/source.sh4/system_pluginsort/CONTROL/prerm
===================================================================
--- /ipk/source.sh4/system_pluginsort/CONTROL/prerm	(revision 13515)
+++ /ipk/source.sh4/system_pluginsort/CONTROL/prerm	(revision 13515)
@@ -0,0 +1,11 @@
+#!/bin/sh
+TMP=/tmp/.system
+echo "syncing disk"
+sync
+if [ `df | grep /dev/mtdblock | grep var | sed 's/ \+/ /g' | cut -d ' ' -f4 | tail -n1 | wc -l` -eq 1 ]; then
+	SPACE=`df | grep /dev/mtdblock | grep var | sed 's/ \+/ /g' | cut -d ' ' -f4 | tail -n1`
+	FREE=`expr $SPACE - 100`
+	echo freespace size $FREE kb
+fi
+echo "removing PluginSort"
+exit 0
Index: /ipk/source.sh4/system_pluginsort/usr/lib/enigma2/python/Plugins/Extensions/PluginSort/LICENSE
===================================================================
--- /ipk/source.sh4/system_pluginsort/usr/lib/enigma2/python/Plugins/Extensions/PluginSort/LICENSE	(revision 13515)
+++ /ipk/source.sh4/system_pluginsort/usr/lib/enigma2/python/Plugins/Extensions/PluginSort/LICENSE	(revision 13515)
@@ -0,0 +1,14 @@
+All Files of this Software are licensed under the Creative Commons 
+Attribution-NonCommercial-ShareAlike 3.0 Unported 
+License if not stated otherwise in a Files Head. To view a copy of this license, visit
+http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to Creative
+Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
+
+Additionally, this plugin may only be distributed and executed on hardware which
+is licensed by Dream Multimedia GmbH.
+
+This plugin is NOT free software. It is open source, you are allowed to
+modify it (if you keep the license), but it may not be commercially 
+distributed other than under the conditions noted above.
+This applies to the source code as a whole as well as to parts of it, unless
+explicitely stated otherwise.
Index: /ipk/source.sh4/system_pluginsort/usr/lib/enigma2/python/Plugins/Extensions/PluginSort/__init__.py
===================================================================
--- /ipk/source.sh4/system_pluginsort/usr/lib/enigma2/python/Plugins/Extensions/PluginSort/__init__.py	(revision 13515)
+++ /ipk/source.sh4/system_pluginsort/usr/lib/enigma2/python/Plugins/Extensions/PluginSort/__init__.py	(revision 13515)
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+from Components.Language import language
+from Tools.Directories import resolveFilename, SCOPE_PLUGINS, SCOPE_LANGUAGE
+from os import environ as os_environ
+import gettext
+
+def localeInit():
+	lang = language.getLanguage()[:2] # getLanguage returns e.g. "fi_FI" for "language_country"
+	os_environ["LANGUAGE"] = lang # Enigma doesn't set this (or LC_ALL, LC_MESSAGES, LANG). gettext needs it!
+	gettext.bindtextdomain("PluginSort", resolveFilename(SCOPE_PLUGINS, "Extensions/PluginSort/locale"))
+
+def _(txt):
+	t = gettext.dgettext("PluginSort", txt)
+	if t == txt:
+		t = gettext.gettext(txt)
+	return t
+
+localeInit()
+language.addCallback(localeInit)
+
+
Index: /ipk/source.sh4/system_pluginsort/usr/lib/enigma2/python/Plugins/Extensions/PluginSort/maintainer.info
===================================================================
--- /ipk/source.sh4/system_pluginsort/usr/lib/enigma2/python/Plugins/Extensions/PluginSort/maintainer.info	(revision 13515)
+++ /ipk/source.sh4/system_pluginsort/usr/lib/enigma2/python/Plugins/Extensions/PluginSort/maintainer.info	(revision 13515)
@@ -0,0 +1,2 @@
+moritz.venn@freaque.net
+PluginSort
Index: /ipk/source.sh4/system_pluginsort/usr/lib/enigma2/python/Plugins/Extensions/PluginSort/mphelp.xml
===================================================================
--- /ipk/source.sh4/system_pluginsort/usr/lib/enigma2/python/Plugins/Extensions/PluginSort/mphelp.xml	(revision 13515)
+++ /ipk/source.sh4/system_pluginsort/usr/lib/enigma2/python/Plugins/Extensions/PluginSort/mphelp.xml	(revision 13515)
@@ -0,0 +1,23 @@
+<mphelp skin="PluginSortHelp" caption="PluginSort Help">
+	<page title="Welcome to PluginSort">
+		<text value="This guide is supposed to give you a quick look at how PluginSort works.
+\n\nYou can abort it at any time by pressing the RED or EXIT button on your remove control or bring it up at a later point by selection it from the context menu of the PluginBrowser by pressing the MENU button.
+\n\n\nBut you should really consider to take the few minutes it takes to read these help pages now instead of spending more on trying to find it out how to use this plugin afterwards." />
+	</page>
+	<page title="Stop stalling! Tell me what to do already.">
+		<text value="When inside the PluginBrowser, it behaves just as it normally would. Besides the fact that it is a whole lot different.
+\n\nIf the SoftwareManager is installed, you can gain access to the so-called Move-Mode by pressing the GREEN button on your remote control.
+\n\n\nFrom now on pressing OK will not launch a plugin, but instead the entry you had selected is highlighted and you can move it around using the LEFT, RIGHT, UP and DOWN buttons of your remote control.
+\nOnce you moved the plugin to a position of your liking, you can deselect it by pressing the OK button again." />
+	</page>
+	<page title="So that's all you can do?">
+		<text value="In addition to just being able to change the order of installed plugins inside the PluginBrowser, if you press the MENU button you can also change the order of plugins inside the Extensionsmenu, the EventInfo-Menu (hold the INFO button when watching TV) or the MovieSelection-Menu (press MENU when inside the MovieSelection).
+\n\nOnce you selected one of these options, you go to a modified PluginBrowser, which shows the respective plugins and you can change their order just as described on the previous page.
+\nThe changes are applied when leaving the editor using the RED or EXIT button on your remote control." />
+	</page>
+	<page title="Congratulations">
+		<text value="You have reached the end of this short guide and should know by now how to rearrange your installed plugins to your liking.
+\nIf you do not, you can bring these pages up at any later point by pressing the MENU button in the PluginBrowser and selecting the entry labeled &quot;Help&quot;.
+\n\n\nBefore sending you off to try out the plugin first hand, I want to point you at the fact that you are also able to start the first 10 plugins in the PluginBrowser by pressing the buttons 1 (for the first plugin) to 0 (for the tenth plugin) on your remote control." />
+	</page>
+</mphelp>
Index: /ipk/source.sh4/system_pluginsort/usr/lib/enigma2/python/Plugins/Extensions/PluginSort/plugin.py
===================================================================
--- /ipk/source.sh4/system_pluginsort/usr/lib/enigma2/python/Plugins/Extensions/PluginSort/plugin.py	(revision 13515)
+++ /ipk/source.sh4/system_pluginsort/usr/lib/enigma2/python/Plugins/Extensions/PluginSort/plugin.py	(revision 13515)
@@ -0,0 +1,509 @@
+from . import _
+
+# Plugin definition
+from Plugins.Plugin import PluginDescriptor
+
+from Screens import PluginBrowser
+from Screens.MessageBox import MessageBox
+from Screens.ChoiceBox import ChoiceBox
+from Components.PluginComponent import PluginComponent, plugins
+from Components.PluginList import PluginEntryComponent
+from Tools.Directories import resolveFilename, fileExists, SCOPE_SKIN_IMAGE, SCOPE_PLUGINS
+from Tools.BoundFunction import boundFunction
+from Screens.InfoBarGenerics import InfoBarPlugins
+from Components.config import config, ConfigSubsection, ConfigYesNo
+
+from Components.ActionMap import ActionMap, NumberActionMap
+from operator import attrgetter # python 2.5+
+
+from Components.MultiContent import MultiContentEntryText, MultiContentEntryPixmapAlphaTest
+
+from enigma import eListboxPythonMultiContent, gFont
+from Tools.LoadPixmap import LoadPixmap
+
+from xml.etree.cElementTree import parse as cet_parse
+try:
+	from xml.etree.cElementTree import ParseError
+except ImportError, ie:
+	ParseError = SyntaxError
+
+from shutil import copyfile, Error
+
+XML_CONFIG = "/etc/enigma2/pluginsort.xml"
+DEBUG = False
+
+config.plugins.pluginsort = ConfigSubsection()
+config.plugins.pluginsort.show_help = ConfigYesNo(default=True)
+
+def SelectedPluginEntryComponent(plugin):
+	if plugin.icon is None:
+		png = LoadPixmap(resolveFilename(SCOPE_SKIN_IMAGE, "skin_default/icons/plugin.png"))
+	else:
+		png = plugin.icon
+
+	return [
+		plugin,
+		MultiContentEntryText(pos=(0,0), size=(440, 50), backcolor_sel=8388608),
+		MultiContentEntryText(pos=(120, 5), size=(320, 25), font=0, text=plugin.name),
+		MultiContentEntryText(pos=(120, 26), size=(320, 17), font=1, text=plugin.description),
+		MultiContentEntryPixmapAlphaTest(pos=(10, 5), size=(100, 40), png = png),
+	]
+
+WHEREMAP = {}
+pdict = PluginDescriptor.__dict__
+for where in pdict:
+	if where.startswith('WHERE_'):
+		WHEREMAP[where] = pdict[where]
+del pdict
+reverse = lambda map: dict(zip(map.values(), map.keys()))
+
+class PluginWeights:
+	def __init__(self):
+		self.plugins = {}
+		self.load()
+
+	def load(self):
+		if not fileExists(XML_CONFIG):
+			return
+
+		try:
+			config = cet_parse(XML_CONFIG).getroot()
+		except ParseError, pe:
+			from time import time
+			print "[PluginSort] Parse Error occured in configuration, backing it up and starting from scratch!"
+			try:
+				copyfile(XML_CONFIG, "/etc/enigma2/pluginsort.xml.%d" % (int(time()),))
+			except Error, she:
+				print "[PluginSort] Uh oh, failed to create the backup... I hope you have one anyway :D"
+			return
+
+		for wheresection in config.findall('where'):
+			where = wheresection.get('type')
+			whereid = WHEREMAP.get(where, None)
+			whereplugins = wheresection.findall('plugin')
+			if whereid is None or not whereplugins:
+				print "[PluginSort] Ignoring section %s because of invalid id (%s) or no plugins (%s)" % (where, repr(whereid), repr(whereplugins))
+				continue
+
+			for plugin in whereplugins:
+				name = plugin.get('name')
+				try:
+					weight = int(plugin.get('weight'))
+				except ValueError, ve:
+					print "[PluginSort] Invalid weight of %s received for plugin %s, ignoring" % (repr(plugin.get('weight')), repr(name))
+				else:
+					self.plugins.setdefault(whereid, {})[name] = weight
+
+	def save(self):
+		list = ['<?xml version="1.0" ?>\n<pluginsort>\n\n']
+		append = list.append
+		extend = list.extend
+
+		idmap = reverse(WHEREMAP)
+		for key in self.plugins.keys():
+			whereplugins = self.plugins.get(key, None)
+			if not whereplugins:
+				continue
+
+			where = idmap[key]
+			extend((' <where type="', str(where), '">\n'))
+			for key, value in whereplugins.iteritems():
+				extend(('  <plugin name="', str(key), '" weight="', str(value), '" />\n'))
+			append((' </where>\n'))
+		append('\n</pluginsort>\n')
+		
+		file = open(XML_CONFIG, 'w')
+		file.writelines(list)
+		file.close()
+
+	def get(self, plugin):
+		for x in plugin.where:
+			whereplugins = self.plugins.get(x, None)
+			weight = whereplugins and whereplugins.get(plugin.name, None)
+			if weight is not None:
+				return weight
+		return plugin.weight
+
+	def set(self, plugin):
+		for x in plugin.where:
+			whereplugins = self.plugins.get(x, None)
+			if whereplugins:
+				whereplugins[plugin.name] = plugin.weight
+			else:
+				self.plugins[x] = {plugin.name: plugin.weight}
+
+pluginWeights = PluginWeights()
+
+def PluginComponent_addPlugin(self, plugin, *args, **kwargs):
+	if len(plugin.where) > 1:
+		print "[PluginSort] Splitting %s up in individual entries (%s)" % (plugin.name, repr(plugin.where))
+		for x in plugin.where:
+			pd = PluginDescriptor(name=plugin.name, where=[x], description=plugin.description, icon=plugin.icon, fnc=plugin.__call__, wakeupfnc=plugin.wakeupfnc, needsRestart=plugin.needsRestart, internal=plugin.internal, weight=plugin.weight)
+
+			newWeight = pluginWeights.get(pd)
+			if DEBUG: print "[PluginSort] Setting weight of %s from %d to %d" % (pd.name, pd.weight, newWeight)
+			pd.weight = newWeight
+			PluginComponent.pluginSort_baseAddPlugin(self, pd, *args, **kwargs)
+
+		# installedPluginList is a list of original descriptors, but we changed it to be a copy, not a reference. so keep it up to date
+		if self.firstRun:
+			self.installedPluginList.append(plugin)
+			if DEBUG: print "[PluginSort] Adding %s to list of installed plugins (%s, %s)." % (plugin.name, plugin.path, repr(plugin.where))
+		return
+
+	newWeight = pluginWeights.get(plugin)
+	if DEBUG: print "[PluginSort] Setting weight of %s from %d to %d" % (plugin.name, plugin.weight, newWeight)
+	plugin.weight = newWeight
+	PluginComponent.pluginSort_baseAddPlugin(self, plugin, *args, **kwargs)
+
+	if self.firstRun:
+		if DEBUG: print "[PluginSort] Adding %s to list of installed plugins (%s, %s)." % (plugin.name, plugin.path, repr(plugin.where))
+		self.installedPluginList.append(plugin)
+
+if DEBUG:
+	def PluginComponent_removePlugin(self, plugin, *args, **kwargs):
+		print "[PluginSort] Supposed to remove plugin: %s (%s, %s)." % (plugin.name, plugin.path, repr(plugin.where))
+		try:
+			PluginComponent.pluginSort_baseRemovePlugin(self, plugin, *args, **kwargs)
+		except ValueError, ve:
+			revMap = reverse(WHEREMAP)
+			print "-"*40
+			print "-"*40
+			print "-"*40
+			print "[PluginSort] pluginList: %s" % (repr([(x.name, x.path, repr([revMap[y] for y in x.where])) for x in self.pluginList]),)
+			for w in plugin.where:
+				print "[PluginSort] plugins[%s]: %s" % (revMap[w], repr([(x.name, x.path, repr([revMap[y] for y in x.where])) for x in self.plugins[w]]))
+	PluginComponent.pluginSort_baseRemovePlugin = PluginComponent.removePlugin
+	PluginComponent.removePlugin = PluginComponent_removePlugin
+
+OriginalPluginBrowser = PluginBrowser.PluginBrowser
+class SortingPluginBrowser(OriginalPluginBrowser):
+	def __init__(self, *args, **kwargs):
+		self.movemode = False
+		self.selected = -1
+		if 'where' in kwargs:
+			self.where = kwargs['where']
+			del kwargs['where']
+		else:
+			self.where = PluginDescriptor.WHERE_PLUGINMENU
+
+		OriginalPluginBrowser.__init__(self, *args, **kwargs)
+		self.skinName = ["SortingPluginBrowser", "PluginBrowser"]
+
+		self["ColorActions"] = ActionMap(["ColorActions"],
+			{
+				"green": self.toggleMoveMode,
+			}, -2
+		)
+		self["ColorActions"].setEnabled(False)
+
+		self["WizardActions"] = ActionMap(["WizardActions"],
+			{
+				"left": boundFunction(self.doMove, self["list"].pageUp),
+				"right": boundFunction(self.doMove, self["list"].pageDown),
+				"up": boundFunction(self.doMove, self["list"].up),
+				"down": boundFunction(self.doMove, self["list"].down),
+			}, -2
+		)
+
+		if self.where != PluginDescriptor.WHERE_PLUGINMENU:
+			self.toggleMoveMode()
+			self.onShow.append(self.setCustomTitle)
+		else:
+			self["NumberActions"] = NumberActionMap(["NumberActions"],
+				{
+					"1": self.keyNumberGlobal,
+					"2": self.keyNumberGlobal,
+					"3": self.keyNumberGlobal,
+					"4": self.keyNumberGlobal,
+					"5": self.keyNumberGlobal,
+					"6": self.keyNumberGlobal,
+					"7": self.keyNumberGlobal,
+					"8": self.keyNumberGlobal,
+					"9": self.keyNumberGlobal,
+					"0": self.keyNumberGlobal,
+				}, -2
+			)
+
+			self["MenuActions"] = ActionMap(["MenuActions"],
+				{
+					"menu": self.openMenu,
+				}, -1
+			)
+		self.onFirstExecBegin.append(self.firstExec)
+
+	def firstExec(self):
+		if config.plugins.pluginsort.show_help.value and pluginSortHelp:
+			config.plugins.pluginsort.show_help.value = False
+			config.plugins.pluginsort.show_help.save()
+			pluginSortHelp.open(self.session)
+
+	def setCustomTitle(self):
+		titleMap = {
+			PluginDescriptor.WHERE_EXTENSIONSMENU: _("Sort Extensions"),
+			PluginDescriptor.WHERE_MOVIELIST: _("Sort MovieList Extensions"),
+			PluginDescriptor.WHERE_EVENTINFO: _("Sort EventInfo Extensions"),
+		}
+		title = titleMap.get(self.where, None)
+		if title:
+			self.setTitle(title)
+
+	def keyNumberGlobal(self, number):
+		if not self.movemode:
+			realnumber = (number - 1) % 10
+			if realnumber < len(self.list):
+				self["list"].moveToIndex(realnumber)
+				self.save()
+
+	def close(self, *args, **kwargs):
+		if self.movemode:
+			self.toggleMoveMode()
+		OriginalPluginBrowser.close(self, *args, **kwargs)
+
+	# copied from PluginBrowser because we redo pretty much anything :-)
+	def updateList(self):
+		self.pluginlist = plugins.getPlugins(self.where)
+		if self.where in (PluginDescriptor.WHERE_PLUGINMENU, PluginDescriptor.WHERE_EXTENSIONSMENU):
+			self.pluginlist.sort(key=attrgetter('weight', 'name')) # sort first by weight, then by name; we get pretty much a weight sorted but otherwise random list
+		else: #if self.where in (PluginDescriptor.WHERE_EVENTINFO, PluginDescriptor.WHERE_MOVIELIST):
+			self.pluginlist.sort(key=attrgetter('weight'))
+		self.list = [PluginEntryComponent(plugin) for plugin in self.pluginlist]
+		self["list"].l.setList(self.list)
+		if self.where == PluginDescriptor.WHERE_PLUGINMENU:
+			if fileExists(resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/plugin.py")):
+				# TRANSLATORS: leaving this empty is encouraged to not cause any confusion (this string was taken directly from the standard PluginBrowser)
+				self["red"].setText(_("Manage extensions"))
+				self["green"].setText(_("Sort") if not self.movemode else _("End Sort"))
+				self["SoftwareActions"].setEnabled(True)
+				self["PluginDownloadActions"].setEnabled(False)
+				self["ColorActions"].setEnabled(True)
+			else:
+				# TRANSLATORS: leaving this empty is encouraged to not cause any confusion (this string was taken directly from the standard PluginBrowser)
+				self["red"].setText(_("Remove Plugins"))
+				# TRANSLATORS: leaving this empty is encouraged to not cause any confusion (this string was taken directly from the standard PluginBrowser)
+				self["green"].setText(_("Download Plugins"))
+				self["SoftwareActions"].setEnabled(False)
+				self["PluginDownloadActions"].setEnabled(True)
+				self["ColorActions"].setEnabled(False)
+		else:
+			self["red"].setText("")
+			self["green"].setText(_("Sort") if not self.movemode else _("End Sort"))
+			self["SoftwareActions"].setEnabled(False)
+			self["PluginDownloadActions"].setEnabled(False)
+			self["ColorActions"].setEnabled(True)
+
+	def doMove(self, func):
+		if self.selected != -1:
+			oldpos = self["list"].getSelectedIndex()
+			func()
+			entry = self.list.pop(oldpos)
+			newpos = self["list"].getSelectedIndex()
+			self.list.insert(newpos, entry)
+			self["list"].l.setList(self.list)
+		else:
+			func()
+
+	def save(self):
+		selected = self.selected
+		if not self.movemode:
+			OriginalPluginBrowser.save(self)
+		elif selected != -1:
+			Len = len(self.pluginlist)
+			newpos = self["list"].getSelectedIndex()
+			entry = self.pluginlist[selected]
+			self.pluginlist.remove(entry)
+			self.pluginlist.insert(newpos, entry)
+
+			# we moved up, increase weight of plugins after us
+			if newpos < selected:
+				print "[PluginSort]", entry.name, "moved up"
+				i = newpos + 1
+				# since we moved up, there has to be an entry after this one
+				diff = abs(self.pluginlist[i].weight - self.pluginlist[newpos].weight) + 1
+				print "[PluginSort] Using weight from %d (%d) and %d (%d) to calculate diff (%d)" % (i, self.pluginlist[i].weight, newpos, self.pluginlist[newpos].weight, diff)
+				while i < Len:
+					if DEBUG: print "[PluginSort] INCREASE WEIGHT OF", self.pluginlist[i].name, "BY", diff
+					self.pluginlist[i].weight += diff
+					i += 1
+			# we moved down, decrease weight of plugins before us
+			elif newpos > selected:
+				print "[PluginSort]", entry.name, "moved down"
+				i = newpos - 1
+				# since we moved up, there has to be an entry before this one
+				diff = abs(self.pluginlist[newpos].weight - self.pluginlist[i].weight) + 1
+				print "[PluginSort] Using weight from %d (%d) and %d (%d) to calculate diff (%d)" % (newpos, self.pluginlist[newpos].weight, i, self.pluginlist[i].weight, diff)
+				while i > -1:
+					if DEBUG: print "[PluginSort] DECREASE WEIGHT OF", self.pluginlist[i].name, "BY", diff
+					self.pluginlist[i].weight -= diff
+					i -= 1
+			else:
+				if DEBUG: print "[PluginSort]", entry.name, "did not move (%d to %d)?" % (selected, newpos)
+
+			self.list = [PluginEntryComponent(plugin) for plugin in self.pluginlist]
+			if DEBUG: print "[PluginSort] NEW LIST:", [(plugin.name, plugin.weight) for plugin in self.pluginlist]
+			self["list"].l.setList(self.list)
+			self.selected = -1
+		else:
+			self.selected = self["list"].getSelectedIndex()
+			self.list[self.selected] = SelectedPluginEntryComponent(self.pluginlist[self.selected])
+			self["list"].l.setList(self.list)
+	
+	def openMenu(self):
+		if self.movemode:
+			# TRANSLATORS: there is no need to translate this string, as it was reused from e2 core
+			moveString = _("disable move mode")
+		else:
+			# TRANSLATORS: there is no need to translate this string, as it was reused from e2 core
+			moveString = _("enable move mode")
+
+		list = [
+			(moveString, self.toggleMoveMode),
+			(_("move extensions"), boundFunction(self.openMover, PluginDescriptor.WHERE_EXTENSIONSMENU)),
+			(_("move movie extensions"), boundFunction(self.openMover, PluginDescriptor.WHERE_MOVIELIST)),
+			(_("move event extensions"), boundFunction(self.openMover, PluginDescriptor.WHERE_EVENTINFO)),
+		]
+
+		if fileExists(resolveFilename(SCOPE_PLUGINS, "Extensions/PluginHider/plugin.py")):
+			list.insert(0, (_("hide selected plugin"), self.hidePlugin))
+
+		if pluginSortHelp:
+			list.insert(0, (_("Help"), boundFunction(pluginSortHelp.open, self.session)))
+
+		self.session.openWithCallback(
+			self.menuCallback,
+			ChoiceBox,
+			list = list,
+		)
+
+	def menuCallback(self, ret):
+		ret and ret[1]()
+
+	def openMover(self, where):
+		self.session.open(SortingPluginBrowser, where=where)
+
+	def hidePlugin(self):
+		try:
+			from Plugins.Extensions.PluginHider.plugin import hidePlugin
+		except Exception, e:
+			self.session.open(MessageBox, _("Unable to load PluginHider"), MessageBox.TYPE_ERROR)
+		else:
+			hidePlugin(self["list"].l.getCurrentSelection()[0])
+
+			# we were actually in move mode, so save the current position
+			if self.selected != -1:
+				self.save()
+			self.updateList()
+
+	def toggleMoveMode(self):
+		if self.movemode:
+			if self.selected != -1:
+				self.save()
+			if fileExists(resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/plugin.py")):
+				self["green"].setText(_("Sort"))
+
+			for plugin in self.pluginlist:
+				pluginWeights.set(plugin)
+			pluginWeights.save()
+
+			# auto-close if not "PluginBrowser"
+			if self.where != PluginDescriptor.WHERE_PLUGINMENU:
+				self.movemode = False
+				return self.close()
+		else:
+			if fileExists(resolveFilename(SCOPE_PLUGINS, "SystemPlugins/SoftwareManager/plugin.py")):
+				self["green"].setText(_("End Sort"))
+		self.movemode = not self.movemode
+
+def autostart(reason, *args, **kwargs):
+	if reason == 0:
+		if hasattr(PluginComponent, 'pluginSort_baseAddPlugin'):
+			print "[PluginSort] Something went wrong as our autostart handler was called multiple times for startup, printing traceback and ignoring."
+			import traceback, sys
+			traceback.print_stack(limit=5, file=sys.stdout)
+		else:
+			PluginComponent.pluginSort_baseAddPlugin = PluginComponent.addPlugin
+			PluginComponent.addPlugin = PluginComponent_addPlugin
+
+			# we use a copy for installed plugins because we might change the 'where'-lists
+			plugins.installedPluginList = plugins.pluginList[:]
+			def PluginComponent__setattr__(self, key, value):
+				if key == 'installedPluginList': return
+				else: self.__dict__[key] = value
+			PluginComponent.__setattr__ = PluginComponent__setattr__
+
+			if hasattr(plugins, 'PluginComponent.pluginHider_baseGetPlugins'):
+				pluginlist = plugins.pluginHider_baseGetPlugins([PluginDescriptor.WHERE_PLUGINMENU, PluginDescriptor.WHERE_EXTENSIONSMENU, PluginDescriptor.WHERE_MOVIELIST, PluginDescriptor.WHERE_EVENTINFO])
+			else:
+				pluginlist = plugins.getPlugins([PluginDescriptor.WHERE_PLUGINMENU, PluginDescriptor.WHERE_EXTENSIONSMENU, PluginDescriptor.WHERE_MOVIELIST, PluginDescriptor.WHERE_EVENTINFO])
+
+			# "fix" weight of plugins already added to list, future ones will be fixed automatically
+			fixed = []
+			for plugin in pluginlist:
+				if plugin in fixed: continue # skip double entries
+
+				# create individual entries for multiple wheres, this is potentially harmful!
+				if len(plugin.where) > 1:
+					# remove all entries except for a potential autostart one (highly unlikely to mix autostart with one of the above, but you never know :D)
+					if PluginDescriptor.WHERE_AUTOSTART in plugin.where:
+						plugin.where.remove(PluginDescriptor.WHERE_AUTOSTART)
+						hadAutostart = True
+					else:
+						hadAutostart = False
+					plugins.removePlugin(plugin)
+					plugins.addPlugin(plugin) # this is our own addPlugin now, which automatically creates copies
+
+					# HACK: re-add autostart entry to internal list inside PluginComponent
+					if hadAutostart:
+						plugin.where = [ PluginDescriptor.WHERE_AUTOSTART ]
+						plugins.pluginList.append(plugin)
+
+				# we're keeping the entry, just fix the weight
+				else:
+					newWeight = pluginWeights.get(plugin)
+					print "[PluginSort] Fixing weight for %s (was %d, now %d)" % (plugin.name, plugin.weight, newWeight)
+					plugin.weight = newWeight
+
+				fixed.append(plugin)
+
+			# let movieepg fix extensions list sorting if installed, else do this ourselves
+			if not fileExists(resolveFilename(SCOPE_PLUGINS, "Extensions/MovieEPG/plugin.py")):
+				def InfoBarPlugins_getPluginList(self, *args, **kwargs):
+					l = InfoBarPlugins.pluginSort_baseGetPluginList(self, *args, **kwargs)
+					try:
+						l.sort(key=lambda e: (e[0][1].args[0].weight, e[2]))
+					except Exception, e:
+						print "[PluginSort] Failed to sort extensions", e
+					return l
+
+				InfoBarPlugins.pluginSort_baseGetPluginList = InfoBarPlugins.getPluginList
+				InfoBarPlugins.getPluginList = InfoBarPlugins_getPluginList
+
+
+			PluginBrowser.PluginBrowser = SortingPluginBrowser
+	else:
+		if hasattr(PluginComponent, 'pluginSort_baseAddPlugin'):
+			PluginComponent.addPlugin = PluginComponent.pluginSort_baseAddPlugin
+			del PluginComponent.pluginSort_baseAddPlugin
+		if hasattr(InfoBarPlugins, 'pluginSort_baseGetPluginList'):
+			InfoBarPlugins.getPluginList = InfoBarPlugins.pluginSort_baseGetPluginList
+			del InfoBarPlugins.pluginSort_baseGetPluginList
+		PluginBrowser.PluginBrowser = OriginalPluginBrowser
+
+#pragma mark - Help
+try:
+	from Plugins.SystemPlugins.MPHelp import registerHelp, showHelp, XMLHelpReader
+	reader = XMLHelpReader(resolveFilename(SCOPE_PLUGINS, "Extensions/PluginSort/mphelp.xml"))
+	pluginSortHelp = registerHelp(*reader)
+except Exception, e:
+	print "[PluginSort] Unable to initialize MPHelp:", e,"- Help not available!"
+	pluginSortHelp = None
+#pragma mark -
+
+def Plugins(**kwargs):
+	return [
+		PluginDescriptor(
+			where=PluginDescriptor.WHERE_AUTOSTART,
+			fnc=autostart,
+			needsRestart=True,
+		),
+	]
