summaryrefslogtreecommitdiff
path: root/openerp/addons/base/module
diff options
context:
space:
mode:
authorThibault Delavallée <tde@openerp.com>2012-12-21 11:03:20 +0100
committerThibault Delavallée <tde@openerp.com>2012-12-21 11:03:20 +0100
commit5b3fc4061ba0c84f7e0ff466c4d7025f9cfa44e9 (patch)
treed07f2c5bb9ec0ce018b824f91caa5f6f1da9c090 /openerp/addons/base/module
parent919c0d1152ba869af49e4d9186698d35dbb89541 (diff)
parent73cb6d5321cc71d85456e6f6e61fc34b79b95c16 (diff)
[MERGE] Sync with trunk.
bzr revid: tde@openerp.com-20121221100320-ntn6zsdcqlvz52xn
Diffstat (limited to 'openerp/addons/base/module')
-rw-r--r--openerp/addons/base/module/module.py261
-rw-r--r--openerp/addons/base/module/module_view.xml99
-rw-r--r--openerp/addons/base/module/wizard/base_export_language_view.xml2
-rw-r--r--openerp/addons/base/module/wizard/base_module_import_view.xml2
-rw-r--r--openerp/addons/base/module/wizard/base_module_update_view.xml8
-rw-r--r--openerp/addons/base/module/wizard/base_module_upgrade_view.xml2
6 files changed, 242 insertions, 132 deletions
diff --git a/openerp/addons/base/module/module.py b/openerp/addons/base/module/module.py
index a10b38cf586..47a4cfc8174 100644
--- a/openerp/addons/base/module/module.py
+++ b/openerp/addons/base/module/module.py
@@ -24,12 +24,22 @@ from docutils.transforms import Transform, writer_aux
from docutils.writers.html4css1 import Writer
import imp
import logging
+import os
import re
+import shutil
+import tempfile
import urllib
+import urllib2
+import zipfile
import zipimport
+try:
+ from cStringIO import StringIO
+except ImportError:
+ from StringIO import StringIO # NOQA
+
import openerp
-from openerp import modules, pooler, release, tools, addons
+from openerp import modules, pooler, tools, addons
from openerp.modules.db import create_categories
from openerp.tools.parse_version import parse_version
from openerp.tools.translate import _
@@ -43,14 +53,29 @@ ACTION_DICT = {
'res_model': 'base.module.upgrade',
'target': 'new',
'type': 'ir.actions.act_window',
- 'nodestroy':True,
+ 'nodestroy': True,
}
+def backup(path, raise_exception=True):
+ path = os.path.normpath(path)
+ if not os.path.exists(path):
+ if not raise_exception:
+ return None
+ raise OSError('path does not exists')
+ cnt = 1
+ while True:
+ bck = '%s~%d' % (path, cnt)
+ if not os.path.exists(bck):
+ shutil.move(path, bck)
+ return bck
+ cnt += 1
+
+
class module_category(osv.osv):
_name = "ir.module.category"
_description = "Application"
- def _module_nbr(self,cr,uid, ids, prop, unknow_none, context):
+ def _module_nbr(self, cr, uid, ids, prop, unknow_none, context):
cr.execute('SELECT category_id, COUNT(*) \
FROM ir_module_module \
WHERE category_id IN %(ids)s \
@@ -58,7 +83,7 @@ class module_category(osv.osv):
FROM ir_module_category \
WHERE parent_id IN %(ids)s) \
GROUP BY category_id', {'ids': tuple(ids)}
- )
+ )
result = dict(cr.fetchall())
for id in ids:
cr.execute('select id from ir_module_category where parent_id=%s', (id,))
@@ -71,16 +96,16 @@ class module_category(osv.osv):
'parent_id': fields.many2one('ir.module.category', 'Parent Application', select=True),
'child_ids': fields.one2many('ir.module.category', 'parent_id', 'Child Applications'),
'module_nr': fields.function(_module_nbr, string='Number of Modules', type='integer'),
- 'module_ids' : fields.one2many('ir.module.module', 'category_id', 'Modules'),
- 'description' : fields.text("Description", translate=True),
- 'sequence' : fields.integer('Sequence'),
- 'visible' : fields.boolean('Visible'),
+ 'module_ids': fields.one2many('ir.module.module', 'category_id', 'Modules'),
+ 'description': fields.text("Description", translate=True),
+ 'sequence': fields.integer('Sequence'),
+ 'visible': fields.boolean('Visible'),
'xml_id': fields.function(osv.osv.get_external_id, type='char', size=128, string="External ID"),
}
_order = 'name'
_defaults = {
- 'visible' : 1,
+ 'visible': 1,
}
class MyFilterMessages(Transform):
@@ -119,7 +144,6 @@ class module(osv.osv):
info = {}
try:
info = modules.load_information_from_description_file(name)
- info['version'] = release.major_version + '.' + info['version']
except Exception:
_logger.debug('Error when trying to fetch informations for '
'module %s', name, exc_info=True)
@@ -134,9 +158,10 @@ class module(osv.osv):
return res
def _get_latest_version(self, cr, uid, ids, field_name=None, arg=None, context=None):
- res = dict.fromkeys(ids, '')
+ default_version = modules.adapt_version('1.0')
+ res = dict.fromkeys(ids, default_version)
for m in self.browse(cr, uid, ids):
- res[m.id] = self.get_module_info(m.name).get('version', '')
+ res[m.id] = self.get_module_info(m.name).get('version', default_version)
return res
def _get_views(self, cr, uid, ids, field_name=None, arg=None, context=None):
@@ -167,9 +192,11 @@ class module(osv.osv):
continue
# then, search and group ir.model.data records
- imd_models = dict( [(m,[]) for m in dmodels])
- imd_ids = model_data_obj.search(cr,uid,[('module','=', module_rec.name),
- ('model','in',tuple(dmodels))])
+ imd_models = dict([(m, []) for m in dmodels])
+ imd_ids = model_data_obj.search(cr, uid, [
+ ('module', '=', module_rec.name),
+ ('model', 'in', tuple(dmodels))
+ ])
for imd_res in model_data_obj.read(cr, uid, imd_ids, ['model', 'res_id'], context=context):
imd_models[imd_res['model']].append(imd_res['res_id'])
@@ -181,7 +208,7 @@ class module(osv.osv):
view_ids = imd_models.get('ir.ui.view', [])
for v in view_obj.browse(cr, uid, view_ids, context=context):
aa = v.inherit_id and '* INHERIT ' or ''
- res_mod_dic['views_by_module'].append(aa + v.name + '('+v.type+')')
+ res_mod_dic['views_by_module'].append('%s%s (%s)' % (aa, v.name, v.type))
report_ids = imd_models.get('ir.actions.report.xml', [])
for rx in report_obj.browse(cr, uid, report_ids, context=context):
@@ -191,15 +218,13 @@ class module(osv.osv):
for um in menu_obj.browse(cr, uid, menu_ids, context=context):
res_mod_dic['menus_by_module'].append(um.complete_name)
except KeyError, e:
- _logger.warning(
- 'Data not found for items of %s', module_rec.name)
+ _logger.warning('Data not found for items of %s', module_rec.name)
except AttributeError, e:
- _logger.warning(
- 'Data not found for items of %s %s', module_rec.name, str(e))
+ _logger.warning('Data not found for items of %s %s', module_rec.name, str(e))
except Exception, e:
- _logger.warning('Unknown error while fetching data of %s',
- module_rec.name, exc_info=True)
- for key, _ in res.iteritems():
+ _logger.warning('Unknown error while fetching data of %s', module_rec.name, exc_info=True)
+
+ for key in res.iterkeys():
for k, v in res[key].iteritems():
res[key][k] = "\n".join(sorted(v))
return res
@@ -232,36 +257,34 @@ class module(osv.osv):
# installed_version refer the latest version (the one on disk)
# latest_version refer the installed version (the one in database)
# published_version refer the version available on the repository
- 'installed_version': fields.function(_get_latest_version,
- string='Latest Version', type='char'),
+ 'installed_version': fields.function(_get_latest_version, string='Latest Version', type='char'),
'latest_version': fields.char('Installed Version', size=64, readonly=True),
'published_version': fields.char('Published Version', size=64, readonly=True),
'url': fields.char('URL', size=128, readonly=True),
'sequence': fields.integer('Sequence'),
- 'dependencies_id': fields.one2many('ir.module.module.dependency',
- 'module_id', 'Dependencies', readonly=True),
+ 'dependencies_id': fields.one2many('ir.module.module.dependency', 'module_id', 'Dependencies', readonly=True),
'auto_install': fields.boolean('Automatic Installation',
- help='An auto-installable module is automatically installed by the '
- 'system when all its dependencies are satisfied. '
- 'If the module has no dependency, it is always installed.'),
+ help='An auto-installable module is automatically installed by the '
+ 'system when all its dependencies are satisfied. '
+ 'If the module has no dependency, it is always installed.'),
'state': fields.selection([
- ('uninstallable','Not Installable'),
- ('uninstalled','Not Installed'),
- ('installed','Installed'),
- ('to upgrade','To be upgraded'),
- ('to remove','To be removed'),
- ('to install','To be installed')
+ ('uninstallable', 'Not Installable'),
+ ('uninstalled', 'Not Installed'),
+ ('installed', 'Installed'),
+ ('to upgrade', 'To be upgraded'),
+ ('to remove', 'To be removed'),
+ ('to install', 'To be installed')
], string='Status', readonly=True, select=True),
'demo': fields.boolean('Demo Data', readonly=True),
'license': fields.selection([
- ('GPL-2', 'GPL Version 2'),
- ('GPL-2 or any later version', 'GPL-2 or later version'),
- ('GPL-3', 'GPL Version 3'),
- ('GPL-3 or any later version', 'GPL-3 or later version'),
- ('AGPL-3', 'Affero GPL-3'),
- ('Other OSI approved licence', 'Other OSI Approved Licence'),
- ('Other proprietary', 'Other Proprietary')
+ ('GPL-2', 'GPL Version 2'),
+ ('GPL-2 or any later version', 'GPL-2 or later version'),
+ ('GPL-3', 'GPL Version 3'),
+ ('GPL-3 or any later version', 'GPL-3 or later version'),
+ ('AGPL-3', 'Affero GPL-3'),
+ ('Other OSI approved licence', 'Other OSI Approved Licence'),
+ ('Other proprietary', 'Other Proprietary')
], string='License', readonly=True),
'menus_by_module': fields.function(_get_views, string='Menus', type='text', multi="meta", store=True),
'reports_by_module': fields.function(_get_views, string='Reports', type='text', multi="meta", store=True),
@@ -283,7 +306,7 @@ class module(osv.osv):
return _('The name of the module must be unique !')
_sql_constraints = [
- ('name_uniq', 'UNIQUE (name)',_name_uniq_msg ),
+ ('name_uniq', 'UNIQUE (name)', _name_uniq_msg),
]
def unlink(self, cr, uid, ids, context=None):
@@ -292,10 +315,9 @@ class module(osv.osv):
if isinstance(ids, (int, long)):
ids = [ids]
mod_names = []
- for mod in self.read(cr, uid, ids, ['state','name'], context):
+ for mod in self.read(cr, uid, ids, ['state', 'name'], context):
if mod['state'] in ('installed', 'to upgrade', 'to remove', 'to install'):
- raise orm.except_orm(_('Error'),
- _('You try to remove a module that is installed or will be installed'))
+ raise orm.except_orm(_('Error'), _('You try to remove a module that is installed or will be installed'))
mod_names.append(mod['name'])
#Removing the entry from ir_model_data
#ids_meta = self.pool.get('ir.model.data').search(cr, uid, [('name', '=', 'module_meta_information'), ('module', 'in', mod_names)])
@@ -340,7 +362,7 @@ class module(osv.osv):
raise orm.except_orm(_('Error'), msg % (module_name, e.args[0]))
def state_update(self, cr, uid, ids, newstate, states_to_update, context=None, level=100):
- if level<1:
+ if level < 1:
raise orm.except_orm(_('Error'), _('Recursion error in modules dependencies !'))
demo = False
for module in self.browse(cr, uid, ids, context=context):
@@ -348,9 +370,9 @@ class module(osv.osv):
for dep in module.dependencies_id:
if dep.state == 'unknown':
raise orm.except_orm(_('Error'), _("You try to install module '%s' that depends on module '%s'.\nBut the latter module is not available in your system.") % (module.name, dep.name,))
- ids2 = self.search(cr, uid, [('name','=',dep.name)])
+ ids2 = self.search(cr, uid, [('name', '=', dep.name)])
if dep.state != newstate:
- mdemo = self.state_update(cr, uid, ids2, newstate, states_to_update, context, level-1,) or mdemo
+ mdemo = self.state_update(cr, uid, ids2, newstate, states_to_update, context, level - 1) or mdemo
else:
od = self.browse(cr, uid, ids2)[0]
mdemo = od.demo or mdemo
@@ -359,7 +381,7 @@ class module(osv.osv):
if not module.dependencies_id:
mdemo = module.demo
if module.state in states_to_update:
- self.write(cr, uid, [module.id], {'state': newstate, 'demo':mdemo})
+ self.write(cr, uid, [module.id], {'state': newstate, 'demo': mdemo})
demo = demo or mdemo
return demo
@@ -403,7 +425,7 @@ class module(osv.osv):
return self._button_immediate_function(cr, uid, ids, self.button_install, context=context)
def button_install_cancel(self, cr, uid, ids, context=None):
- self.write(cr, uid, ids, {'state': 'uninstalled', 'demo':False})
+ self.write(cr, uid, ids, {'state': 'uninstalled', 'demo': False})
return True
def module_uninstall(self, cr, uid, ids, context=None):
@@ -421,12 +443,13 @@ class module(osv.osv):
return True
def downstream_dependencies(self, cr, uid, ids, known_dep_ids=None,
- exclude_states=['uninstalled','uninstallable','to remove'],
+ exclude_states=['uninstalled', 'uninstallable', 'to remove'],
context=None):
"""Return the ids of all modules that directly or indirectly depend
on the given module `ids`, and that satisfy the `exclude_states`
filter"""
- if not ids: return []
+ if not ids:
+ return []
known_dep_ids = set(known_dep_ids or [])
cr.execute('''SELECT DISTINCT m.id
FROM
@@ -437,13 +460,13 @@ class module(osv.osv):
d.name IN (SELECT name from ir_module_module where id in %s) AND
m.state NOT IN %s AND
m.id NOT IN %s ''',
- (tuple(ids),tuple(exclude_states), tuple(known_dep_ids or ids)))
+ (tuple(ids), tuple(exclude_states), tuple(known_dep_ids or ids)))
new_dep_ids = set([m[0] for m in cr.fetchall()])
missing_mod_ids = new_dep_ids - known_dep_ids
known_dep_ids |= new_dep_ids
if missing_mod_ids:
known_dep_ids |= set(self.downstream_dependencies(cr, uid, list(missing_mod_ids),
- known_dep_ids, exclude_states,context))
+ known_dep_ids, exclude_states, context))
return list(known_dep_ids)
def _button_immediate_function(self, cr, uid, ids, function, context=None):
@@ -460,9 +483,9 @@ class module(osv.osv):
menu_obj = self.pool.get('ir.ui.menu')
menu_ids = menu_obj.search(cr, uid, [('parent_id', '=', False)], context=context)
return {
- 'type' : 'ir.actions.client',
- 'tag' : 'reload',
- 'params' : {'menu_id' : menu_ids and menu_ids[0] or False}
+ 'type': 'ir.actions.client',
+ 'tag': 'reload',
+ 'params': {'menu_id': menu_ids and menu_ids[0] or False}
}
def button_immediate_uninstall(self, cr, uid, ids, context=None):
@@ -496,20 +519,19 @@ class module(osv.osv):
self.update_list(cr, uid)
i = 0
- while i<len(todo):
+ while i < len(todo):
mod = todo[i]
i += 1
- if mod.state not in ('installed','to upgrade'):
- raise orm.except_orm(_('Error'),
- _("Can not upgrade module '%s'. It is not installed.") % (mod.name,))
+ if mod.state not in ('installed', 'to upgrade'):
+ raise orm.except_orm(_('Error'), _("Can not upgrade module '%s'. It is not installed.") % (mod.name,))
self.check_external_dependencies(mod.name, 'to upgrade')
iids = depobj.search(cr, uid, [('name', '=', mod.name)], context=context)
for dep in depobj.browse(cr, uid, iids, context=context):
- if dep.module_id.state=='installed' and dep.module_id not in todo:
+ if dep.module_id.state == 'installed' and dep.module_id not in todo:
todo.append(dep.module_id)
ids = map(lambda x: x.id, todo)
- self.write(cr, uid, ids, {'state':'to upgrade'}, context=context)
+ self.write(cr, uid, ids, {'state': 'to upgrade'}, context=context)
to_install = []
for mod in todo:
@@ -517,7 +539,7 @@ class module(osv.osv):
if dep.state == 'unknown':
raise orm.except_orm(_('Error'), _('You try to upgrade a module that depends on the module: %s.\nBut this module is not available in your system.') % (dep.name,))
if dep.state == 'uninstalled':
- ids2 = self.search(cr, uid, [('name','=',dep.name)])
+ ids2 = self.search(cr, uid, [('name', '=', dep.name)])
to_install.extend(ids2)
self.button_install(cr, uid, to_install, context=context)
@@ -550,8 +572,9 @@ class module(osv.osv):
# update the list of available packages
def update_list(self, cr, uid, context=None):
- res = [0, 0] # [update, add]
+ res = [0, 0] # [update, add]
+ default_version = modules.adapt_version('1.0')
known_mods = self.browse(cr, uid, self.search(cr, uid, []))
known_mods_names = dict([(m.name, m) for m in known_mods])
@@ -570,7 +593,7 @@ class module(osv.osv):
updated_values[key] = values[key]
if terp.get('installable', True) and mod.state == 'uninstallable':
updated_values['state'] = 'uninstalled'
- if parse_version(terp.get('version', '')) > parse_version(mod.latest_version or ''):
+ if parse_version(terp.get('version', default_version)) > parse_version(mod.latest_version or default_version):
res[0] += 1
if updated_values:
self.write(cr, uid, mod.id, updated_values)
@@ -587,24 +610,32 @@ class module(osv.osv):
self._update_dependencies(cr, uid, mod, terp.get('depends', []))
self._update_category(cr, uid, mod, terp.get('category', 'Uncategorized'))
+ # Trigger load_addons if new module have been discovered it exists on
+ # wsgi handlers, so they can react accordingly
+ if tuple(res) != (0, 0):
+ for handler in openerp.service.wsgi_server.module_handlers:
+ if hasattr(handler,'load_addons'):
+ handler.load_addons()
+
return res
def download(self, cr, uid, ids, download=True, context=None):
res = []
+ default_version = modules.adapt_version('1.0')
for mod in self.browse(cr, uid, ids, context=context):
if not mod.url:
continue
match = re.search('-([a-zA-Z0-9\._-]+)(\.zip)', mod.url, re.I)
- version = '0'
+ version = default_version
if match:
version = match.group(1)
- if parse_version(mod.installed_version or '0') >= parse_version(version):
+ if parse_version(mod.installed_version) >= parse_version(version):
continue
res.append(mod.url)
if not download:
continue
zip_content = urllib.urlopen(mod.url).read()
- fname = modules.get_module_path(str(mod.name)+'.zip', downloaded=True)
+ fname = modules.get_module_path(str(mod.name) + '.zip', downloaded=True)
try:
with open(fname, 'wb') as fp:
fp.write(zip_content)
@@ -614,17 +645,77 @@ class module(osv.osv):
raise orm.except_orm(_('Error'), _('Can not create the module file:\n %s') % (fname,))
terp = self.get_module_info(mod.name)
self.write(cr, uid, mod.id, self.get_values_from_terp(terp))
- cr.execute('DELETE FROM ir_module_module_dependency ' \
- 'WHERE module_id = %s', (mod.id,))
- self._update_dependencies(cr, uid, mod, terp.get('depends',
- []))
- self._update_category(cr, uid, mod, terp.get('category',
- 'Uncategorized'))
+ cr.execute('DELETE FROM ir_module_module_dependency WHERE module_id = %s', (mod.id,))
+ self._update_dependencies(cr, uid, mod, terp.get('depends', []))
+ self._update_category(cr, uid, mod, terp.get('category', 'Uncategorized'))
# Import module
zimp = zipimport.zipimporter(fname)
zimp.load_module(mod.name)
return res
+ def install_from_urls(self, cr, uid, urls, context=None):
+ OPENERP = 'openerp'
+ tmp = tempfile.mkdtemp()
+ try:
+ for module_name, url in urls.items():
+ if not url:
+ continue # nothing to download, local version is already the last one
+ try:
+ content = urllib2.urlopen(url).read()
+ except Exception, e:
+ _logger.exception('ggr')
+ raise osv.except_osv('grrr', e)
+ else:
+ zipfile.ZipFile(StringIO(content)).extractall(tmp)
+ assert os.path.isdir(os.path.join(tmp, module_name))
+
+ for module_name in urls:
+ if module_name == OPENERP:
+ continue # special case. handled below
+ module_path = modules.get_module_path(module_name, downloaded=True, display_warning=False)
+ bck = backup(module_path, False)
+ shutil.move(os.path.join(tmp, module_name), module_path)
+ if bck:
+ shutil.rmtree(bck)
+
+ if urls.get(OPENERP, None):
+ # special case. it containt the server and the base module.
+ # extract path is not the same
+
+ base_path = os.path.dirname(modules.get_module_path('base'))
+
+ # copy all modules in the SERVER/openerp/addons directory to the new "openerp" module (except base itself)
+ for d in os.listdir(base_path):
+ if d != 'base' and os.path.isdir(os.path.join(base_path, d)):
+ destdir = os.path.join(tmp, OPENERP, 'addons', d) # XXX 'openerp' subdirectory ?
+ shutil.copytree(os.path.join(base_path, d), destdir)
+
+ # then replace the server by the new "base" module
+ server_dir = openerp.tools.config['root_path'] # XXX or dirname()
+ bck = backup(server_dir)
+ shutil.move(os.path.join(tmp, OPENERP), server_dir)
+ #if bck:
+ # shutil.rmtree(bck)
+
+ self.update_list(cr, uid, context=context)
+
+ ids = self.search(cr, uid, [('name', 'in', urls.keys())], context=context)
+ if self.search_count(cr, uid, [('id', 'in', ids), ('state', '=', 'installed')], context=context):
+ # if any to update
+ cr.commit()
+ openerp.service.restart_server()
+ return {
+ 'type': 'ir.actions.client',
+ 'tag': 'home',
+ 'params': {'wait': True},
+ }
+ return self.button_immediate_install(cr, uid, ids, context=context)
+ finally:
+ shutil.rmtree(tmp)
+
+ def install_by_names(self, cr, uid, names, context=None):
+ raise NotImplementedError('# TODO')
+
def _update_dependencies(self, cr, uid, mod_browse, depends=None):
if depends is None:
depends = []
@@ -679,20 +770,20 @@ class module_dependency(osv.osv):
_columns = {
# The dependency name
- 'name': fields.char('Name', size=128, select=True),
+ 'name': fields.char('Name', size=128, select=True),
# The module that depends on it
'module_id': fields.many2one('ir.module.module', 'Module', select=True, ondelete='cascade'),
'state': fields.function(_state, type='selection', selection=[
- ('uninstallable','Uninstallable'),
- ('uninstalled','Not Installed'),
- ('installed','Installed'),
- ('to upgrade','To be upgraded'),
- ('to remove','To be removed'),
- ('to install','To be installed'),
+ ('uninstallable', 'Uninstallable'),
+ ('uninstalled', 'Not Installed'),
+ ('installed', 'Installed'),
+ ('to upgrade', 'To be upgraded'),
+ ('to remove', 'To be removed'),
+ ('to install', 'To be installed'),
('unknown', 'Unknown'),
- ], string='Status', readonly=True, select=True),
+ ], string='Status', readonly=True, select=True),
}
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/openerp/addons/base/module/module_view.xml b/openerp/addons/base/module/module_view.xml
index 5f33a437f08..3a43a2591ba 100644
--- a/openerp/addons/base/module/module_view.xml
+++ b/openerp/addons/base/module/module_view.xml
@@ -1,9 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
-
<!-- Modules Categories -->
-
<record id="view_module_category_form" model="ir.ui.view">
<field name="name">ir.module.category.form</field>
<field name="model">ir.module.category</field>
@@ -32,7 +30,6 @@
</record>
<!-- Click on a category -->
-
<record id="view_module_filter" model="ir.ui.view">
<field name="name">ir.module.module.list.select</field>
<field name="model">ir.module.module</field>
@@ -43,7 +40,7 @@
<filter name="app" icon="terp-check" string="Apps" domain="[('application', '=', 1)]"/>
<filter name="extra" icon="terp-check" string="Extra" domain="[('application', '=', 0)]"/>
<separator/>
- <filter icon="terp-check" string="Installed" domain="[('state', 'in', ['installed', 'to upgrade', 'to remove'])]"/>
+ <filter name="installed" icon="terp-check" string="Installed" domain="[('state', 'in', ['installed', 'to upgrade', 'to remove'])]"/>
<filter icon="terp-dialog-close" string="Not Installed" domain="[('state', 'in', ['uninstalled', 'uninstallable', 'to install'])]"/>
<field name="category_id"/>
<group expand="0" string="Group By...">
@@ -53,37 +50,6 @@
</search>
</field>
</record>
-
- <record model="ir.ui.view" id="module_view_kanban">
- <field name="name">Modules Kanban</field>
- <field name="model">ir.module.module</field>
- <field name="arch" type="xml">
- <kanban create="false">
- <field name="icon"/>
- <field name="name"/>
- <field name="state"/>
- <field name="summary"/>
- <templates>
- <t t-name="kanban-box">
- <div class="oe_module_vignette">
- <t t-set="installed" t-value="record.state.raw_value == 'installed'"/>
- <img t-attf-src="#{record.icon.value}" class="oe_module_icon"/>
- <div class="oe_module_desc">
- <h4><a type="open"><field name="shortdesc"/></a></h4>
- <p class="oe_module_name">
- <t t-if="record.summary.raw_value"><field name="summary"/><br/></t>
- <i><field name="name" groups="base.group_no_one"/></i>
- </p>
- <button type="object" name="button_immediate_install" states="uninstalled">Install</button>
- <button t-if="installed" disabled="disabled">Installed</button>
- </div>
- </div>
- </t>
- </templates>
- </kanban>
- </field>
- </record>
-
<record id="action_module_open_categ" model="ir.actions.act_window">
<field name="name">Modules</field>
<field name="res_model">ir.module.module</field>
@@ -100,7 +66,6 @@
<!-- Modules -->
-
<record id="module_form" model="ir.ui.view">
<field name="name">ir.module.module.form</field>
<field name="model">ir.module.module</field>
@@ -176,20 +141,74 @@
</tree>
</field>
</record>
+ <record model="ir.ui.view" id="module_view_kanban">
+ <field name="name">Modules Kanban</field>
+ <field name="model">ir.module.module</field>
+ <field name="arch" type="xml">
+ <kanban create="false">
+ <field name="icon"/>
+ <field name="name"/>
+ <field name="state"/>
+ <field name="summary"/>
+ <templates>
+ <t t-name="kanban-box">
+ <div class="oe_module_vignette">
+ <t t-set="installed" t-value="record.state.raw_value == 'installed'"/>
+ <img t-attf-src="#{record.icon.value}" class="oe_module_icon"/>
+ <div class="oe_module_desc">
+ <h4><a type="open"><field name="shortdesc"/></a></h4>
+ <p class="oe_module_name">
+ <t t-if="record.summary.raw_value"><field name="summary"/><br/></t>
+ <i><field name="name" groups="base.group_no_one"/></i>
+ </p>
+ <button type="object" name="button_immediate_install" states="uninstalled">Install</button>
+ <button t-if="installed" disabled="disabled">Installed</button>
+ </div>
+ </div>
+ </t>
+ </templates>
+ </kanban>
+ </field>
+ </record>
<record id="open_module_tree" model="ir.actions.act_window">
- <field name="name">Install a Module</field>
+ <!-- uncomment on released
+ <field name="name">Installed Modules</field>
+ -->
+ <field name="name">Modules</field>
<field name="res_model">ir.module.module</field>
<field name="view_type">form</field>
<field name="view_mode">kanban,tree,form</field>
- <field name="context">{'search_default_app':1}</field>
+ <!-- uncomment on released
+ <field name="context">{'search_default_installed':1}</field>
+ -->
<field name="search_view_id" ref="view_module_filter"/>
<field name="help" type="html">
<p><b>No module found!</b></p>
<p>You should try others search criteria.</p>
</field>
</record>
- <menuitem id="menu_module_tree" parent="base.menu_management" name="Modules"
- sequence="1" action="open_module_tree"/>
+ <menuitem id="menu_module_tree" parent="menu_management" name="Installed Modules" sequence="10" action="open_module_tree"/>
+
+
+ <!-- Apps modules -->
+ <record model="ir.actions.client" id="modules_act_cl">
+ <field name="name">Apps</field>
+ <field name="tag">apps</field>
+ </record>
+ <!-- uncomment on released
+ <menuitem id="module_mi" parent="base.menu_management" sequence="3" action="modules_act_cl"/>
+ -->
+ <menuitem id="module_mi" parent="base.menu_management" sequence="20" action="modules_act_cl"/>
+
+ <record model="ir.actions.client" id="modules_updates_act_cl">
+ <field name="name">Updates</field>
+ <field name="tag">apps.updates</field>
+ <field name="params">{}</field>
+ </record>
+ <!-- uncomment on released
+ <menuitem id="menu_module_updates" parent="base.menu_management" sequence="7" action="modules_updates_act_cl"/>
+ -->
+ <menuitem id="menu_module_updates" parent="base.menu_management" sequence="30" action="modules_updates_act_cl"/>
</data>
</openerp>
diff --git a/openerp/addons/base/module/wizard/base_export_language_view.xml b/openerp/addons/base/module/wizard/base_export_language_view.xml
index cbf7104f957..f184186a500 100644
--- a/openerp/addons/base/module/wizard/base_export_language_view.xml
+++ b/openerp/addons/base/module/wizard/base_export_language_view.xml
@@ -11,7 +11,7 @@
<group states="choose" string="Export Settings">
<field name="lang"/>
<field name="format"/>
- <field name="modules"/>
+ <field name="modules" widget="many2many_tags"/>
</group>
<div states="get">
<h2>Export Complete</h2>
diff --git a/openerp/addons/base/module/wizard/base_module_import_view.xml b/openerp/addons/base/module/wizard/base_module_import_view.xml
index 192bf6c2a92..d9d6bb6ee78 100644
--- a/openerp/addons/base/module/wizard/base_module_import_view.xml
+++ b/openerp/addons/base/module/wizard/base_module_import_view.xml
@@ -43,7 +43,7 @@
id="menu_view_base_module_import"
parent="menu_management"
groups="base.group_no_one"
- sequence="1"/>
+ sequence="6"/>
-->
</data>
diff --git a/openerp/addons/base/module/wizard/base_module_update_view.xml b/openerp/addons/base/module/wizard/base_module_update_view.xml
index 75d2b1316a6..cb9b9090294 100644
--- a/openerp/addons/base/module/wizard/base_module_update_view.xml
+++ b/openerp/addons/base/module/wizard/base_module_update_view.xml
@@ -18,17 +18,17 @@
</group>
<footer>
<div states="init">
- <button name="update_module" string="Update" type="object" class="oe_highlight"/> or
+ <button name="update_module" string="Update" type="object" class="oe_highlight"/> or
<button special="cancel" string="Cancel" class="oe_link"/>
</div>
<div states="done">
- <button name="action_module_open" string="Open Modules" type="object" class="oe_highlight"/> or
+ <button name="action_module_open" string="Open Modules" type="object" class="oe_highlight"/> or
<button special="cancel" string="Close" class="oe_link"/>
</div>
</footer>
</form>
</field>
- </record>
+ </record>
<record id="action_view_base_module_update" model="ir.actions.act_window">
<field name="name">Module Update</field>
@@ -45,7 +45,7 @@
id="menu_view_base_module_update"
groups="base.group_no_one"
parent="menu_management"
- sequence="2"
+ sequence="40"
icon="STOCK_CONVERT"/>
</data>
diff --git a/openerp/addons/base/module/wizard/base_module_upgrade_view.xml b/openerp/addons/base/module/wizard/base_module_upgrade_view.xml
index afd3a2e17b1..1a1225befcb 100644
--- a/openerp/addons/base/module/wizard/base_module_upgrade_view.xml
+++ b/openerp/addons/base/module/wizard/base_module_upgrade_view.xml
@@ -35,7 +35,7 @@
groups="base.group_no_one"
id="menu_view_base_module_upgrade"
parent="menu_management"
- sequence="3"/>
+ sequence="50"/>
<record id="view_base_module_upgrade_install" model="ir.ui.view">
<field name="name">Module Upgrade Install</field>