diff --git a/fields/ref.py b/fields/ref.py index 69fa1e9..49c361b 100644 --- a/fields/ref.py +++ b/fields/ref.py @@ -52,6 +52,16 @@ class Ref(Field): 'display:none'">::tied.o.getSubTitle() ''') + # This PX displays buttons for triggering global actions on several linked + # objects (delete many, unlink many,...) + pxGlobalActions = Px(''' + + + ''') + # This PX displays icons for triggering actions on a given referenced object # (edit, delete, etc). pxObjectActions = Px(''' @@ -88,14 +98,17 @@ class Ref(Field): - - @@ -137,7 +150,6 @@ class Ref(Field): # PX that displays referred objects as a list. pxViewList = Px(''' -
@@ -174,67 +186,86 @@ class Ref(Field):

:_('no_ref')

-
- -
- - - - - - - - -
- :_(refField.labelId) - :field.pxSortIcons - :tool.pxShowDetails -
- - - :field.pxObjectTitle -
:field.pxObjectActions
-
- - - :field.pxRender - -
+ + + + + + + + +
+ :_(refField.labelId) + :field.pxSortIcons + :tool.pxShowDetails + + +
+ + + :field.pxObjectTitle +
:field.pxObjectActions
+
+ + + :field.pxRender + +
+
+ +
:field.pxGlobalActions
+ :tool.pxNavigate - ''') + + + + ''') # PX that displays the list of objects the user may select to insert into a # ref field with link="list". pxViewPickList = Px(''' - :field.pxViewList''') # PX that displays referred objects as menus. @@ -269,12 +300,15 @@ class Ref(Field):
''') - # PX that displays referred objects through this field. + # PX that displays referred objects through this field. In mode link="list", + # if, in the request, key "scope" is present and holds value "objs", the + # pick list (containing possible values) will not be rendered. pxView = Px(''' - :field.pxViewPickList + + +
:field.pxViewPickList
:field.pxViewList + var2="subLabel=linkList and 'selected_objects' or None"> +
:field.pxViewList
+ :field.pxViewList +
:field.pxViewMenus ''') @@ -356,10 +398,10 @@ class Ref(Field): width=None, height=5, maxChars=None, colspan=1, master=None, masterValue=None, focus=False, historized=False, mapping=None, label=None, queryable=False, queryFields=None, queryNbCols=1, - navigable=False, changeOrder=True, sdefault='', scolspan=1, - swidth=None, sheight=None, sselect=None, persist=True, - render='list', menuIdMethod=None, menuInfoMethod=None, - menuUrlMethod=None): + navigable=False, changeOrder=True, checkboxes=True, + sdefault='', scolspan=1, swidth=None, sheight=None, + sselect=None, persist=True, render='list', menuIdMethod=None, + menuInfoMethod=None, menuUrlMethod=None): self.klass = klass self.attribute = attribute # May the user add new objects through this ref ? @@ -444,9 +486,13 @@ class Ref(Field): self.queryNbCols = queryNbCols # Within the portlet, will referred elements appear ? self.navigable = navigable - # If changeOrder is False, it even if the user has the right to modify + # If "changeOrder" is False, it even if the user has the right to modify # the field, it will not be possible to move objects or sort them. self.changeOrder = changeOrder + # If "checkboxes" is True, every linked object will be "selectable" vi + # a checkbox: global actions will be possible, that will act on the + # subset of selected objects: delete, unlink, etc. + self.checkboxes = checkboxes # There are different ways to render a bunch of linked objects: # - "list" (the default) renders them as a list (=a XHTML table); # - "menus" renders them as a series of popup menus, grouped by type. @@ -708,9 +754,12 @@ class Ref(Field): elif nbOfRefs > maxRef: return obj.translate('max_ref_violated') - def linkObject(self, obj, value, back=False): + def linkObject(self, obj, value, back=False, noSecurity=True): '''This method links p_value (which can be a list of objects) to p_obj through this Ref field.''' + # Security check + if not noSecurity: obj.allows(self.writePermission, raiseError=True) + # p_value can be a list of objects if type(value) in sutils.sequenceTypes: for v in value: self.linkObject(obj, v, back=back) @@ -736,9 +785,11 @@ class Ref(Field): # Update the back reference if not back: self.back.linkObject(value, obj, back=True) - def unlinkObject(self, obj, value, back=False): + def unlinkObject(self, obj, value, back=False, noSecurity=True): '''This method unlinks p_value (which can be a list of objects) from p_obj through this Ref field.''' + # Security check + if not noSecurity: obj.allows(self.writePermission, raiseError=True) # p_value can be a list of objects if type(value) in sutils.sequenceTypes: for v in value: self.unlinkObject(obj, v, back=back) @@ -827,6 +878,39 @@ class Ref(Field): else: return self.callMethod(obj, self.changeOrder) + def checkboxesEnabled(self, obj): + '''Are checkboxes enabled?''' + if isinstance(self.checkboxes, bool): + return self.checkboxes + else: + return self.callMethod(obj, self.checkboxes) + + def getCbJsInit(self, obj): + '''When checkboxes are enabled, this method defines a JS associative + array (named "_appy_objs_cbs") that will store checkboxes' statuses. + This array is needed because all linked objects are not visible at + the same time (pagination). + + Moreover, if self.link is "list", an additional array (named + "_appy_poss_cbs") is defined for possible values. + + Initial semantics of this (those) array(s) is as follows: if a key + is present in it for a given linked object, it means that the + checkbox is unchecked. All linked objects are thus selected by + default. This semantics may be inverted: presence of a key may mean + that the checkbox is checked. The current array semantics is stored + in a variable named "_appy_objs_sem" (or "_appy_poss_sem") and may + hold "unchecked" (initial semantics) or "checked" (inversed + semantics). Inversing semantic allows to keep the array small even + when checking/unchecking all checkboxes. + + The mentioned JS arrays and variables are stored as attributes of the + DOM node representing this field.''' + code = "\nnode['_appy_%s_cbs']={};\nnode['_appy_%s_sem']='unchecked';" + poss = (self.link == 'list') and (code % ('poss', 'poss')) or '' + return "var node=document.getElementById('%s_%s');%s%s" % \ + (obj.id, self.name, code % ('objs', 'objs'), poss) + def doChangeOrder(self, obj): '''Moves a referred object up or down.''' rq = obj.REQUEST @@ -877,6 +961,37 @@ class Ref(Field): reverse = rq.get('reverse') == 'True' obj.appy().sort(self.name, sortKey=sortKey, reverse=reverse) + def onUiRequest(self, obj, rq): + '''This method is called when an action tied to this Ref field is + triggered from the user interface (link, unlink, link_many, + unlink_many...).''' + action = rq['linkAction'] + tool = obj.getTool() + if action == 'link': + tied = tool.getObject(rq['targetUid']) + self.linkObject(obj, tied, noSecurity=False) + elif action == 'unlink': + tied = tool.getObject(rq['targetUid']) + self.unlinkObject(obj, tied, noSecurity=False) + elif action == 'link_many': + uids = rq['targetUid'].strip(',') or (); + if uids: uids = uids.split(',') + unchecked = rq['semantics'] == 'unchecked' + # Browse possible values + for tied in self.getPossibleValues(obj, removeLinked=True): + if unchecked: + # Keep only tied objects not among uids. + if tied.uid in uids: continue + else: + # Keep only tied objects being in uids. + if tied.uid not in uids: continue + self.linkObject(obj, tied.o, noSecurity=False) + elif action == 'unlink_many': + pass + urlBack = obj.getUrl(rq['HTTP_REFERER']) + obj.say(obj.translate('action_done')) + tool.goto(urlBack) + def autoref(klass, field): '''klass.field is a Ref to p_klass. This kind of auto-reference can't be declared in the "normal" way, like this: diff --git a/gen/mixins/__init__.py b/gen/mixins/__init__.py index da8fd2a..41d9c6f 100644 --- a/gen/mixins/__init__.py +++ b/gen/mixins/__init__.py @@ -179,29 +179,13 @@ class BaseMixin: (appy.user.login, appy.klass.__name__, appy.uid)) self.goto(self.getUrl(rq['HTTP_REFERER'])) - def onUnlink(self): - '''Called when an object unlinking is triggered from the ui.''' - rq = self.REQUEST - tool = self.getTool() - sourceObject = tool.getObject(rq['sourceUid']) - targetObject = tool.getObject(rq['targetUid']) - field = sourceObject.getAppyType(rq['fieldName']) - field.unlinkObject(sourceObject, targetObject) - urlBack = self.getUrl(rq['HTTP_REFERER']) - self.say(self.translate('action_done')) - self.goto(urlBack) - def onLink(self): - '''Called when an object linking is triggered from the ui.''' + '''Called when object (un)linking is triggered from the ui.''' rq = self.REQUEST tool = self.getTool() sourceObject = tool.getObject(rq['sourceUid']) - targetObject = tool.getObject(rq['targetUid']) field = sourceObject.getAppyType(rq['fieldName']) - field.linkObject(sourceObject, targetObject) - urlBack = self.getUrl(rq['HTTP_REFERER']) - self.say(self.translate('action_done')) - self.goto(urlBack) + return field.onUiRequest(sourceObject, rq) def onCreate(self): '''This method is called when a user wants to create a root object in diff --git a/gen/tr/Appy.pot b/gen/tr/Appy.pot index 4e93e22..a995a9e 100644 --- a/gen/tr/Appy.pot +++ b/gen/tr/Appy.pot @@ -83,11 +83,11 @@ msgstr "" msgid "add_ref" msgstr "" -#. Default: "Selectable elements" +#. Default: "Available elements" msgid "selectable_objects" msgstr "" -#. Default: "Selected elements" +#. Default: "Inserted elements" msgid "selected_objects" msgstr "" @@ -191,7 +191,7 @@ msgstr "" msgid "object_delete" msgstr "" -#. Default: "Unlink" +#. Default: "Remove" msgid "object_unlink" msgstr "" @@ -199,6 +199,14 @@ msgstr "" msgid "object_link" msgstr "" +#. Default: "Insert selected elements" +msgid "object_link_many" +msgstr "" + +#. Default: "(Un)check everything" +msgid "check_uncheck" +msgstr "" + #. Default: "Unlock" msgid "page_unlock" msgstr "" diff --git a/gen/tr/ar.po b/gen/tr/ar.po index 59190b8..2311055 100644 --- a/gen/tr/ar.po +++ b/gen/tr/ar.po @@ -83,11 +83,11 @@ msgstr "" msgid "add_ref" msgstr "" -#. Default: "Selectable elements" +#. Default: "Available elements" msgid "selectable_objects" msgstr "" -#. Default: "Selected elements" +#. Default: "Inserted elements" msgid "selected_objects" msgstr "" @@ -191,7 +191,7 @@ msgstr "تعديل" msgid "object_delete" msgstr "" -#. Default: "Unlink" +#. Default: "Remove" msgid "object_unlink" msgstr "" @@ -199,6 +199,14 @@ msgstr "" msgid "object_link" msgstr "" +#. Default: "Insert selected elements" +msgid "object_link_many" +msgstr "" + +#. Default: "(Un)check everything" +msgid "check_uncheck" +msgstr "" + #. Default: "Unlock" msgid "page_unlock" msgstr "" diff --git a/gen/tr/de.po b/gen/tr/de.po index 677a7bd..9cb4317 100644 --- a/gen/tr/de.po +++ b/gen/tr/de.po @@ -83,11 +83,11 @@ msgstr "Kein Element" msgid "add_ref" msgstr "Hinzufügen" -#. Default: "Selectable elements" +#. Default: "Available elements" msgid "selectable_objects" msgstr "" -#. Default: "Selected elements" +#. Default: "Inserted elements" msgid "selected_objects" msgstr "" @@ -191,7 +191,7 @@ msgstr "Bearbeiten" msgid "object_delete" msgstr "Löschen" -#. Default: "Unlink" +#. Default: "Remove" msgid "object_unlink" msgstr "" @@ -199,6 +199,14 @@ msgstr "" msgid "object_link" msgstr "" +#. Default: "Insert selected elements" +msgid "object_link_many" +msgstr "" + +#. Default: "(Un)check everything" +msgid "check_uncheck" +msgstr "" + #. Default: "Unlock" msgid "page_unlock" msgstr "" diff --git a/gen/tr/en.po b/gen/tr/en.po index 38fdd1b..d5c6d78 100644 --- a/gen/tr/en.po +++ b/gen/tr/en.po @@ -84,13 +84,13 @@ msgstr "No object." msgid "add_ref" msgstr "Add a new one" -#. Default: "Selectable elements" +#. Default: "Available elements" msgid "selectable_objects" msgstr "Selectable elements" -#. Default: "Selected elements" +#. Default: "Inserted elements" msgid "selected_objects" -msgstr "Selected elements" +msgstr "Inserted elements" #. Default: "The action has been successfully executed." msgid "action_ok" @@ -192,7 +192,7 @@ msgstr "Edit" msgid "object_delete" msgstr "Delete" -#. Default: "Unlink" +#. Default: "Remove" msgid "object_unlink" msgstr "Unlink" @@ -200,6 +200,14 @@ msgstr "Unlink" msgid "object_link" msgstr "Insert" +#. Default: "Insert selected elements" +msgid "object_link_many" +msgstr "Insert selected elements" + +#. Default: "(Un)check everything" +msgid "check_uncheck" +msgstr "(Un)check everything" + #. Default: "Unlock" msgid "page_unlock" msgstr "Unlock" diff --git a/gen/tr/es.po b/gen/tr/es.po index 4438e1d..c4af84e 100644 --- a/gen/tr/es.po +++ b/gen/tr/es.po @@ -83,11 +83,11 @@ msgstr "Ningún elemento." msgid "add_ref" msgstr "Añadir" -#. Default: "Selectable elements" +#. Default: "Available elements" msgid "selectable_objects" msgstr "" -#. Default: "Selected elements" +#. Default: "Inserted elements" msgid "selected_objects" msgstr "" @@ -191,7 +191,7 @@ msgstr "Editar" msgid "object_delete" msgstr "Eliminar" -#. Default: "Unlink" +#. Default: "Remove" msgid "object_unlink" msgstr "" @@ -199,6 +199,14 @@ msgstr "" msgid "object_link" msgstr "" +#. Default: "Insert selected elements" +msgid "object_link_many" +msgstr "" + +#. Default: "(Un)check everything" +msgid "check_uncheck" +msgstr "" + #. Default: "Unlock" msgid "page_unlock" msgstr "" diff --git a/gen/tr/fr.po b/gen/tr/fr.po index bd2c78a..04a462b 100644 --- a/gen/tr/fr.po +++ b/gen/tr/fr.po @@ -84,13 +84,13 @@ msgstr "Aucun élément." msgid "add_ref" msgstr "Ajouter" -#. Default: "Selectable elements" +#. Default: "Available elements" msgid "selectable_objects" msgstr "Éléments sélectionnables" -#. Default: "Selected elements" +#. Default: "Inserted elements" msgid "selected_objects" -msgstr "Éléments sélectionnés" +msgstr "Éléments insérés" #. Default: "The action has been successfully executed." msgid "action_ok" @@ -192,14 +192,22 @@ msgstr "Modifier" msgid "object_delete" msgstr "Supprimer" -#. Default: "Unlink" +#. Default: "Remove" msgid "object_unlink" -msgstr "Dissocier" +msgstr "Retirer" #. Default: "Insert" msgid "object_link" msgstr "Insérer" +#. Default: "Insert selected elements" +msgid "object_link_many" +msgstr "Insérer la sélection" + +#. Default: "(Un)check everything" +msgid "check_uncheck" +msgstr "Tout (dé)sélectionner" + #. Default: "Unlock" msgid "page_unlock" msgstr "Déverrouiller" diff --git a/gen/tr/it.po b/gen/tr/it.po index 924bdfb..8602bba 100644 --- a/gen/tr/it.po +++ b/gen/tr/it.po @@ -83,11 +83,11 @@ msgstr "Nessun elemento" msgid "add_ref" msgstr "Aggiungi un nuovo" -#. Default: "Selectable elements" +#. Default: "Available elements" msgid "selectable_objects" msgstr "" -#. Default: "Selected elements" +#. Default: "Inserted elements" msgid "selected_objects" msgstr "" @@ -191,7 +191,7 @@ msgstr "Modifica" msgid "object_delete" msgstr "Elimina" -#. Default: "Unlink" +#. Default: "Remove" msgid "object_unlink" msgstr "" @@ -199,6 +199,14 @@ msgstr "" msgid "object_link" msgstr "" +#. Default: "Insert selected elements" +msgid "object_link_many" +msgstr "" + +#. Default: "(Un)check everything" +msgid "check_uncheck" +msgstr "" + #. Default: "Unlock" msgid "page_unlock" msgstr "" diff --git a/gen/tr/nl.po b/gen/tr/nl.po index 5b593a7..3f31f00 100644 --- a/gen/tr/nl.po +++ b/gen/tr/nl.po @@ -83,11 +83,11 @@ msgstr "Geen element." msgid "add_ref" msgstr "Toevoegen" -#. Default: "Selectable elements" +#. Default: "Available elements" msgid "selectable_objects" msgstr "" -#. Default: "Selected elements" +#. Default: "Inserted elements" msgid "selected_objects" msgstr "" @@ -191,7 +191,7 @@ msgstr "Bewerken" msgid "object_delete" msgstr "Verwijderen" -#. Default: "Unlink" +#. Default: "Remove" msgid "object_unlink" msgstr "" @@ -199,6 +199,14 @@ msgstr "" msgid "object_link" msgstr "" +#. Default: "Insert selected elements" +msgid "object_link_many" +msgstr "" + +#. Default: "(Un)check everything" +msgid "check_uncheck" +msgstr "" + #. Default: "Unlock" msgid "page_unlock" msgstr "" diff --git a/gen/ui/appy.css b/gen/ui/appy.css index b0f8997..5422d28 100644 --- a/gen/ui/appy.css +++ b/gen/ui/appy.css @@ -66,7 +66,7 @@ img { border: 0; vertical-align: middle } background-color: #dbdde1; font-weight: bold } .navigate td { padding: 4px 9px } .login { margin: 3px; color: black } -input.button { border-width: 0 !important; color: #666666; height: 23px; +input.button { border-width: 0 !important; color: #666666; height: 24px; width: 150px; cursor:pointer; font-size: 90%; padding: 1px 0 0 10px; background-color: transparent !important } .buttons { margin-left: 4px } @@ -157,3 +157,4 @@ td.search { padding-top: 8px } .error { margin: 5px } .podName { font-size: 90% } .podTable { margin-left: 15px } +.cbCell { width: 10px; text-align: center} diff --git a/gen/ui/appy.js b/gen/ui/appy.js index c179699..42f36d3 100644 --- a/gen/ui/appy.js +++ b/gen/ui/appy.js @@ -229,13 +229,16 @@ function askRefField(hookId, objectUrl, fieldName, innerRef, startNumber, action, actionParams){ // Sends an Ajax request for getting the content of a reference field. var startKey = hookId + '_startNumber'; - var params = {'innerRef': innerRef }; + var scope = hookId.split('_').pop(); + var params = {'innerRef': innerRef, 'scope': scope}; params[startKey] = startNumber; if (action) params['action'] = action; if (actionParams) { for (key in actionParams) { params[key] = actionParams[key]; }; } - askAjaxChunk(hookId, 'GET', objectUrl, fieldName+':pxView', params); + var px = (scope == 'objs')? ':pxView': ':pxViewPickList'; + askAjaxChunk(hookId, 'GET', objectUrl, fieldName + px, params, null, + evalInnerScripts); } function askField(hookId, objectUrl, layoutType, showChanges, masterValues, @@ -251,7 +254,7 @@ function askField(hookId, objectUrl, layoutType, showChanges, masterValues, askAjaxChunk(hookId, 'GET', objectUrl, px, params, null, evalInnerScripts); } -// Function used by checkbox widgets for having radio-button-like behaviour +// Used by checkbox widgets for having radio-button-like behaviour. function toggleCheckbox(visibleCheckbox, hiddenBoolean) { vis = document.getElementById(visibleCheckbox); hidden = document.getElementById(hiddenBoolean); @@ -259,6 +262,61 @@ function toggleCheckbox(visibleCheckbox, hiddenBoolean) { else hidden.value = 'False'; } +// (Un)checks a checkbox corresponding to a linked object. +function toggleRefCb(checkbox) { + var name = checkbox.getAttribute('name'); + var elems = name.split('_'); + // Get the DOM node corresponding to the Ref field. + var node = document.getElementById(elems[0] + '_' + elems[1]); + // Get the array that stores checkbox statuses. + var statuses = node['_appy_' + elems[2] + '_cbs']; + // Get the array semantics + var semantics = node['_appy_' + elems[2] + '_sem']; + var uid = checkbox.value; + if (semantics == 'unchecked') { + if (!checkbox.checked) statuses[uid] = null; + else {if (uid in statuses) delete statuses[uid]}; + } + else { // semantics is 'checked' + if (checkbox.checked) statuses[uid] = null; + else {if (uid in statuses) delete statuses[uid]}; + } +} + +// Initialise checkboxes of a Ref field. +function initRefCbs(id) { + var elems = id.split('_'); + // Get the DOM node corresponding to the Ref field. + var node = document.getElementById(elems[0] + '_' + elems[1]); + // Get the array that stores checkbox statuses. + var statuses = node['_appy_' + elems[2] + '_cbs']; + // Get the array semantics + var semantics = node['_appy_' + elems[2] + '_sem']; + var value = (semantics == 'unchecked')? false: true; + // Update visible checkboxes. + var checkboxes = getElementsHavingName('input', id); + for (var i=0; i < checkboxes.length; i++) { + if (checkboxes[i].value in statuses) checkboxes[i].checked = value; + else checkboxes[i].checked = !value; + } +} + +// Toggle all checkboxes of a Ref field. +function toggleAllRefCbs(id) { + var elems = id.split('_'); + // Get the DOM node corresponding to the Ref field. + var node = document.getElementById(elems[0] + '_' + elems[1]); + // Empty the array that stores checkbox statuses. + var statuses = node['_appy_' + elems[2] + '_cbs']; + for (var key in statuses) delete statuses[key]; + // Switch the array semantics. + var semAttr = '_appy_' + elems[2] + '_sem'; + if (node[semAttr] == 'unchecked') node[semAttr] = 'checked'; + else node[semAttr] = 'unchecked'; + // Update the visible checkboxes + initRefCbs(id); +} + // Shows/hides a dropdown menu function toggleDropdown(dropdownId, forcedValue){ var dropdown = document.getElementById(dropdownId); @@ -456,22 +514,35 @@ function onDeleteEvent(objectUid, eventTime) { askConfirm('form', 'deleteEventForm', action_confirm); } -function onUnlinkObject(sourceUid, fieldName, targetUid) { - f = document.getElementById('unlinkForm'); - f.sourceUid.value = sourceUid; - f.fieldName.value = fieldName; - f.targetUid.value = targetUid; - askConfirm('form', 'unlinkForm', action_confirm); -} - -function onLinkObject(sourceUid, fieldName, targetUid) { +function onLink(action, sourceUid, fieldName, targetUid) { f = document.getElementById('linkForm'); + f.linkAction.value = action; f.sourceUid.value = sourceUid; f.fieldName.value = fieldName; f.targetUid.value = targetUid; f.submit(); } +function onLinkMany(id) { + var elems = id.split('_'); + // Get the DOM node corresponding to the Ref field. + var node = document.getElementById(elems[0] + '_' + elems[1]); + // Get the uids of (un-)checked objects. + var statuses = node['_appy_' + elems[2] + '_cbs']; + var uids = ''; + for (var uid in statuses) uids += uid + ','; + // Get the array semantics + var semantics = node['_appy_' + elems[2] + '_sem']; + // Fill the form and ask for a confirmation + f = document.getElementById('linkForm'); + f.linkAction.value = 'link_many'; + f.sourceUid.value = elems[0]; + f.fieldName.value = elems[1]; + f.targetUid.value = uids; + f.semantics.value = semantics; + askConfirm('form', 'linkForm', action_confirm); +} + function onUnlockPage(objectUid, pageName) { f = document.getElementById('unlockForm'); f.objectUid.value = objectUid; diff --git a/gen/ui/checkall.png b/gen/ui/checkall.png new file mode 100644 index 0000000..e0e3c64 Binary files /dev/null and b/gen/ui/checkall.png differ diff --git a/gen/ui/linkMany.png b/gen/ui/linkMany.png new file mode 100644 index 0000000..e27d136 Binary files /dev/null and b/gen/ui/linkMany.png differ diff --git a/gen/ui/unlinkUp.png b/gen/ui/unlinkUp.png new file mode 100644 index 0000000..32fb14b Binary files /dev/null and b/gen/ui/unlinkUp.png differ diff --git a/gen/wrappers/ToolWrapper.py b/gen/wrappers/ToolWrapper.py index 5a40e6d..c209dee 100644 --- a/gen/wrappers/ToolWrapper.py +++ b/gen/wrappers/ToolWrapper.py @@ -115,19 +115,14 @@ class ToolWrapper(AbstractWrapper): - -
- - - - -
- +
+ +