Initial import from Docker volume
5
ir/ui/__init__.py
Executable file
@@ -0,0 +1,5 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
from . import icon, menu, view
|
||||
|
||||
__all__ = ['menu', 'view', 'icon']
|
||||
BIN
ir/ui/__pycache__/__init__.cpython-311.opt-1.pyc
Executable file
BIN
ir/ui/__pycache__/__init__.cpython-311.pyc
Executable file
BIN
ir/ui/__pycache__/icon.cpython-311.opt-1.pyc
Executable file
BIN
ir/ui/__pycache__/icon.cpython-311.pyc
Executable file
BIN
ir/ui/__pycache__/menu.cpython-311.opt-1.pyc
Executable file
BIN
ir/ui/__pycache__/menu.cpython-311.pyc
Executable file
BIN
ir/ui/__pycache__/view.cpython-311.opt-1.pyc
Executable file
BIN
ir/ui/__pycache__/view.cpython-311.pyc
Executable file
170
ir/ui/board.rnc
Executable file
@@ -0,0 +1,170 @@
|
||||
namespace a = "http://relaxng.org/ns/compatibility/annotations/1.0"
|
||||
|
||||
board =
|
||||
element board {
|
||||
attlist.board,
|
||||
(image
|
||||
| separator
|
||||
| label
|
||||
| newline
|
||||
| link
|
||||
| notebook
|
||||
| group
|
||||
| hpaned
|
||||
| vpaned
|
||||
| action)*
|
||||
}
|
||||
attlist.board &= [ a:defaultValue = "4" ] attribute col { text }?
|
||||
image = element image { attlist.image, empty }
|
||||
attlist.image &= attribute name { text }
|
||||
attlist.image &= [ a:defaultValue = "1" ] attribute colspan { text }?
|
||||
attlist.image &=
|
||||
[ a:defaultValue = "0" ] attribute yexpand { "0" | "1" }?
|
||||
attlist.image &= [ a:defaultValue = "0" ] attribute yfill { "0" | "1" }?
|
||||
attlist.image &=
|
||||
[ a:defaultValue = "0" ] attribute xexpand { "0" | "1" }?
|
||||
attlist.image &= [ a:defaultValue = "0" ] attribute xfill { "0" | "1" }?
|
||||
attlist.image &= attribute help { text }?
|
||||
attlist.image &= attribute states { text }?
|
||||
separator = element separator { attlist.separator, empty }
|
||||
attlist.separator &= [ a:defaultValue = "" ] attribute string { text }?
|
||||
attlist.separator &= ( attribute name { text } | attribute name { text } )
|
||||
attlist.separator &= attribute states { text }?
|
||||
attlist.separator &=
|
||||
[ a:defaultValue = "0.0" ] attribute xalign { text }?
|
||||
attlist.separator &=
|
||||
[ a:defaultValue = "1" ] attribute colspan { text }?
|
||||
attlist.separator &=
|
||||
[ a:defaultValue = "0" ] attribute yexpand { "0" | "1" }?
|
||||
attlist.separator &=
|
||||
[ a:defaultValue = "0" ] attribute yfill { "0" | "1" }?
|
||||
attlist.separator &=
|
||||
[ a:defaultValue = "0" ] attribute xexpand { "0" | "1" }?
|
||||
attlist.separator &=
|
||||
[ a:defaultValue = "0" ] attribute xfill { "0" | "1" }?
|
||||
attlist.separator &= attribute help { text }?
|
||||
label = element label { attlist.label, empty }
|
||||
attlist.label &= [ a:defaultValue = "" ] attribute string { text }?
|
||||
attlist.label &= ( attribute name { text } | attribute name { text } )
|
||||
attlist.label &= attribute states { text }?
|
||||
attlist.label &= [ a:defaultValue = "0.0" ] attribute xalign { text }?
|
||||
attlist.label &= [ a:defaultValue = "0.5" ] attribute yalign { text }?
|
||||
attlist.label &=
|
||||
[ a:defaultValue = "0" ] attribute yexpand { "0" | "1" }?
|
||||
attlist.label &= [ a:defaultValue = "0" ] attribute yfill { "0" | "1" }?
|
||||
attlist.label &=
|
||||
[ a:defaultValue = "0" ] attribute xexpand { "0" | "1" }?
|
||||
attlist.label &= [ a:defaultValue = "1" ] attribute xfill { "0" | "1" }?
|
||||
attlist.label &= [ a:defaultValue = "1" ] attribute colspan { text }?
|
||||
attlist.label &= attribute help { text }?
|
||||
newline = element newline { attlist.newline, empty }
|
||||
attlist.newline &= attribute id { text }
|
||||
link = element link { attlist.link, empty }
|
||||
attlist.link &= attribute name { text }
|
||||
attlist.link &= attribute id { text }?
|
||||
attlist.link &= [ a:defaultValue = "1" ] attribute colspan { text }?
|
||||
attlist.link &= attribute states { text }?
|
||||
attlist.link &= attribute icon { text }?
|
||||
attlist.link &= [ a:defaultValue = "show" ] attribute empty { "show" | "hide" }?
|
||||
notebook = element notebook { attlist.notebook, page* }
|
||||
attlist.notebook &= [ a:defaultValue = "4" ] attribute colspan { text }?
|
||||
page =
|
||||
element page {
|
||||
attlist.page,
|
||||
(image
|
||||
| separator
|
||||
| label
|
||||
| newline
|
||||
| link
|
||||
| notebook
|
||||
| group
|
||||
| hpaned
|
||||
| vpaned
|
||||
| action)*
|
||||
}
|
||||
attlist.page &= attribute angle { text }?
|
||||
attlist.page &=
|
||||
[ a:defaultValue = "Unknown" ] attribute string { text }?
|
||||
attlist.page &= [ a:defaultValue = "4" ] attribute col { text }?
|
||||
attlist.page &= ( attribute name { text } | attribute id { text } )
|
||||
group =
|
||||
element group {
|
||||
attlist.group,
|
||||
(image
|
||||
| separator
|
||||
| label
|
||||
| newline
|
||||
| link
|
||||
| notebook
|
||||
| group
|
||||
| hpaned
|
||||
| vpaned
|
||||
| action)*
|
||||
}
|
||||
attlist.group &= attribute string { text }?
|
||||
attlist.group &= [ a:defaultValue = "1" ] attribute colspan { text }?
|
||||
attlist.group &=
|
||||
[ a:defaultValue = "0" ] attribute yexpand { "0" | "1" }?
|
||||
attlist.group &= [ a:defaultValue = "1" ] attribute yfill { "0" | "1" }?
|
||||
attlist.group &= [ a:defaultValue = "0.5" ] attribute yalign { text }?
|
||||
attlist.group &=
|
||||
[ a:defaultValue = "0" ] attribute xexpand { "0" | "1" }?
|
||||
attlist.group &= [ a:defaultValue = "1" ] attribute xfill { "0" | "1" }?
|
||||
attlist.group &= [ a:defaultValue = "0.5" ] attribute xalign { text }?
|
||||
attlist.group &= [ a:defaultValue = "1" ] attribute rowspan { text }?
|
||||
attlist.group &= [ a:defaultValue = "4" ] attribute col { text }?
|
||||
attlist.group &= attribute id { text }
|
||||
|
||||
hpaned = element hpaned { attlist.paned, child* }
|
||||
|
||||
vpaned = element vpaned { attlist.paned, child* }
|
||||
|
||||
attlist.paned &= [ a:defaultValue = "4" ] attribute colspan { text }?
|
||||
attlist.paned &= attribute position { text }?
|
||||
attlist.paned &= attribute id { text }
|
||||
|
||||
child =
|
||||
element child {
|
||||
attlist.child,
|
||||
(image
|
||||
| separator
|
||||
| label
|
||||
| newline
|
||||
| link
|
||||
| notebook
|
||||
| group
|
||||
| hpaned
|
||||
| vpaned
|
||||
| action)*
|
||||
}
|
||||
|
||||
attlist.child &= attribute id { text }
|
||||
|
||||
data = element data { attlist.data, xpath+ }
|
||||
attlist.data &= empty
|
||||
|
||||
xpath = element xpath { attlist.xpath,
|
||||
(image
|
||||
| separator
|
||||
| label
|
||||
| newline
|
||||
| link
|
||||
| notebook
|
||||
| group
|
||||
| hpaned
|
||||
| vpaned
|
||||
| action
|
||||
| page
|
||||
| child
|
||||
| board
|
||||
)*
|
||||
}
|
||||
attlist.xpath &= attribute expr { text }
|
||||
attlist.xpath &=
|
||||
[ a:defaultValue = "inside" ]
|
||||
attribute position { "inside" | "replace" | "replace_attributes" | "after" | "before" }?
|
||||
action = element action { attlist.action, empty }
|
||||
attlist.action &= attribute name { text }
|
||||
attlist.action &= [ a:defaultValue = "1" ] attribute colspan { text }?
|
||||
label |= notAllowed
|
||||
start = data | board | label
|
||||
739
ir/ui/board.rng
Executable file
@@ -0,0 +1,739 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<grammar xmlns="http://relaxng.org/ns/structure/1.0"
|
||||
xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0">
|
||||
<define name="board">
|
||||
<element>
|
||||
<name ns="">board</name>
|
||||
<ref name="attlist.board"/>
|
||||
<zeroOrMore>
|
||||
<choice>
|
||||
<ref name="image"/>
|
||||
<ref name="separator"/>
|
||||
<ref name="label"/>
|
||||
<ref name="newline"/>
|
||||
<ref name="link"/>
|
||||
<ref name="notebook"/>
|
||||
<ref name="group"/>
|
||||
<ref name="hpaned"/>
|
||||
<ref name="vpaned"/>
|
||||
<ref name="action"/>
|
||||
</choice>
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
</define>
|
||||
<define name="attlist.board" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="4">
|
||||
<name ns="">col</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="image">
|
||||
<element>
|
||||
<name ns="">image</name>
|
||||
<ref name="attlist.image"/>
|
||||
<empty/>
|
||||
</element>
|
||||
</define>
|
||||
<define name="attlist.image" combine="interleave">
|
||||
<attribute>
|
||||
<name ns="">name</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</define>
|
||||
<define name="attlist.image" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="1">
|
||||
<name ns="">colspan</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.image" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="0">
|
||||
<name ns="">yexpand</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.image" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="0">
|
||||
<name ns="">yfill</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.image" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="0">
|
||||
<name ns="">xexpand</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.image" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="0">
|
||||
<name ns="">xfill</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.image" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">help</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.image" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">states</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="separator">
|
||||
<element>
|
||||
<name ns="">separator</name>
|
||||
<ref name="attlist.separator"/>
|
||||
<empty/>
|
||||
</element>
|
||||
</define>
|
||||
<define name="attlist.separator" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="">
|
||||
<name ns="">string</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.separator" combine="interleave">
|
||||
<choice>
|
||||
<attribute>
|
||||
<name ns="">name</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name ns="">name</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</choice>
|
||||
</define>
|
||||
<define name="attlist.separator" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">states</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.separator" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="0.0">
|
||||
<name ns="">xalign</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.separator" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="1">
|
||||
<name ns="">colspan</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.separator" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="0">
|
||||
<name ns="">yexpand</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.separator" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="0">
|
||||
<name ns="">yfill</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.separator" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="0">
|
||||
<name ns="">xexpand</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.separator" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="0">
|
||||
<name ns="">xfill</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.separator" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">help</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="label">
|
||||
<element>
|
||||
<name ns="">label</name>
|
||||
<ref name="attlist.label"/>
|
||||
<empty/>
|
||||
</element>
|
||||
</define>
|
||||
<define name="attlist.label" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="">
|
||||
<name ns="">string</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.label" combine="interleave">
|
||||
<choice>
|
||||
<attribute>
|
||||
<name ns="">name</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name ns="">name</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</choice>
|
||||
</define>
|
||||
<define name="attlist.label" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">states</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.label" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="0.0">
|
||||
<name ns="">xalign</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.label" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="0.5">
|
||||
<name ns="">yalign</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.label" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="0">
|
||||
<name ns="">yexpand</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.label" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="0">
|
||||
<name ns="">yfill</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.label" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="0">
|
||||
<name ns="">xexpand</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.label" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="1">
|
||||
<name ns="">xfill</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.label" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="1">
|
||||
<name ns="">colspan</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.label" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">help</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="newline">
|
||||
<element>
|
||||
<name ns="">newline</name>
|
||||
<ref name="attlist.newline"/>
|
||||
<empty/>
|
||||
</element>
|
||||
</define>
|
||||
<define name="attlist.newline" combine="interleave">
|
||||
<attribute>
|
||||
<name ns="">id</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</define>
|
||||
<define name="link">
|
||||
<element>
|
||||
<name ns="">link</name>
|
||||
<ref name="attlist.link"/>
|
||||
<empty/>
|
||||
</element>
|
||||
</define>
|
||||
<define name="attlist.link" combine="interleave">
|
||||
<attribute>
|
||||
<name ns="">name</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</define>
|
||||
<define name="attlist.link" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">id</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.link" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="1">
|
||||
<name ns="">colspan</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.link" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">states</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.link" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">icon</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.link" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="show">
|
||||
<name ns="">empty</name>
|
||||
<choice>
|
||||
<value>show</value>
|
||||
<value>hide</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="notebook">
|
||||
<element>
|
||||
<name ns="">notebook</name>
|
||||
<ref name="attlist.notebook"/>
|
||||
<zeroOrMore>
|
||||
<ref name="page"/>
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
</define>
|
||||
<define name="attlist.notebook" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="4">
|
||||
<name ns="">colspan</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="page">
|
||||
<element>
|
||||
<name ns="">page</name>
|
||||
<ref name="attlist.page"/>
|
||||
<zeroOrMore>
|
||||
<choice>
|
||||
<ref name="image"/>
|
||||
<ref name="separator"/>
|
||||
<ref name="label"/>
|
||||
<ref name="newline"/>
|
||||
<ref name="link"/>
|
||||
<ref name="notebook"/>
|
||||
<ref name="group"/>
|
||||
<ref name="hpaned"/>
|
||||
<ref name="vpaned"/>
|
||||
<ref name="action"/>
|
||||
</choice>
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
</define>
|
||||
<define name="attlist.page" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">angle</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.page" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="Unknown">
|
||||
<name ns="">string</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.page" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="4">
|
||||
<name ns="">col</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.page" combine="interleave">
|
||||
<choice>
|
||||
<attribute>
|
||||
<name ns="">name</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name ns="">id</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</choice>
|
||||
</define>
|
||||
<define name="group">
|
||||
<element>
|
||||
<name ns="">group</name>
|
||||
<ref name="attlist.group"/>
|
||||
<zeroOrMore>
|
||||
<choice>
|
||||
<ref name="image"/>
|
||||
<ref name="separator"/>
|
||||
<ref name="label"/>
|
||||
<ref name="newline"/>
|
||||
<ref name="link"/>
|
||||
<ref name="notebook"/>
|
||||
<ref name="group"/>
|
||||
<ref name="hpaned"/>
|
||||
<ref name="vpaned"/>
|
||||
<ref name="action"/>
|
||||
</choice>
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
</define>
|
||||
<define name="attlist.group" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">string</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.group" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="1">
|
||||
<name ns="">colspan</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.group" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="0">
|
||||
<name ns="">yexpand</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.group" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="1">
|
||||
<name ns="">yfill</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.group" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="0.5">
|
||||
<name ns="">yalign</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.group" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="0">
|
||||
<name ns="">xexpand</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.group" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="1">
|
||||
<name ns="">xfill</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.group" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="0.5">
|
||||
<name ns="">xalign</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.group" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="1">
|
||||
<name ns="">rowspan</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.group" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="4">
|
||||
<name ns="">col</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.group" combine="interleave">
|
||||
<attribute>
|
||||
<name ns="">id</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</define>
|
||||
<define name="hpaned">
|
||||
<element>
|
||||
<name ns="">hpaned</name>
|
||||
<ref name="attlist.paned"/>
|
||||
<zeroOrMore>
|
||||
<ref name="child"/>
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
</define>
|
||||
<define name="vpaned">
|
||||
<element>
|
||||
<name ns="">vpaned</name>
|
||||
<ref name="attlist.paned"/>
|
||||
<zeroOrMore>
|
||||
<ref name="child"/>
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
</define>
|
||||
<define name="attlist.paned" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="4">
|
||||
<name ns="">colspan</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.paned" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">position</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.paned" combine="interleave">
|
||||
<attribute>
|
||||
<name ns="">id</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</define>
|
||||
<define name="child">
|
||||
<element>
|
||||
<name ns="">child</name>
|
||||
<ref name="attlist.child"/>
|
||||
<zeroOrMore>
|
||||
<choice>
|
||||
<ref name="image"/>
|
||||
<ref name="separator"/>
|
||||
<ref name="label"/>
|
||||
<ref name="newline"/>
|
||||
<ref name="link"/>
|
||||
<ref name="notebook"/>
|
||||
<ref name="group"/>
|
||||
<ref name="hpaned"/>
|
||||
<ref name="vpaned"/>
|
||||
<ref name="action"/>
|
||||
</choice>
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
</define>
|
||||
<define name="attlist.child" combine="interleave">
|
||||
<attribute>
|
||||
<name ns="">id</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</define>
|
||||
<define name="data">
|
||||
<element>
|
||||
<name ns="">data</name>
|
||||
<ref name="attlist.data"/>
|
||||
<oneOrMore>
|
||||
<ref name="xpath"/>
|
||||
</oneOrMore>
|
||||
</element>
|
||||
</define>
|
||||
<define name="attlist.data" combine="interleave">
|
||||
<empty/>
|
||||
</define>
|
||||
<define name="xpath">
|
||||
<element>
|
||||
<name ns="">xpath</name>
|
||||
<ref name="attlist.xpath"/>
|
||||
<zeroOrMore>
|
||||
<choice>
|
||||
<ref name="image"/>
|
||||
<ref name="separator"/>
|
||||
<ref name="label"/>
|
||||
<ref name="newline"/>
|
||||
<ref name="link"/>
|
||||
<ref name="notebook"/>
|
||||
<ref name="group"/>
|
||||
<ref name="hpaned"/>
|
||||
<ref name="vpaned"/>
|
||||
<ref name="action"/>
|
||||
<ref name="page"/>
|
||||
<ref name="child"/>
|
||||
<ref name="board"/>
|
||||
</choice>
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
</define>
|
||||
<define name="attlist.xpath" combine="interleave">
|
||||
<attribute>
|
||||
<name ns="">expr</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</define>
|
||||
<define name="attlist.xpath" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="inside">
|
||||
<name ns="">position</name>
|
||||
<choice>
|
||||
<value>inside</value>
|
||||
<value>replace</value>
|
||||
<value>replace_attributes</value>
|
||||
<value>after</value>
|
||||
<value>before</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="action">
|
||||
<element>
|
||||
<name ns="">action</name>
|
||||
<ref name="attlist.action"/>
|
||||
<empty/>
|
||||
</element>
|
||||
</define>
|
||||
<define name="attlist.action" combine="interleave">
|
||||
<attribute>
|
||||
<name ns="">name</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</define>
|
||||
<define name="attlist.action" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="1">
|
||||
<name ns="">colspan</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="label" combine="choice">
|
||||
<notAllowed/>
|
||||
</define>
|
||||
<start>
|
||||
<choice>
|
||||
<ref name="data"/>
|
||||
<ref name="board"/>
|
||||
<ref name="label"/>
|
||||
</choice>
|
||||
</start>
|
||||
</grammar>
|
||||
36
ir/ui/calendar.rnc
Executable file
@@ -0,0 +1,36 @@
|
||||
namespace a = "http://relaxng.org/ns/compatibility/annotations/1.0"
|
||||
|
||||
calendar = element calendar { attlist.calendar, field* }
|
||||
attlist.calendar &=
|
||||
attribute dtstart { text }
|
||||
attlist.calendar &=
|
||||
attribute dtend { text }?
|
||||
attlist.calendar &=
|
||||
attribute mode { "day"
|
||||
| "week"
|
||||
| "month" }?
|
||||
attlist.calendar &= [a:defaultValue = "1" ] attribute editable { "0" | "1" }?
|
||||
attlist.calendar &= attribute color { text }?
|
||||
attlist.calendar &= attribute background_color { text }?
|
||||
attlist.calendar &=
|
||||
attribute width { text }?
|
||||
attlist.calendar &=
|
||||
attribute height { text }?
|
||||
field = element field { attlist.field, empty }
|
||||
attlist.field &= attribute name { text }
|
||||
data = element data { attlist.data, xpath* }
|
||||
attlist.data &= empty
|
||||
|
||||
xpath = element xpath {
|
||||
attlist.xpath, (field | calendar)*
|
||||
}
|
||||
attlist.xpath &= attribute expr { text }
|
||||
attlist.xpath &=
|
||||
[ a:defaultValue = "inside" ]
|
||||
attribute position { "inside"
|
||||
| "replace"
|
||||
| "replace_attributes"
|
||||
| "after"
|
||||
| "before" }?
|
||||
|
||||
start = data | calendar
|
||||
145
ir/ui/calendar.rng
Executable file
@@ -0,0 +1,145 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<grammar xmlns="http://relaxng.org/ns/structure/1.0"
|
||||
xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0">
|
||||
<define name="calendar">
|
||||
<element>
|
||||
<name ns="">calendar</name>
|
||||
<ref name="attlist.calendar"/>
|
||||
<zeroOrMore>
|
||||
<ref name="field"/>
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
</define>
|
||||
<define name="attlist.calendar" combine="interleave">
|
||||
<attribute>
|
||||
<name ns="">dtstart</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</define>
|
||||
<define name="attlist.calendar" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">dtend</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.calendar" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">mode</name>
|
||||
<choice>
|
||||
<value>day</value>
|
||||
<value>week</value>
|
||||
<value>month</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.calendar" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="1">
|
||||
<name ns="">editable</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.calendar" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">color</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.calendar" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">background_color</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.calendar" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">width</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.calendar" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">height</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="field">
|
||||
<element>
|
||||
<name ns="">field</name>
|
||||
<ref name="attlist.field"/>
|
||||
<empty/>
|
||||
</element>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<attribute>
|
||||
<name ns="">name</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</define>
|
||||
<define name="data">
|
||||
<element>
|
||||
<name ns="">data</name>
|
||||
<ref name="attlist.data"/>
|
||||
<zeroOrMore>
|
||||
<ref name="xpath"/>
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
</define>
|
||||
<define name="attlist.data" combine="interleave">
|
||||
<empty/>
|
||||
</define>
|
||||
<define name="xpath">
|
||||
<element>
|
||||
<name ns="">xpath</name>
|
||||
<ref name="attlist.xpath"/>
|
||||
<zeroOrMore>
|
||||
<choice>
|
||||
<ref name="field"/>
|
||||
<ref name="calendar"/>
|
||||
</choice>
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
</define>
|
||||
<define name="attlist.xpath" combine="interleave">
|
||||
<attribute>
|
||||
<name ns="">expr</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</define>
|
||||
<define name="attlist.xpath" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="inside">
|
||||
<name ns="">position</name>
|
||||
<choice>
|
||||
<value>inside</value>
|
||||
<value>replace</value>
|
||||
<value>replace_attributes</value>
|
||||
<value>after</value>
|
||||
<value>before</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<start>
|
||||
<choice>
|
||||
<ref name="data"/>
|
||||
<ref name="calendar"/>
|
||||
</choice>
|
||||
</start>
|
||||
</grammar>
|
||||
300
ir/ui/form.rnc
Executable file
@@ -0,0 +1,300 @@
|
||||
namespace a = "http://relaxng.org/ns/compatibility/annotations/1.0"
|
||||
|
||||
form =
|
||||
element form {
|
||||
attlist.form,
|
||||
(label
|
||||
| field
|
||||
| image
|
||||
| separator
|
||||
| newline
|
||||
| button
|
||||
| link
|
||||
| notebook
|
||||
| group
|
||||
| hpaned
|
||||
| vpaned)*
|
||||
}
|
||||
attlist.form &= attribute on_write { text }?
|
||||
attlist.form &=
|
||||
[ a:defaultValue = "1" ] attribute creatable { "0" | "1" }?
|
||||
attlist.form &= [ a:defaultValue = "4" ] attribute col { text }?
|
||||
attlist.form &= attribute cursor { text }?
|
||||
attlist.form &= attribute scan_code { "one" | "submit" | "loop" }?
|
||||
attlist.form &= attribute scan_code_depends { text }?
|
||||
attlist.form &= attribute scan_code_states { text }?
|
||||
|
||||
label = element label { attlist.label, empty }
|
||||
attlist.label &= [ a:defaultValue = "" ] attribute string { text }?
|
||||
attlist.label &= ( attribute name { text } | attribute id { text } )
|
||||
attlist.label &= attribute states { text }?
|
||||
attlist.label &= [ a:defaultValue = "0.0" ] attribute xalign { text }?
|
||||
attlist.label &= [ a:defaultValue = "0.5" ] attribute yalign { text }?
|
||||
attlist.label &=
|
||||
[ a:defaultValue = "0" ] attribute yexpand { "0" | "1" }?
|
||||
attlist.label &= [ a:defaultValue = "0" ] attribute yfill { "0" | "1" }?
|
||||
attlist.label &=
|
||||
[ a:defaultValue = "0" ] attribute xexpand { "0" | "1" }?
|
||||
attlist.label &= [ a:defaultValue = "1" ] attribute xfill { "0" | "1" }?
|
||||
attlist.label &= [ a:defaultValue = "1" ] attribute colspan { text }?
|
||||
attlist.label &= attribute help { text }?
|
||||
|
||||
field = element field { attlist.field, empty }
|
||||
attlist.field &= attribute name { text }
|
||||
attlist.field &= [ a:defaultValue = "1" ] attribute colspan { text }?
|
||||
attlist.field &=
|
||||
attribute widget {
|
||||
"binary"
|
||||
| "boolean"
|
||||
| "callto"
|
||||
| "char"
|
||||
| "date"
|
||||
| "datetime"
|
||||
| "dict"
|
||||
| "document"
|
||||
| "email"
|
||||
| "float"
|
||||
| "html"
|
||||
| "image"
|
||||
| "integer"
|
||||
| "many2many"
|
||||
| "many2one"
|
||||
| "multiselection"
|
||||
| "numeric"
|
||||
| "one2many"
|
||||
| "one2one"
|
||||
| "password"
|
||||
| "progressbar"
|
||||
| "pyson"
|
||||
| "reference"
|
||||
| "richtext"
|
||||
| "selection"
|
||||
| "sip"
|
||||
| "text"
|
||||
| "time"
|
||||
| "timedelta"
|
||||
| "url"
|
||||
}?
|
||||
attlist.field &= attribute fill { "0" | "1" }?
|
||||
attlist.field &= attribute yexpand { "0" | "1" }?
|
||||
attlist.field &= attribute yfill { "0" | "1" }?
|
||||
attlist.field &= attribute empty { "0" | "1" }?
|
||||
attlist.field &=
|
||||
[ a:defaultValue = "1" ] attribute xexpand { "0" | "1" }?
|
||||
attlist.field &= [ a:defaultValue = "1" ] attribute xfill { "0" | "1" }?
|
||||
attlist.field &= [ a:defaultValue = "0.0" ] attribute xalign { text }?
|
||||
attlist.field &= [ a:defaultValue = "0.5" ] attribute yalign { text }?
|
||||
attlist.field &= attribute help { text }?
|
||||
attlist.field &= attribute width { text }?
|
||||
attlist.field &= attribute height { text }?
|
||||
attlist.field &= attribute readonly { "0" | "1" }?
|
||||
attlist.field &=
|
||||
[ a:defaultValue = "0" ] attribute tree_invisible { "0" | "1" }?
|
||||
attlist.field &= attribute mode { text }?
|
||||
attlist.field &= attribute view_ids { text }?
|
||||
attlist.field &= attribute product { text }?
|
||||
attlist.field &=
|
||||
[ a:defaultValue = "0" ] attribute invisible { "0" | "1" }?
|
||||
attlist.field &=
|
||||
[ a:defaultValue = "1" ] attribute create { "0" | "1" }?
|
||||
attlist.field &=
|
||||
[ a:defaultValue = "1" ] attribute delete { "0" | "1" }?
|
||||
attlist.field &=
|
||||
[ a:defaultValue = "left_to_right" ] attribute orientation {
|
||||
"left_to_right"
|
||||
| "right_to_left"
|
||||
| "bottom_to_top"
|
||||
| "top_to_bottom"
|
||||
}?
|
||||
attlist.field &= attribute spell { text }?
|
||||
attlist.field &=
|
||||
[a:defaultValue = "0"] attribute filename_visible { "0" | "1" }?
|
||||
attlist.field &= [a:defaultValue = "0"] attribute pre_validate { "0" | "1" }?
|
||||
attlist.field &= attribute icon { text }?
|
||||
attlist.field &= [a:defaultValue = "1"] attribute completion { "0" | "1" }?
|
||||
attlist.field &= attribute string { text }?
|
||||
attlist.field &= [a:defaultValue = "1"] attribute factor { text }?
|
||||
attlist.field &= attribute filename { text }?
|
||||
attlist.field &= attribute help_field { text }?
|
||||
attlist.field &=
|
||||
[a:defaultValue = "0"] attribute toolbar { "0" | "1" }?
|
||||
attlist.field &= attribute symbol { text }?
|
||||
attlist.field &= [a:defaultValue = "1"] attribute grouping { "0" | "1" }?
|
||||
attlist.field &= [a:defaultValue = "square"] attribute border { "square" | "circle" | "rounded" }?
|
||||
attlist.field &= attribute loading { "lazy" | "eager" }?
|
||||
image = element image { attlist.image, empty }
|
||||
attlist.image &= attribute name { text }
|
||||
attlist.image &= [a:defaultValue = "icon"] attribute type { "icon" | "url" }?
|
||||
attlist.image &= attribute url_size { text }?
|
||||
attlist.image &= [a:defaultValue = "square"] attribute border { "square" | "circle" | "rounded" }?
|
||||
attlist.image &= [ a:defaultValue = "1" ] attribute colspan { text }?
|
||||
attlist.image &=
|
||||
[ a:defaultValue = "0" ] attribute yexpand { "0" | "1" }?
|
||||
attlist.image &= [ a:defaultValue = "0" ] attribute yfill { "0" | "1" }?
|
||||
attlist.image &=
|
||||
[ a:defaultValue = "1" ] attribute xexpand { "0" | "1" }?
|
||||
attlist.image &=
|
||||
[ a:defaultValue = "48" ] attribute size {text }?
|
||||
attlist.image &= [ a:defaultValue = "0" ] attribute xfill { "0" | "1" }?
|
||||
attlist.image &= attribute help { text }?
|
||||
attlist.image &= attribute states { text }?
|
||||
separator = element separator { attlist.separator, empty }
|
||||
attlist.separator &= [ a:defaultValue = "" ] attribute string { text }?
|
||||
attlist.separator &= ( attribute name { text } | attribute id { text} )
|
||||
attlist.separator &= attribute states { text }?
|
||||
attlist.separator &=
|
||||
[ a:defaultValue = "0.0" ] attribute xalign { text }?
|
||||
attlist.separator &=
|
||||
[ a:defaultValue = "1" ] attribute colspan { text }?
|
||||
attlist.separator &=
|
||||
[ a:defaultValue = "0" ] attribute yexpand { "0" | "1" }?
|
||||
attlist.separator &=
|
||||
[ a:defaultValue = "0" ] attribute yfill { "0" | "1" }?
|
||||
attlist.separator &=
|
||||
[ a:defaultValue = "1" ] attribute xexpand { "0" | "1" }?
|
||||
attlist.separator &=
|
||||
[ a:defaultValue = "0" ] attribute xfill { "0" | "1" }?
|
||||
attlist.separator &= attribute help { text }?
|
||||
newline = element newline { attlist.newline, empty }
|
||||
attlist.newline &= empty
|
||||
button = element button { attlist.button, empty }
|
||||
attlist.button &= [ a:defaultValue = "1" ] attribute colspan { text }?
|
||||
attlist.button &= attribute help { text }?
|
||||
attlist.button &= attribute string { text }?
|
||||
attlist.button &= attribute icon { text }?
|
||||
attlist.button &= attribute confirm { text }?
|
||||
attlist.button &= attribute name { text }
|
||||
attlist.button &= attribute states { text }?
|
||||
attlist.button &=
|
||||
[ a:defaultValue = "0" ] attribute yexpand { "0" | "1" }?
|
||||
attlist.button &=
|
||||
[ a:defaultValue = "0" ] attribute yfill { "0" | "1" }?
|
||||
attlist.button &=
|
||||
[ a:defaultValue = "1" ] attribute xexpand { "0" | "1" }?
|
||||
attlist.button &=
|
||||
[ a:defaultValue = "0" ] attribute xfill { "0" | "1" }?
|
||||
attlist.button &=
|
||||
[ a:defaultValue="action" ]
|
||||
attribute keyword { "relate" | "print" | "action" }?
|
||||
attlist.button &= [ a:defaultValue = "0" ] attribute rule { "0" | "1" }?
|
||||
attlist.button &= attribute change { text }?
|
||||
attlist.button &= attribute type { "class" | "instance" }?
|
||||
link = element link { attlist.link, empty }
|
||||
attlist.link &= attribute name { text }
|
||||
attlist.link &= attribute id { text }?
|
||||
attlist.link &= [ a:defaultValue = "1" ] attribute colspan { text }?
|
||||
attlist.link &= attribute states { text }?
|
||||
attlist.link &= attribute icon { text }?
|
||||
attlist.link &= [ a:defaultValue = "show" ] attribute empty { "show" | "hide" }?
|
||||
notebook = element notebook { attlist.notebook, page* }
|
||||
attlist.notebook &= [ a:defaultValue = "4" ] attribute colspan { text }?
|
||||
attlist.notebook &= [ a:defaultValue = "1" ] attribute yexpand { "0" | "1" }?
|
||||
attlist.notebook &= [ a:defaultValue = "1" ] attribute yfill { "0" | "1" }?
|
||||
attlist.notebook &= attribute states { text }?
|
||||
attlist.notebook &= attribute width { text }?
|
||||
attlist.notebook &= attribute height { text }?
|
||||
page =
|
||||
element page {
|
||||
attlist.page,
|
||||
(label
|
||||
| field
|
||||
| image
|
||||
| separator
|
||||
| newline
|
||||
| button
|
||||
| link
|
||||
| notebook
|
||||
| group
|
||||
| hpaned
|
||||
| vpaned)*
|
||||
}
|
||||
attlist.page &= attribute angle { text }?
|
||||
attlist.page &= attribute icon { text }?
|
||||
attlist.page &=
|
||||
[ a:defaultValue = "Unknown" ] attribute string { text }?
|
||||
attlist.page &= [ a:defaultValue = "4" ] attribute col { text }?
|
||||
attlist.page &= ( attribute name { text } | attribute id { text } )
|
||||
attlist.page &= attribute states { text }?
|
||||
group =
|
||||
element group {
|
||||
attlist.group,
|
||||
(label
|
||||
| field
|
||||
| image
|
||||
| separator
|
||||
| newline
|
||||
| button
|
||||
| link
|
||||
| notebook
|
||||
| group
|
||||
| hpaned
|
||||
| vpaned)*
|
||||
}
|
||||
attlist.group &= attribute string { text }?
|
||||
attlist.group &= [ a:defaultValue = "1" ] attribute colspan { text }?
|
||||
attlist.group &=
|
||||
[ a:defaultValue = "0" ] attribute yexpand { "0" | "1" }?
|
||||
attlist.group &= [ a:defaultValue = "1" ] attribute yfill { "0" | "1" }?
|
||||
attlist.group &= [ a:defaultValue = "0.5" ] attribute yalign { text }?
|
||||
attlist.group &=
|
||||
[ a:defaultValue = "0" ] attribute xexpand { "0" | "1" }?
|
||||
attlist.group &= [ a:defaultValue = "1" ] attribute xfill { "0" | "1" }?
|
||||
attlist.group &= [ a:defaultValue = "0.5" ] attribute xalign { text }?
|
||||
attlist.group &= [ a:defaultValue = "1" ] attribute rowspan { text }?
|
||||
attlist.group &= [ a:defaultValue = "4" ] attribute col { text }?
|
||||
attlist.group &= ( attribute name { text } | attribute id { text } )
|
||||
attlist.group &= attribute states { text }?
|
||||
attlist.group &= [ a:defaultValue = "0" ] attribute homogeneous { "0" | "1" }?
|
||||
attlist.group &= attribute expandable { "0" | "1" }?
|
||||
|
||||
hpaned = element hpaned { attlist.paned, child* }
|
||||
|
||||
vpaned = element vpaned { attlist.paned, child* }
|
||||
|
||||
attlist.paned &= [ a:defaultValue = "4" ] attribute colspan { text }?
|
||||
attlist.paned &= attribute position { text }?
|
||||
attlist.paned &= attribute id { text }
|
||||
|
||||
child =
|
||||
element child {
|
||||
attlist.child,
|
||||
(label
|
||||
| field
|
||||
| image
|
||||
| separator
|
||||
| newline
|
||||
| button
|
||||
| link
|
||||
| notebook
|
||||
| group
|
||||
| hpaned
|
||||
| vpaned)*
|
||||
}
|
||||
|
||||
attlist.child &= attribute id { text }
|
||||
|
||||
data = element data { attlist.data, xpath* }
|
||||
attlist.data &= empty
|
||||
|
||||
xpath = element xpath { attlist.xpath,
|
||||
(label
|
||||
| field
|
||||
| image
|
||||
| separator
|
||||
| newline
|
||||
| button
|
||||
| link
|
||||
| notebook
|
||||
| group
|
||||
| hpaned
|
||||
| vpaned
|
||||
| form
|
||||
| page
|
||||
| child)*
|
||||
}
|
||||
attlist.xpath &= attribute expr { text }
|
||||
attlist.xpath &=
|
||||
[ a:defaultValue = "inside" ]
|
||||
attribute position { "inside" | "replace" | "replace_attributes" | "after" | "before" }?
|
||||
|
||||
start = data | form
|
||||
1447
ir/ui/form.rng
Executable file
39
ir/ui/graph.rnc
Executable file
@@ -0,0 +1,39 @@
|
||||
namespace a = "http://relaxng.org/ns/compatibility/annotations/1.0"
|
||||
|
||||
graph = element graph { attlist.graph, x*, y* }
|
||||
attlist.graph &=
|
||||
[ a:defaultValue = "vbar" ]
|
||||
attribute type { "vbar" | "hbar" | "line" | "pie" }?
|
||||
attlist.graph &= attribute background { text }?
|
||||
attlist.graph &= attribute color { text }?
|
||||
attlist.graph &=
|
||||
[ a:defaultValue = "1" ] attribute legend { "0" | "1" }?
|
||||
x = element x { attlist.x, field }
|
||||
attlist.x &= empty
|
||||
y = element y { attlist.y, field+ }
|
||||
attlist.y &= empty
|
||||
field = element field { attlist.field, empty }
|
||||
attlist.field &= attribute name { text }
|
||||
attlist.field &= attribute string { text }?
|
||||
attlist.field &= attribute key { text }?
|
||||
attlist.field &= attribute domain { text }?
|
||||
attlist.field &= attribute fill { "0" | "1" }?
|
||||
attlist.field &= attribute empty { "0" | "1" }?
|
||||
attlist.field &= attribute color { text }?
|
||||
attlist.field &= attribute timedelta { text }?
|
||||
attlist.field &=
|
||||
[ a:defaultValue = "linear" ]
|
||||
attribute interpolation { "constant-left" | "constant-right" | "constant-center" | "linear" }?
|
||||
data = element data { attlist.data, xpath* }
|
||||
attlist.data &= empty
|
||||
xpath = element xpath { attlist.xpath,
|
||||
(graph
|
||||
| x
|
||||
| y
|
||||
| field)*
|
||||
}
|
||||
attlist.xpath &= attribute expr { text }
|
||||
attlist.xpath &=
|
||||
[ a:defaultValue = "inside" ]
|
||||
attribute position { "inside" | "replace" | "replace_attributes" | "after" | "before" }?
|
||||
start = data | graph
|
||||
218
ir/ui/graph.rng
Executable file
@@ -0,0 +1,218 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<grammar xmlns="http://relaxng.org/ns/structure/1.0"
|
||||
xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0">
|
||||
<define name="graph">
|
||||
<element>
|
||||
<name ns="">graph</name>
|
||||
<ref name="attlist.graph"/>
|
||||
<zeroOrMore>
|
||||
<ref name="x"/>
|
||||
</zeroOrMore>
|
||||
<zeroOrMore>
|
||||
<ref name="y"/>
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
</define>
|
||||
<define name="attlist.graph" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="vbar">
|
||||
<name ns="">type</name>
|
||||
<choice>
|
||||
<value>vbar</value>
|
||||
<value>hbar</value>
|
||||
<value>line</value>
|
||||
<value>pie</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.graph" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">background</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.graph" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">color</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.graph" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="1">
|
||||
<name ns="">legend</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="x">
|
||||
<element>
|
||||
<name ns="">x</name>
|
||||
<ref name="attlist.x"/>
|
||||
<ref name="field"/>
|
||||
</element>
|
||||
</define>
|
||||
<define name="attlist.x" combine="interleave">
|
||||
<empty/>
|
||||
</define>
|
||||
<define name="y">
|
||||
<element>
|
||||
<name ns="">y</name>
|
||||
<ref name="attlist.y"/>
|
||||
<oneOrMore>
|
||||
<ref name="field"/>
|
||||
</oneOrMore>
|
||||
</element>
|
||||
</define>
|
||||
<define name="attlist.y" combine="interleave">
|
||||
<empty/>
|
||||
</define>
|
||||
<define name="field">
|
||||
<element>
|
||||
<name ns="">field</name>
|
||||
<ref name="attlist.field"/>
|
||||
<empty/>
|
||||
</element>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<attribute>
|
||||
<name ns="">name</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">string</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">key</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">domain</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">fill</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">empty</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">color</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">timedelta</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="linear">
|
||||
<name ns="">interpolation</name>
|
||||
<choice>
|
||||
<value>constant-left</value>
|
||||
<value>constant-right</value>
|
||||
<value>constant-center</value>
|
||||
<value>linear</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="data">
|
||||
<element>
|
||||
<name ns="">data</name>
|
||||
<ref name="attlist.data"/>
|
||||
<zeroOrMore>
|
||||
<ref name="xpath"/>
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
</define>
|
||||
<define name="attlist.data" combine="interleave">
|
||||
<empty/>
|
||||
</define>
|
||||
<define name="xpath">
|
||||
<element>
|
||||
<name ns="">xpath</name>
|
||||
<ref name="attlist.xpath"/>
|
||||
<zeroOrMore>
|
||||
<choice>
|
||||
<ref name="graph"/>
|
||||
<ref name="x"/>
|
||||
<ref name="y"/>
|
||||
<ref name="field"/>
|
||||
</choice>
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
</define>
|
||||
<define name="attlist.xpath" combine="interleave">
|
||||
<attribute>
|
||||
<name ns="">expr</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</define>
|
||||
<define name="attlist.xpath" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="inside">
|
||||
<name ns="">position</name>
|
||||
<choice>
|
||||
<value>inside</value>
|
||||
<value>replace</value>
|
||||
<value>replace_attributes</value>
|
||||
<value>after</value>
|
||||
<value>before</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<start>
|
||||
<choice>
|
||||
<ref name="data"/>
|
||||
<ref name="graph"/>
|
||||
</choice>
|
||||
</start>
|
||||
</grammar>
|
||||
87
ir/ui/icon.py
Executable file
@@ -0,0 +1,87 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of this
|
||||
# repository contains the full copyright notices and license terms.
|
||||
|
||||
import os
|
||||
|
||||
from trytond.cache import Cache
|
||||
from trytond.model import ModelSQL, ModelView, fields, sequence_ordered
|
||||
from trytond.rpc import RPC
|
||||
from trytond.tools import file_open
|
||||
from trytond.transaction import Transaction
|
||||
|
||||
|
||||
class Icon(
|
||||
fields.fmany2one(
|
||||
'module_ref', 'module', 'ir.module,name', "Module",
|
||||
readonly=True, required=True, ondelete='CASCADE'),
|
||||
sequence_ordered(), ModelSQL, ModelView):
|
||||
'Icon'
|
||||
__name__ = 'ir.ui.icon'
|
||||
|
||||
name = fields.Char('Name', required=True)
|
||||
module = fields.Char('Module', readonly=True, required=True)
|
||||
path = fields.Char('SVG Path', readonly=True, required=True)
|
||||
icon = fields.Function(fields.Char('Icon', depends=['path']), 'get_icon')
|
||||
_list_icons = Cache('ir.ui.icon.list_icons', context=False)
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(Icon, cls).__setup__()
|
||||
cls.__rpc__.update({
|
||||
'list_icons': RPC(),
|
||||
})
|
||||
|
||||
@classmethod
|
||||
def __register__(cls, module_name):
|
||||
super().__register__(module_name)
|
||||
|
||||
table = cls.__table_handler__(module_name)
|
||||
|
||||
# Migration from 5.0: remove required on sequence
|
||||
table.not_null_action('sequence', 'remove')
|
||||
|
||||
@staticmethod
|
||||
def default_module():
|
||||
return Transaction().context.get('module') or ''
|
||||
|
||||
@staticmethod
|
||||
def default_sequence():
|
||||
return 10
|
||||
|
||||
@classmethod
|
||||
def list_icons(cls):
|
||||
icons = cls._list_icons.get(None)
|
||||
if icons is not None:
|
||||
return icons
|
||||
icons = {}
|
||||
for icon in cls.browse(cls.search([],
|
||||
order=[('sequence', 'ASC'), ('id', 'ASC')])):
|
||||
if icon.name not in icons:
|
||||
icons[icon.name] = icon.id
|
||||
icons = sorted((icon_id, name) for name, icon_id in icons.items())
|
||||
cls._list_icons.set(None, icons)
|
||||
return icons
|
||||
|
||||
def get_icon(self, name):
|
||||
path = os.path.join(self.module, self.path.replace('/', os.sep))
|
||||
with file_open(
|
||||
path,
|
||||
subdir='modules' if self.module not in {'ir', 'res'} else '',
|
||||
mode='r', encoding='utf-8') as fp:
|
||||
return fp.read()
|
||||
|
||||
@classmethod
|
||||
def create(cls, vlist):
|
||||
icons = super().create(vlist)
|
||||
cls._list_icons.clear()
|
||||
return icons
|
||||
|
||||
@classmethod
|
||||
def write(cls, *args):
|
||||
super().write(*args)
|
||||
cls._list_icons.clear()
|
||||
|
||||
@classmethod
|
||||
def delete(cls, icons):
|
||||
super().delete(icons)
|
||||
cls._list_icons.clear()
|
||||
38
ir/ui/icon.xml
Executable file
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<tryton>
|
||||
<data>
|
||||
<record model="ir.ui.view" id="icon_view_tree">
|
||||
<field name="model">ir.ui.icon</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="name">icon_view_list</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="icon_view_form">
|
||||
<field name="model">ir.ui.icon</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">icon_view_form</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window" id="act_icon_form">
|
||||
<field name="name">Icons</field>
|
||||
<field name="res_model">ir.ui.icon</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view"
|
||||
id="act_icon_form_view1">
|
||||
<field name="sequence" eval="10"/>
|
||||
<field name="view" ref="icon_view_tree"/>
|
||||
<field name="act_window" ref="act_icon_form"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view"
|
||||
id="act_icon_form_view2">
|
||||
<field name="sequence" eval="20"/>
|
||||
<field name="view" ref="icon_view_form"/>
|
||||
<field name="act_window" ref="act_icon_form"/>
|
||||
</record>
|
||||
<menuitem
|
||||
parent="menu_ui"
|
||||
action="act_icon_form"
|
||||
sequence="20"
|
||||
id="menu_icon_form"/>
|
||||
</data>
|
||||
</tryton>
|
||||
4
ir/ui/icons/tryton-board.svg
Executable file
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M0 0h24v24H0z" fill="none"/>
|
||||
<path d="M3 13h8V3H3v10zm0 8h8v-6H3v6zm10 0h8V11h-8v10zm0-18v6h8V3h-8z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 211 B |
4
ir/ui/icons/tryton-calendar.svg
Executable file
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M9 11H7v2h2v-2zm4 0h-2v2h2v-2zm4 0h-2v2h2v-2zm2-7h-1V2h-2v2H8V2H6v2H5c-1.11 0-1.99.9-1.99 2L3 20c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 16H5V9h14v11z"/>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 313 B |
4
ir/ui/icons/tryton-folder.svg
Executable file
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8l-2-2z"/>
|
||||
<path d="M0 0h24v24H0z" fill="none"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 241 B |
4
ir/ui/icons/tryton-form.svg
Executable file
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"/>
|
||||
<path d="M0 0h24v24H0z" fill="none"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 299 B |
4
ir/ui/icons/tryton-graph.svg
Executable file
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4zm2.5 2.1h-15V5h15v14.1zm0-16.1h-15c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h15c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"/>
|
||||
<path fill="none" d="M0 0h24v24H0z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 298 B |
4
ir/ui/icons/tryton-list.svg
Executable file
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M4 15h16v-2H4v2zm0 4h16v-2H4v2zm0-8h16V9H4v2zm0-6v2h16V5H4z"/>
|
||||
<path fill="none" d="M0 0h24v24H0V0z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 211 B |
4
ir/ui/icons/tryton-settings.svg
Executable file
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
|
||||
<path fill="none" d="M0 0h20v20H0V0z"/>
|
||||
<path d="M15.95 10.78c.03-.25.05-.51.05-.78s-.02-.53-.06-.78l1.69-1.32c.15-.12.19-.34.1-.51l-1.6-2.77c-.1-.18-.31-.24-.49-.18l-1.99.8c-.42-.32-.86-.58-1.35-.78L12 2.34c-.03-.2-.2-.34-.4-.34H8.4c-.2 0-.36.14-.39.34l-.3 2.12c-.49.2-.94.47-1.35.78l-1.99-.8c-.18-.07-.39 0-.49.18l-1.6 2.77c-.1.18-.06.39.1.51l1.69 1.32c-.04.25-.07.52-.07.78s.02.53.06.78L2.37 12.1c-.15.12-.19.34-.1.51l1.6 2.77c.1.18.31.24.49.18l1.99-.8c.42.32.86.58 1.35.78l.3 2.12c.04.2.2.34.4.34h3.2c.2 0 .37-.14.39-.34l.3-2.12c.49-.2.94-.47 1.35-.78l1.99.8c.18.07.39 0 .49-.18l1.6-2.77c.1-.18.06-.39-.1-.51l-1.67-1.32zM10 13c-1.65 0-3-1.35-3-3s1.35-3 3-3 3 1.35 3 3-1.35 3-3 3z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 786 B |
4
ir/ui/icons/tryton-tree.svg
Executable file
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M3 13h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm4 4h14v-2H7v2zm0 4h14v-2H7v2zM7 7v2h14V7H7z"/>
|
||||
<path d="M0 0h24v24H0z" fill="none"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 236 B |
308
ir/ui/menu.py
Executable file
@@ -0,0 +1,308 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
from collections import defaultdict
|
||||
from itertools import groupby
|
||||
|
||||
from trytond.model import (
|
||||
DeactivableMixin, ModelSQL, ModelView, fields, sequence_ordered, tree)
|
||||
from trytond.pool import Pool
|
||||
from trytond.rpc import RPC
|
||||
from trytond.tools import grouped_slice
|
||||
from trytond.transaction import Transaction, inactive_records
|
||||
|
||||
|
||||
def one_in(i, j):
|
||||
"""Check the presence of an element of setA in setB
|
||||
"""
|
||||
for k in i:
|
||||
if k in j:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
CLIENT_ICONS = [(x, x) for x in [
|
||||
'tryton-add',
|
||||
'tryton-archive',
|
||||
'tryton-attach',
|
||||
'tryton-back',
|
||||
'tryton-barcode-scanner',
|
||||
'tryton-bookmark-border',
|
||||
'tryton-bookmark',
|
||||
'tryton-bookmarks',
|
||||
'tryton-cancel',
|
||||
'tryton-clear',
|
||||
'tryton-close',
|
||||
'tryton-copy',
|
||||
'tryton-create',
|
||||
'tryton-date',
|
||||
'tryton-delete',
|
||||
'tryton-download',
|
||||
'tryton-email',
|
||||
'tryton-error',
|
||||
'tryton-exit',
|
||||
'tryton-export',
|
||||
'tryton-filter',
|
||||
'tryton-format-align-center',
|
||||
'tryton-format-align-justify',
|
||||
'tryton-format-align-left',
|
||||
'tryton-format-align-right',
|
||||
'tryton-format-bold',
|
||||
'tryton-format-color-text',
|
||||
'tryton-format-italic',
|
||||
'tryton-format-underline',
|
||||
'tryton-forward',
|
||||
'tryton-history',
|
||||
'tryton-import',
|
||||
'tryton-info',
|
||||
'tryton-launch',
|
||||
'tryton-link',
|
||||
'tryton-log',
|
||||
'tryton-menu',
|
||||
'tryton-note',
|
||||
'tryton-ok',
|
||||
'tryton-open',
|
||||
'tryton-print',
|
||||
'tryton-public',
|
||||
'tryton-refresh',
|
||||
'tryton-remove',
|
||||
'tryton-save',
|
||||
'tryton-search',
|
||||
'tryton-sound-off',
|
||||
'tryton-sound-on',
|
||||
'tryton-star-border',
|
||||
'tryton-star',
|
||||
'tryton-switch',
|
||||
'tryton-translate',
|
||||
'tryton-unarchive',
|
||||
'tryton-undo',
|
||||
'tryton-warning',
|
||||
]]
|
||||
|
||||
|
||||
class UIMenu(
|
||||
DeactivableMixin,
|
||||
sequence_ordered(order='ASC NULLS LAST'),
|
||||
tree(separator=' / '),
|
||||
ModelSQL, ModelView):
|
||||
"UI menu"
|
||||
__name__ = 'ir.ui.menu'
|
||||
|
||||
name = fields.Char('Menu', required=True, translate=True)
|
||||
childs = fields.One2Many('ir.ui.menu', 'parent', 'Children')
|
||||
parent = fields.Many2One('ir.ui.menu', 'Parent Menu', ondelete='CASCADE')
|
||||
complete_name = fields.Function(fields.Char('Complete Name'),
|
||||
'get_rec_name', searcher='search_rec_name')
|
||||
icon = fields.Selection('list_icons', 'Icon', translate=False)
|
||||
action = fields.Function(fields.Reference('Action',
|
||||
selection=[
|
||||
('', ''),
|
||||
('ir.action.report', 'ir.action.report'),
|
||||
('ir.action.act_window', 'ir.action.act_window'),
|
||||
('ir.action.wizard', 'ir.action.wizard'),
|
||||
('ir.action.url', 'ir.action.url'),
|
||||
], translate=False), 'get_action', setter='set_action')
|
||||
action_keywords = fields.One2Many(
|
||||
'ir.action.keyword', 'model', "Action Keywords",
|
||||
filter=[
|
||||
('keyword', '=', 'tree_open'),
|
||||
])
|
||||
favorite = fields.Function(fields.Boolean('Favorite'), 'get_favorite')
|
||||
|
||||
@classmethod
|
||||
def order_complete_name(cls, tables):
|
||||
return cls.name.convert_order('name', tables, cls)
|
||||
|
||||
@staticmethod
|
||||
def default_icon():
|
||||
return 'tryton-folder'
|
||||
|
||||
@classmethod
|
||||
def default_sequence(cls):
|
||||
return 50
|
||||
|
||||
@staticmethod
|
||||
def list_icons():
|
||||
pool = Pool()
|
||||
Icon = pool.get('ir.ui.icon')
|
||||
return sorted(CLIENT_ICONS
|
||||
+ [(name, name) for _, name in Icon.list_icons()])
|
||||
|
||||
@classmethod
|
||||
def search_global(cls, text):
|
||||
# TODO improve search clause
|
||||
for record in cls.search([
|
||||
('rec_name', 'ilike', '%%%s%%' % text),
|
||||
]):
|
||||
if record.action_keywords:
|
||||
yield record, record.rec_name, record.icon
|
||||
|
||||
@classmethod
|
||||
def search(cls, domain, offset=0, limit=None, order=None, count=False,
|
||||
query=False):
|
||||
pool = Pool()
|
||||
ModelAccess = pool.get('ir.model.access')
|
||||
transaction = Transaction()
|
||||
|
||||
def has_action_access(menu):
|
||||
if menu.action_keywords and all(
|
||||
k.action.type == 'ir.action.act_window'
|
||||
for k in menu.action_keywords):
|
||||
for keyword in menu.action_keywords:
|
||||
res_model = keyword.action.action.res_model
|
||||
if not res_model:
|
||||
break
|
||||
if ModelAccess.check(res_model, raise_exception=False):
|
||||
break
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
|
||||
menus = super(UIMenu, cls).search(domain, offset=offset, limit=limit,
|
||||
order=order, count=False, query=query)
|
||||
if query:
|
||||
return menus
|
||||
|
||||
if transaction.check_access and menus:
|
||||
|
||||
menus = list(filter(has_action_access, menus))
|
||||
|
||||
parent_ids = {x.parent.id for x in menus if x.parent}
|
||||
parents = set()
|
||||
for sub_parent_ids in grouped_slice(parent_ids):
|
||||
parents.update(cls.search([
|
||||
('id', 'in', list(sub_parent_ids)),
|
||||
]))
|
||||
# Re-browse to avoid side-cache access
|
||||
menus = cls.browse([x.id for x in menus
|
||||
if (x.parent and x.parent in parents) or not x.parent])
|
||||
|
||||
if count:
|
||||
return len(menus)
|
||||
return menus
|
||||
|
||||
@classmethod
|
||||
@inactive_records
|
||||
def get_action(cls, menus, name):
|
||||
pool = Pool()
|
||||
actions = dict((m.id, None) for m in menus)
|
||||
menus = cls.browse(menus)
|
||||
action_keywords = sum((list(m.action_keywords) for m in menus), [])
|
||||
|
||||
def action_type(keyword):
|
||||
return keyword.action.type
|
||||
action_keywords.sort(key=action_type)
|
||||
for type, action_keywords in groupby(action_keywords, key=action_type):
|
||||
action_keywords = list(action_keywords)
|
||||
action2keywords = defaultdict(list)
|
||||
for action_keyword in action_keywords:
|
||||
model = action_keyword.model
|
||||
actions[model.id] = '%s,-1' % type
|
||||
action2keywords[action_keyword.action.id].append(
|
||||
action_keyword)
|
||||
|
||||
Action = pool.get(type)
|
||||
factions = Action.search([
|
||||
('action', 'in', list(action2keywords.keys())),
|
||||
])
|
||||
for action in factions:
|
||||
for action_keyword in action2keywords[action.id]:
|
||||
actions[action_keyword.model.id] = str(action)
|
||||
return actions
|
||||
|
||||
@classmethod
|
||||
def set_action(cls, menus, name, value):
|
||||
pool = Pool()
|
||||
ActionKeyword = pool.get('ir.action.keyword')
|
||||
action_keywords = []
|
||||
transaction = Transaction()
|
||||
for i in range(0, len(menus), transaction.database.IN_MAX):
|
||||
sub_menus = menus[i:i + transaction.database.IN_MAX]
|
||||
action_keywords += ActionKeyword.search([
|
||||
('keyword', '=', 'tree_open'),
|
||||
('model', 'in', [str(menu) for menu in sub_menus]),
|
||||
])
|
||||
if action_keywords:
|
||||
with Transaction().set_context(_timestamp=False):
|
||||
ActionKeyword.delete(action_keywords)
|
||||
if not value:
|
||||
return
|
||||
if isinstance(value, str):
|
||||
action_type, action_id = value.split(',')
|
||||
else:
|
||||
action_type, action_id = value
|
||||
if int(action_id) <= 0:
|
||||
return
|
||||
Action = pool.get(action_type)
|
||||
action = Action(int(action_id))
|
||||
to_create = []
|
||||
for menu in menus:
|
||||
with Transaction().set_context(_timestamp=False):
|
||||
to_create.append({
|
||||
'keyword': 'tree_open',
|
||||
'model': str(menu),
|
||||
'action': action.action.id,
|
||||
})
|
||||
if to_create:
|
||||
ActionKeyword.create(to_create)
|
||||
|
||||
@classmethod
|
||||
def get_favorite(cls, menus, name):
|
||||
pool = Pool()
|
||||
Favorite = pool.get('ir.ui.menu.favorite')
|
||||
user = Transaction().user
|
||||
favorites = Favorite.search([
|
||||
('menu', 'in', [m.id for m in menus]),
|
||||
('user', '=', user),
|
||||
])
|
||||
menu2favorite = {
|
||||
m.id: False if m.action_keywords else None for m in menus}
|
||||
menu2favorite.update(dict((f.menu.id, True) for f in favorites))
|
||||
return menu2favorite
|
||||
|
||||
|
||||
class UIMenuFavorite(sequence_ordered(), ModelSQL, ModelView):
|
||||
"Menu Favorite"
|
||||
__name__ = 'ir.ui.menu.favorite'
|
||||
|
||||
menu = fields.Many2One('ir.ui.menu', 'Menu', required=True,
|
||||
ondelete='CASCADE')
|
||||
user = fields.Many2One('res.user', 'User', required=True,
|
||||
ondelete='CASCADE')
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(UIMenuFavorite, cls).__setup__()
|
||||
cls.__rpc__.update({
|
||||
'get': RPC(check_access=False),
|
||||
'set': RPC(check_access=False, readonly=False),
|
||||
'unset': RPC(check_access=False, readonly=False),
|
||||
})
|
||||
|
||||
@staticmethod
|
||||
def default_user():
|
||||
return Transaction().user
|
||||
|
||||
@classmethod
|
||||
def get(cls):
|
||||
user = Transaction().user
|
||||
favorites = cls.search([
|
||||
('user', '=', user),
|
||||
])
|
||||
return [(f.menu.id, f.menu.rec_name, f.menu.icon) for f in favorites]
|
||||
|
||||
@classmethod
|
||||
def set(cls, menu_id):
|
||||
user = Transaction().user
|
||||
cls.create([{
|
||||
'menu': menu_id,
|
||||
'user': user,
|
||||
}])
|
||||
|
||||
@classmethod
|
||||
def unset(cls, menu_id):
|
||||
user = Transaction().user
|
||||
favorites = cls.search([
|
||||
('menu', '=', menu_id),
|
||||
('user', '=', user),
|
||||
])
|
||||
cls.delete(favorites)
|
||||
76
ir/ui/menu.xml
Executable file
@@ -0,0 +1,76 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<tryton>
|
||||
<data>
|
||||
<record model="ir.ui.view" id="menu_view_tree_tree">
|
||||
<field name="model">ir.ui.menu</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="field_childs">childs</field>
|
||||
<field name="priority" eval="20"/>
|
||||
<field name="name">ui_menu_tree</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="menu_view_list">
|
||||
<field name="model">ir.ui.menu</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="priority" eval="10"/>
|
||||
<field name="name">ui_menu_list</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="menu_view_form">
|
||||
<field name="model">ir.ui.menu</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">ui_menu_form</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.action.act_window" id="act_menu_tree">
|
||||
<field name="name">Menu</field>
|
||||
<field name="res_model">ir.ui.menu</field>
|
||||
<field name="usage">menu</field>
|
||||
<field name="domain" eval="[('parent', '=', None)]" pyson="1"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view"
|
||||
id="act_menu_tree_view1">
|
||||
<field name="sequence" eval="1"/>
|
||||
<field name="view" ref="menu_view_tree_tree"/>
|
||||
<field name="act_window" ref="act_menu_tree"/>
|
||||
</record>
|
||||
|
||||
<record model="ir.action.act_window" id="act_menu_list">
|
||||
<field name="name">Menu</field>
|
||||
<field name="res_model">ir.ui.menu</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view"
|
||||
id="act_menu_list_view1">
|
||||
<field name="sequence" eval="10"/>
|
||||
<field name="view" ref="menu_view_list"/>
|
||||
<field name="act_window" ref="act_menu_list"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view"
|
||||
id="act_menu_list_view2">
|
||||
<field name="sequence" eval="20"/>
|
||||
<field name="view" ref="menu_view_form"/>
|
||||
<field name="act_window" ref="act_menu_list"/>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
parent="menu_ui"
|
||||
action="act_menu_list"
|
||||
sequence="10"
|
||||
id="menu_menu_list"/>
|
||||
|
||||
<record model="ir.ui.view" id="menu_favorite_view_list">
|
||||
<field name="model">ir.ui.menu.favorite</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="name">ui_menu_favorite_list</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="menu_favorite_view_form">
|
||||
<field name="model">ir.ui.menu.favorite</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">ui_menu_favorite_form</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</tryton>
|
||||
114
ir/ui/tree.rnc
Executable file
@@ -0,0 +1,114 @@
|
||||
namespace a = "http://relaxng.org/ns/compatibility/annotations/1.0"
|
||||
|
||||
tree = element tree { attlist.tree,
|
||||
(field
|
||||
| button)*
|
||||
}
|
||||
attlist.tree &= attribute on_write { text }?
|
||||
attlist.tree &= attribute editable { "0" | "1" }?
|
||||
attlist.tree &=
|
||||
[ a:defaultValue = "1" ] attribute creatable { "0" | "1" }?
|
||||
attlist.tree &= attribute sequence { text }?
|
||||
attlist.tree &=
|
||||
[ a:defaultValue = "0" ] attribute keyword_open { "0" | "1" }?
|
||||
attlist.tree &=
|
||||
[ a:defaultValue = "0" ] attribute tree_state { "0" | "1" }?
|
||||
attlist.tree &= attribute visual { text }?
|
||||
field = element field { attlist.field, (prefix | suffix)* }
|
||||
attlist.field &= attribute name { text }
|
||||
attlist.field &= attribute readonly { "0" | "1" }?
|
||||
attlist.field &=
|
||||
attribute widget {
|
||||
"binary"
|
||||
| "boolean"
|
||||
| "callto"
|
||||
| "char"
|
||||
| "date"
|
||||
| "datetime"
|
||||
| "email"
|
||||
| "float"
|
||||
| "image"
|
||||
| "integer"
|
||||
| "many2many"
|
||||
| "many2one"
|
||||
| "multiselection"
|
||||
| "numeric"
|
||||
| "one2many"
|
||||
| "one2one"
|
||||
| "progressbar"
|
||||
| "reference"
|
||||
| "selection"
|
||||
| "sip"
|
||||
| "text"
|
||||
| "time"
|
||||
| "timedelta"
|
||||
| "url"
|
||||
}?
|
||||
attlist.field &=
|
||||
[ a:defaultValue = "0" ] attribute tree_invisible { text }?
|
||||
attlist.field &= attribute optional { "0" | "1" }?
|
||||
attlist.field &=
|
||||
[ a:defaultValue = "0" ] attribute expand { xsd:integer }?
|
||||
attlist.field &= attribute visual { text }?
|
||||
attlist.field &= attribute icon { text }?
|
||||
attlist.field &=
|
||||
[ a:defaultValue = "0" ] attribute sum { "0" | "1" }?
|
||||
attlist.field &= attribute width { text }?
|
||||
attlist.field &= attribute height { text }?
|
||||
attlist.field &=
|
||||
[ a:defaultValue = "1" ] attribute create { "0" | "1" }?
|
||||
attlist.field &=
|
||||
[ a:defaultValue = "1" ] attribute delete { "0" | "1" }?
|
||||
attlist.field &=
|
||||
[ a:defaultValue = "left_to_right" ] attribute orientation {
|
||||
"left_to_right"
|
||||
| "right_to_left"
|
||||
| "bottom_to_top"
|
||||
| "top_to_bottom"
|
||||
}?
|
||||
attlist.field &= [a:defaultValue = "0"] attribute pre_validate { "0" | "1" }?
|
||||
attlist.field &= [a:defaultValue = "1"] attribute completion { "0" | "1" }?
|
||||
attlist.field &= attribute string { text }?
|
||||
attlist.field &= [a:defaultValue = "1"] attribute factor { text }?
|
||||
attlist.field &= attribute filename { text }?
|
||||
attlist.field &= attribute help_field { text }?
|
||||
attlist.field &= attribute view_ids { text }?
|
||||
attlist.field &= attribute symbol { text }?
|
||||
attlist.field &= [a:defaultValue = "1"] attribute grouping { "0" | "1" }?
|
||||
prefix = element prefix { attlist.affix, empty }
|
||||
suffix = element suffix { attlist.affix, empty }
|
||||
attlist.affix &= attribute string { text }?
|
||||
attlist.affix &= ( attribute name { text } | attribute id { text } )
|
||||
attlist.affix &= attribute icon { text }?
|
||||
attlist.affix &= [a:defaultValue = "icon"] attribute icon_type { "icon" | "url" }?
|
||||
attlist.affix &= attribute url_size { text }?
|
||||
attlist.affix &= [a:defaultValue = "square"] attribute border { "square" | "circle" | "rounded" }?
|
||||
button = element button { attlist.button, empty }
|
||||
attlist.button &= attribute help { text }?
|
||||
attlist.button &= attribute string { text }?
|
||||
attlist.button &= attribute confirm { text }?
|
||||
attlist.button &= attribute name { text }
|
||||
attlist.button &= attribute states { text }?
|
||||
attlist.button &=
|
||||
[ a:defaultValue="action" ]
|
||||
attribute keyword { "relate" | "print" | "action" }?
|
||||
attlist.button &= attribute change { text }?
|
||||
attlist.button &= attribute type { "class" | "instance" }?
|
||||
attlist.button &=
|
||||
[ a:defaultValue = "0" ] attribute tree_invisible { text }?
|
||||
attlist.button &= attribute width { text }?
|
||||
data = element data { attlist.data, xpath* }
|
||||
attlist.data &= empty
|
||||
xpath = element xpath { attlist.xpath,
|
||||
(field
|
||||
| prefix
|
||||
| suffix
|
||||
| button
|
||||
| tree
|
||||
)*
|
||||
}
|
||||
attlist.xpath &= attribute expr { text }
|
||||
attlist.xpath &=
|
||||
[ a:defaultValue = "inside" ]
|
||||
attribute position { "inside" | "replace" | "replace_attributes" | "after" | "before" }?
|
||||
start = tree | data
|
||||
551
ir/ui/tree.rng
Executable file
@@ -0,0 +1,551 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<grammar xmlns="http://relaxng.org/ns/structure/1.0"
|
||||
xmlns:a="http://relaxng.org/ns/compatibility/annotations/1.0"
|
||||
datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes">
|
||||
<define name="tree">
|
||||
<element>
|
||||
<name ns="">tree</name>
|
||||
<ref name="attlist.tree"/>
|
||||
<zeroOrMore>
|
||||
<choice>
|
||||
<ref name="field"/>
|
||||
<ref name="button"/>
|
||||
</choice>
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
</define>
|
||||
<define name="attlist.tree" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">on_write</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.tree" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">editable</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.tree" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="1">
|
||||
<name ns="">creatable</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.tree" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">sequence</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.tree" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="0">
|
||||
<name ns="">keyword_open</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.tree" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="0">
|
||||
<name ns="">tree_state</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.tree" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">visual</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="field">
|
||||
<element>
|
||||
<name ns="">field</name>
|
||||
<ref name="attlist.field"/>
|
||||
<zeroOrMore>
|
||||
<choice>
|
||||
<ref name="prefix"/>
|
||||
<ref name="suffix"/>
|
||||
</choice>
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<attribute>
|
||||
<name ns="">name</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">readonly</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">widget</name>
|
||||
<choice>
|
||||
<value>binary</value>
|
||||
<value>boolean</value>
|
||||
<value>callto</value>
|
||||
<value>char</value>
|
||||
<value>date</value>
|
||||
<value>datetime</value>
|
||||
<value>email</value>
|
||||
<value>float</value>
|
||||
<value>image</value>
|
||||
<value>integer</value>
|
||||
<value>many2many</value>
|
||||
<value>many2one</value>
|
||||
<value>multiselection</value>
|
||||
<value>numeric</value>
|
||||
<value>one2many</value>
|
||||
<value>one2one</value>
|
||||
<value>progressbar</value>
|
||||
<value>reference</value>
|
||||
<value>selection</value>
|
||||
<value>sip</value>
|
||||
<value>text</value>
|
||||
<value>time</value>
|
||||
<value>timedelta</value>
|
||||
<value>url</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="0">
|
||||
<name ns="">tree_invisible</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">optional</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="0">
|
||||
<name ns="">expand</name>
|
||||
<data type="integer"/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">visual</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">icon</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="0">
|
||||
<name ns="">sum</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">width</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">height</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="1">
|
||||
<name ns="">create</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="1">
|
||||
<name ns="">delete</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="left_to_right">
|
||||
<name ns="">orientation</name>
|
||||
<choice>
|
||||
<value>left_to_right</value>
|
||||
<value>right_to_left</value>
|
||||
<value>bottom_to_top</value>
|
||||
<value>top_to_bottom</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="0">
|
||||
<name ns="">pre_validate</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="1">
|
||||
<name ns="">completion</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">string</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="1">
|
||||
<name ns="">factor</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">filename</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">help_field</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">view_ids</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">symbol</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.field" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="1">
|
||||
<name ns="">grouping</name>
|
||||
<choice>
|
||||
<value>0</value>
|
||||
<value>1</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="prefix">
|
||||
<element>
|
||||
<name ns="">prefix</name>
|
||||
<ref name="attlist.affix"/>
|
||||
<empty/>
|
||||
</element>
|
||||
</define>
|
||||
<define name="suffix">
|
||||
<element>
|
||||
<name ns="">suffix</name>
|
||||
<ref name="attlist.affix"/>
|
||||
<empty/>
|
||||
</element>
|
||||
</define>
|
||||
<define name="attlist.affix" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">string</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.affix" combine="interleave">
|
||||
<choice>
|
||||
<attribute>
|
||||
<name ns="">name</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
<attribute>
|
||||
<name ns="">id</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</choice>
|
||||
</define>
|
||||
<define name="attlist.affix" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">icon</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.affix" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="icon">
|
||||
<name ns="">icon_type</name>
|
||||
<choice>
|
||||
<value>icon</value>
|
||||
<value>url</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.affix" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">url_size</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.affix" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="square">
|
||||
<name ns="">border</name>
|
||||
<choice>
|
||||
<value>square</value>
|
||||
<value>circle</value>
|
||||
<value>rounded</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="button">
|
||||
<element>
|
||||
<name ns="">button</name>
|
||||
<ref name="attlist.button"/>
|
||||
<empty/>
|
||||
</element>
|
||||
</define>
|
||||
<define name="attlist.button" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">help</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.button" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">string</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.button" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">confirm</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.button" combine="interleave">
|
||||
<attribute>
|
||||
<name ns="">name</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</define>
|
||||
<define name="attlist.button" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">states</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.button" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="action">
|
||||
<name ns="">keyword</name>
|
||||
<choice>
|
||||
<value>relate</value>
|
||||
<value>print</value>
|
||||
<value>action</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.button" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">change</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.button" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">type</name>
|
||||
<choice>
|
||||
<value>class</value>
|
||||
<value>instance</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.button" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="0">
|
||||
<name ns="">tree_invisible</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="attlist.button" combine="interleave">
|
||||
<optional>
|
||||
<attribute>
|
||||
<name ns="">width</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<define name="data">
|
||||
<element>
|
||||
<name ns="">data</name>
|
||||
<ref name="attlist.data"/>
|
||||
<zeroOrMore>
|
||||
<ref name="xpath"/>
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
</define>
|
||||
<define name="attlist.data" combine="interleave">
|
||||
<empty/>
|
||||
</define>
|
||||
<define name="xpath">
|
||||
<element>
|
||||
<name ns="">xpath</name>
|
||||
<ref name="attlist.xpath"/>
|
||||
<zeroOrMore>
|
||||
<choice>
|
||||
<ref name="field"/>
|
||||
<ref name="prefix"/>
|
||||
<ref name="suffix"/>
|
||||
<ref name="button"/>
|
||||
<ref name="tree"/>
|
||||
</choice>
|
||||
</zeroOrMore>
|
||||
</element>
|
||||
</define>
|
||||
<define name="attlist.xpath" combine="interleave">
|
||||
<attribute>
|
||||
<name ns="">expr</name>
|
||||
<text/>
|
||||
</attribute>
|
||||
</define>
|
||||
<define name="attlist.xpath" combine="interleave">
|
||||
<optional>
|
||||
<attribute a:defaultValue="inside">
|
||||
<name ns="">position</name>
|
||||
<choice>
|
||||
<value>inside</value>
|
||||
<value>replace</value>
|
||||
<value>replace_attributes</value>
|
||||
<value>after</value>
|
||||
<value>before</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
</optional>
|
||||
</define>
|
||||
<start>
|
||||
<choice>
|
||||
<ref name="tree"/>
|
||||
<ref name="data"/>
|
||||
</choice>
|
||||
</start>
|
||||
</grammar>
|
||||
50
ir/ui/ui.xml
Executable file
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<tryton>
|
||||
<data>
|
||||
<record model="ir.ui.icon" id="board_icon">
|
||||
<field name="name">tryton-board</field>
|
||||
<field name="path">ui/icons/tryton-board.svg</field>
|
||||
</record>
|
||||
<record model="ir.ui.icon" id="calendar_icon">
|
||||
<field name="name">tryton-calendar</field>
|
||||
<field name="path">ui/icons/tryton-calendar.svg</field>
|
||||
</record>
|
||||
<record model="ir.ui.icon" id="folder_icon">
|
||||
<field name="name">tryton-folder</field>
|
||||
<field name="path">ui/icons/tryton-folder.svg</field>
|
||||
</record>
|
||||
<record model="ir.ui.icon" id="form_icon">
|
||||
<field name="name">tryton-form</field>
|
||||
<field name="path">ui/icons/tryton-form.svg</field>
|
||||
</record>
|
||||
<record model="ir.ui.icon" id="graph_icon">
|
||||
<field name="name">tryton-graph</field>
|
||||
<field name="path">ui/icons/tryton-graph.svg</field>
|
||||
</record>
|
||||
<record model="ir.ui.icon" id="list_icon">
|
||||
<field name="name">tryton-list</field>
|
||||
<field name="path">ui/icons/tryton-list.svg</field>
|
||||
</record>
|
||||
<record model="ir.ui.icon" id="settings_icon">
|
||||
<field name="name">tryton-settings</field>
|
||||
<field name="path">ui/icons/tryton-settings.svg</field>
|
||||
</record>
|
||||
<record model="ir.ui.icon" id="tree_icon">
|
||||
<field name="name">tryton-tree</field>
|
||||
<field name="path">ui/icons/tryton-tree.svg</field>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
name="Administration"
|
||||
sequence="9999"
|
||||
id="menu_administration"
|
||||
icon="tryton-settings"/>
|
||||
<menuitem
|
||||
name="User Interface"
|
||||
parent="menu_administration"
|
||||
sequence="50"
|
||||
id="menu_ui"/>
|
||||
</data>
|
||||
</tryton>
|
||||
797
ir/ui/view.py
Executable file
@@ -0,0 +1,797 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
import json
|
||||
import os
|
||||
import logging
|
||||
from lxml import etree
|
||||
from sql import Literal, Null
|
||||
|
||||
from trytond.cache import Cache, MemoryCache
|
||||
from trytond.i18n import gettext
|
||||
from trytond.model import Index, ModelSQL, ModelView, fields, sequence_ordered
|
||||
from trytond.model.exceptions import ValidationError
|
||||
from trytond.pool import Pool
|
||||
from trytond.pyson import PYSON, Bool, Eval, If, PYSONDecoder
|
||||
from trytond.rpc import RPC
|
||||
from trytond.tools import file_open
|
||||
from trytond.transaction import Transaction
|
||||
from trytond.wizard import Button, StateView, Wizard
|
||||
|
||||
from ..action import DomainError, ViewError
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class XMLError(ValidationError):
|
||||
pass
|
||||
|
||||
|
||||
class View(
|
||||
fields.fmany2one(
|
||||
'model_ref', 'model', 'ir.model,model', "Model",
|
||||
ondelete='CASCADE'),
|
||||
fields.fmany2one(
|
||||
'field_children', 'field_childs,model',
|
||||
'ir.model.field,name,model',
|
||||
"Children Field",
|
||||
domain=[
|
||||
('model', '=', Eval('model')),
|
||||
],
|
||||
states={
|
||||
'invisible': Eval('type') != 'tree',
|
||||
}),
|
||||
fields.fmany2one(
|
||||
'module_ref', 'module', 'ir.module,name', "Module",
|
||||
readonly=True, ondelete='CASCADE'),
|
||||
sequence_ordered('priority', "Priority"), ModelSQL, ModelView):
|
||||
"View"
|
||||
__name__ = 'ir.ui.view'
|
||||
model = fields.Char('Model', states={
|
||||
'required': Eval('type') != 'board',
|
||||
})
|
||||
type = fields.Selection([
|
||||
(None, ''),
|
||||
('tree', 'Tree'),
|
||||
('form', 'Form'),
|
||||
('graph', 'Graph'),
|
||||
('calendar', 'Calendar'),
|
||||
('board', 'Board'),
|
||||
('list-form', "List Form"),
|
||||
], 'View Type',
|
||||
domain=[
|
||||
If(Bool(Eval('inherit')),
|
||||
('type', '=', None),
|
||||
('type', '!=', None)),
|
||||
],
|
||||
depends=['inherit'])
|
||||
type_string = type.translated('type')
|
||||
data = fields.Text('Data')
|
||||
name = fields.Char('Name', states={
|
||||
'invisible': ~(Eval('module') & Eval('name')),
|
||||
}, depends=['module'], readonly=True)
|
||||
arch = fields.Function(fields.Text('View Architecture', states={
|
||||
'readonly': Bool(Eval('name')),
|
||||
}, depends=['name']), 'get_arch', setter='set_arch')
|
||||
basis = fields.Function(fields.Boolean("Basis"), 'get_basis')
|
||||
inherit = fields.Many2One('ir.ui.view', 'Inherited View',
|
||||
ondelete='CASCADE')
|
||||
extensions = fields.One2Many(
|
||||
'ir.ui.view', 'inherit', "Extensions",
|
||||
filter=[
|
||||
('basis', '=', False),
|
||||
],
|
||||
domain=[
|
||||
('model', '=', Eval('model')),
|
||||
('type', '=', None),
|
||||
],
|
||||
states={
|
||||
'invisible': ~Eval('type'),
|
||||
},
|
||||
order=[('id', None)])
|
||||
field_childs = fields.Char('Children Field', states={
|
||||
'invisible': Eval('type') != 'tree',
|
||||
}, depends=['type'])
|
||||
module = fields.Char('Module', states={
|
||||
'invisible': ~Eval('module'),
|
||||
}, readonly=True)
|
||||
domain = fields.Char('Domain', states={
|
||||
'invisible': ~Eval('inherit'),
|
||||
}, depends=['inherit'])
|
||||
_get_rng_cache = MemoryCache('ir_ui_view.get_rng', context=False)
|
||||
_view_get_cache = Cache('ir_ui_view.view_get')
|
||||
__module_index = None
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(View, cls).__setup__()
|
||||
table = cls.__table__()
|
||||
cls.priority.required = True
|
||||
|
||||
cls.__rpc__['view_get'] = RPC(instantiate=0, cache=dict(days=1))
|
||||
cls._buttons.update({
|
||||
'show': {
|
||||
'readonly': Eval('type') != 'form',
|
||||
'invisible': ~Eval('basis', False),
|
||||
'depends': ['type', 'basis'],
|
||||
},
|
||||
})
|
||||
cls._sql_indexes.update({
|
||||
Index(table,
|
||||
(table.model, Index.Equality()),
|
||||
(table.inherit, Index.Equality())),
|
||||
Index(
|
||||
table,
|
||||
(table.id, Index.Equality()),
|
||||
(table.inherit, Index.Equality())),
|
||||
})
|
||||
|
||||
@staticmethod
|
||||
def default_priority():
|
||||
return 16
|
||||
|
||||
@staticmethod
|
||||
def default_module():
|
||||
return Transaction().context.get('module') or ''
|
||||
|
||||
def get_basis(self, name):
|
||||
return not self.inherit or self.model != self.inherit.model
|
||||
|
||||
@classmethod
|
||||
def domain_basis(cls, domain, tables):
|
||||
table, _ = tables[None]
|
||||
if 'inherit' not in tables:
|
||||
inherit = cls.__table__()
|
||||
tables['inherit'] = {
|
||||
None: (inherit, table.inherit == inherit.id),
|
||||
}
|
||||
else:
|
||||
inherit, _ = tables['inherit'][None]
|
||||
expression = (table.inherit == Null) | (table.model != inherit.model)
|
||||
|
||||
_, operator, value = domain
|
||||
if operator in {'=', '!='}:
|
||||
if (operator == '=') != value:
|
||||
expression = ~expression
|
||||
elif operator in {'in', 'not in'}:
|
||||
if True in value and False not in value:
|
||||
pass
|
||||
elif False in value and True not in value:
|
||||
expression = ~expression
|
||||
else:
|
||||
expression = Literal(True)
|
||||
else:
|
||||
expression = Literal(True)
|
||||
return expression
|
||||
|
||||
def get_rec_name(self, name):
|
||||
return '%s (%s)' % (
|
||||
self.model_ref.rec_name,
|
||||
self.inherit.rec_name if self.inherit else self.type_string)
|
||||
|
||||
@classmethod
|
||||
def search_rec_name(cls, name, clause):
|
||||
return [('model_ref.rec_name', *clause[1:])]
|
||||
|
||||
@classmethod
|
||||
@ModelView.button_action('ir.act_view_show')
|
||||
def show(cls, views):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def get_rng(cls, type_):
|
||||
key = (cls.__name__, type_)
|
||||
rng = cls._get_rng_cache.get(key)
|
||||
if rng is None:
|
||||
if type_ == 'list-form':
|
||||
type_ = 'form'
|
||||
rng_name = os.path.join(os.path.dirname(__file__), type_ + '.rng')
|
||||
with open(rng_name, 'rb') as fp:
|
||||
rng = etree.fromstring(fp.read())
|
||||
cls._get_rng_cache.set(key, rng)
|
||||
return rng
|
||||
|
||||
@property
|
||||
def rng_type(self):
|
||||
if self.inherit:
|
||||
return self.inherit.rng_type
|
||||
return self.type
|
||||
|
||||
@classmethod
|
||||
def validate(cls, views):
|
||||
super(View, cls).validate(views)
|
||||
cls.check_xml(views)
|
||||
|
||||
@classmethod
|
||||
def check_xml(cls, views):
|
||||
"Check XML"
|
||||
for view in views:
|
||||
if not view.arch:
|
||||
continue
|
||||
xml = view.arch.strip()
|
||||
if not xml:
|
||||
continue
|
||||
tree = etree.fromstring(xml)
|
||||
|
||||
if hasattr(etree, 'RelaxNG'):
|
||||
validator = etree.RelaxNG(etree=cls.get_rng(view.rng_type))
|
||||
if not validator.validate(tree):
|
||||
error_log = '\n'.join(map(str,
|
||||
validator.error_log.filter_from_errors()))
|
||||
raise XMLError(
|
||||
gettext('ir.msg_view_invalid_xml', name=view.rec_name),
|
||||
error_log)
|
||||
root_element = tree.getroottree().getroot()
|
||||
|
||||
# validate pyson attributes
|
||||
validates = {
|
||||
'states': fields.states_validate,
|
||||
}
|
||||
|
||||
def encode(element):
|
||||
for attr in ('states', 'domain', 'spell'):
|
||||
if not element.get(attr):
|
||||
continue
|
||||
try:
|
||||
value = PYSONDecoder().decode(element.get(attr))
|
||||
validates.get(attr, lambda a: True)(value)
|
||||
except Exception as e:
|
||||
error_log = '%s: <%s %s="%s"/>' % (
|
||||
e, element.get('id') or element.get('name'), attr,
|
||||
element.get(attr))
|
||||
raise XMLError(
|
||||
gettext(
|
||||
'ir.msg_view_invalid_xml', name=view.rec_name),
|
||||
error_log) from e
|
||||
for child in element:
|
||||
encode(child)
|
||||
encode(root_element)
|
||||
|
||||
def get_arch(self, name):
|
||||
value = None
|
||||
if self.name and self.module:
|
||||
path = os.path.join(self.module, 'view', self.name + '.xml')
|
||||
try:
|
||||
with file_open(path,
|
||||
subdir='modules', mode='r', encoding='utf-8') as fp:
|
||||
value = fp.read()
|
||||
except IOError:
|
||||
pass
|
||||
if not value:
|
||||
value = self.data
|
||||
return value
|
||||
|
||||
@classmethod
|
||||
def set_arch(cls, views, name, value):
|
||||
cls.write(views, {'data': value})
|
||||
|
||||
@classmethod
|
||||
def delete(cls, views):
|
||||
super(View, cls).delete(views)
|
||||
# Restart the cache
|
||||
cls._view_get_cache.clear()
|
||||
ModelView._fields_view_get_cache.clear()
|
||||
|
||||
@classmethod
|
||||
def create(cls, vlist):
|
||||
views = super(View, cls).create(vlist)
|
||||
# Restart the cache
|
||||
cls._view_get_cache.clear()
|
||||
ModelView._fields_view_get_cache.clear()
|
||||
return views
|
||||
|
||||
@classmethod
|
||||
def write(cls, views, values, *args):
|
||||
super(View, cls).write(views, values, *args)
|
||||
# Restart the cache
|
||||
cls._view_get_cache.clear()
|
||||
ModelView._fields_view_get_cache.clear()
|
||||
|
||||
@property
|
||||
def _module_index(self):
|
||||
from trytond.modules import create_graph, get_modules
|
||||
if self.__class__.__module_index is None:
|
||||
graph = create_graph(get_modules(with_test=Pool.test))
|
||||
modules = [m.name for m in graph]
|
||||
self.__class__.__module_index = {
|
||||
m: i for i, m in enumerate(reversed(modules))}
|
||||
return self.__class__.__module_index
|
||||
|
||||
def view_get(self, model=None):
|
||||
key = (self.id, model)
|
||||
result = self._view_get_cache.get(key)
|
||||
if result:
|
||||
return result
|
||||
if self.inherit:
|
||||
if self.inherit.model == model:
|
||||
return self.inherit.view_get(model=model)
|
||||
else:
|
||||
arch = self.inherit.view_get(self.inherit.model)['arch']
|
||||
else:
|
||||
arch = self.arch
|
||||
|
||||
views = self.__class__.search(['OR', [
|
||||
('inherit', '=', self.id),
|
||||
('model', '=', model),
|
||||
], [
|
||||
('id', '=', self.id),
|
||||
('inherit', '!=', None),
|
||||
],
|
||||
])
|
||||
views.sort(
|
||||
key=lambda v: self._module_index.get(v.module, -1), reverse=True)
|
||||
parser = etree.XMLParser(remove_comments=True, resolve_entities=False)
|
||||
# logger.info("ARCH:%s",arch)
|
||||
# logger.info("MODEL:%s",model)
|
||||
# logger.info("PARSER:%s",etree)
|
||||
tree = etree.fromstring(arch, parser=parser)
|
||||
decoder = PYSONDecoder({'context': Transaction().context})
|
||||
for view in views:
|
||||
if view.domain and not decoder.decode(view.domain):
|
||||
continue
|
||||
if not view.arch or not view.arch.strip():
|
||||
continue
|
||||
tree_inherit = etree.fromstring(view.arch, parser=parser)
|
||||
tree = self.inherit_apply(tree, tree_inherit)
|
||||
if model:
|
||||
root = tree.getroottree().getroot()
|
||||
self._translate(root, model, Transaction().language)
|
||||
arch = etree.tostring(tree, encoding='utf-8').decode('utf-8')
|
||||
result = {
|
||||
'type': self.rng_type,
|
||||
'view_id': self.id,
|
||||
'arch': arch,
|
||||
'field_childs': self.field_childs,
|
||||
}
|
||||
self._view_get_cache.set(key, result)
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def inherit_apply(cls, tree, inherit):
|
||||
root_inherit = inherit.getroottree().getroot()
|
||||
for element in root_inherit:
|
||||
expr = element.get('expr')
|
||||
targets = tree.xpath(expr)
|
||||
assert targets, "No elements found for expression %r" % expr
|
||||
for target in targets:
|
||||
position = element.get('position', 'inside')
|
||||
new_tree = getattr(cls, '_inherit_apply_%s' % position)(
|
||||
tree, element, target)
|
||||
if new_tree:
|
||||
tree = new_tree
|
||||
return tree
|
||||
|
||||
@classmethod
|
||||
def _inherit_apply_replace(cls, tree, element, target):
|
||||
parent = target.getparent()
|
||||
if parent is None:
|
||||
tree, = element
|
||||
return tree
|
||||
cls._inherit_apply_after(tree, element, target)
|
||||
parent.remove(target)
|
||||
|
||||
@classmethod
|
||||
def _inherit_apply_replace_attributes(cls, tree, element, target):
|
||||
child, = element
|
||||
for attr in child.attrib:
|
||||
target.set(attr, child.get(attr))
|
||||
|
||||
@classmethod
|
||||
def _inherit_apply_inside(cls, tree, element, target):
|
||||
target.extend(list(element))
|
||||
|
||||
@classmethod
|
||||
def _inherit_apply_after(cls, tree, element, target):
|
||||
parent = target.getparent()
|
||||
next_ = target.getnext()
|
||||
if next_ is not None:
|
||||
for child in element:
|
||||
index = parent.index(next_)
|
||||
parent.insert(index, child)
|
||||
else:
|
||||
parent.extend(list(element))
|
||||
|
||||
@classmethod
|
||||
def _inherit_apply_before(cls, tree, element, target):
|
||||
parent = target.getparent()
|
||||
for child in element:
|
||||
index = parent.index(target)
|
||||
parent.insert(index, child)
|
||||
|
||||
@classmethod
|
||||
def _translate(cls, element, model, language):
|
||||
pool = Pool()
|
||||
Translation = pool.get('ir.translation')
|
||||
for attr in ['string', 'sum', 'confirm', 'help']:
|
||||
if element.get(attr):
|
||||
translation = Translation.get_source(
|
||||
model, 'view', language, element.get(attr))
|
||||
if translation:
|
||||
element.set(attr, translation)
|
||||
for child in element:
|
||||
cls._translate(child, model, language)
|
||||
|
||||
|
||||
class ShowViewStart(ModelView):
|
||||
'Show view'
|
||||
__name__ = 'ir.ui.view.show.start'
|
||||
__no_slots__ = True
|
||||
|
||||
|
||||
class ShowView(Wizard):
|
||||
'Show view'
|
||||
__name__ = 'ir.ui.view.show'
|
||||
|
||||
class ShowStateView(StateView):
|
||||
|
||||
def __init__(self, model_name, buttons):
|
||||
StateView.__init__(self, model_name, None, buttons)
|
||||
|
||||
def get_view(self, wizard, state_name):
|
||||
pool = Pool()
|
||||
View = pool.get('ir.ui.view')
|
||||
view_id = Transaction().context.get('active_id')
|
||||
if not view_id:
|
||||
# Set type to please ModuleTestCase.test_wizards
|
||||
return {'type': 'form'}
|
||||
view = View(view_id)
|
||||
Model = pool.get(view.model)
|
||||
return Model.fields_view_get(view_id=view.id)
|
||||
|
||||
def get_defaults(self, wizard, state_name, fields):
|
||||
return {}
|
||||
|
||||
start = ShowStateView('ir.ui.view.show.start', [
|
||||
Button('Close', 'end', 'tryton-close', default=True),
|
||||
])
|
||||
|
||||
|
||||
class ViewTreeWidth(
|
||||
fields.fmany2one(
|
||||
'model_ref', 'model', 'ir.model,model', "Model",
|
||||
required=True, ondelete='CASCADE'),
|
||||
fields.fmany2one(
|
||||
'field_ref', 'field,model', 'ir.model.field,name,model', "Field",
|
||||
required=True, ondelete='CASCADE',
|
||||
domain=[
|
||||
('model', '=', Eval('model')),
|
||||
]),
|
||||
ModelSQL, ModelView):
|
||||
"View Tree Width"
|
||||
__name__ = 'ir.ui.view_tree_width'
|
||||
model = fields.Char('Model', required=True)
|
||||
field = fields.Char('Field', required=True)
|
||||
user = fields.Many2One('res.user', 'User', required=True,
|
||||
ondelete='CASCADE')
|
||||
width = fields.Integer('Width', required=True)
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(ViewTreeWidth, cls).__setup__()
|
||||
table = cls.__table__()
|
||||
cls.__rpc__.update({
|
||||
'set_width': RPC(readonly=False),
|
||||
})
|
||||
cls._sql_indexes.add(
|
||||
Index(
|
||||
table,
|
||||
(table.user, Index.Equality()),
|
||||
(table.model, Index.Equality()),
|
||||
(table.field, Index.Equality())))
|
||||
|
||||
def get_rec_name(self, name):
|
||||
return f'{self.field_ref.rec_name} @ {self.model_ref.rec_name}'
|
||||
|
||||
@classmethod
|
||||
def search_rec_name(cls, name, clause):
|
||||
operator = clause[1]
|
||||
if operator.startswith('!') or operator.startswith('not '):
|
||||
bool_op = 'AND'
|
||||
else:
|
||||
bool_op = 'OR'
|
||||
return [bool_op,
|
||||
('model_ref.rec_name', *clause[1:]),
|
||||
('field_ref.rec_name', *clause[1:]),
|
||||
]
|
||||
|
||||
@classmethod
|
||||
def delete(cls, records):
|
||||
ModelView._fields_view_get_cache.clear()
|
||||
super(ViewTreeWidth, cls).delete(records)
|
||||
|
||||
@classmethod
|
||||
def create(cls, vlist):
|
||||
res = super(ViewTreeWidth, cls).create(vlist)
|
||||
ModelView._fields_view_get_cache.clear()
|
||||
return res
|
||||
|
||||
@classmethod
|
||||
def write(cls, records, values, *args):
|
||||
super(ViewTreeWidth, cls).write(records, values, *args)
|
||||
ModelView._fields_view_get_cache.clear()
|
||||
|
||||
@classmethod
|
||||
def set_width(cls, model, fields):
|
||||
'''
|
||||
Set width for the current user on the model.
|
||||
fields is a dictionary with key: field name and value: width.
|
||||
'''
|
||||
records = cls.search([
|
||||
('user', '=', Transaction().user),
|
||||
('model', '=', model),
|
||||
('field', 'in', list(fields.keys())),
|
||||
])
|
||||
cls.delete(records)
|
||||
|
||||
to_create = []
|
||||
for field in list(fields.keys()):
|
||||
to_create.append({
|
||||
'model': model,
|
||||
'field': field,
|
||||
'user': Transaction().user,
|
||||
'width': fields[field],
|
||||
})
|
||||
if to_create:
|
||||
cls.create(to_create)
|
||||
|
||||
|
||||
class ViewTreeOptional(ModelSQL, ModelView):
|
||||
"View Tree Optional"
|
||||
__name__ = 'ir.ui.view_tree_optional'
|
||||
view_id = fields.Many2One(
|
||||
'ir.ui.view', "View ID", required=True, ondelete='CASCADE')
|
||||
user = fields.Many2One(
|
||||
'res.user', "User", required=True, ondelete='CASCADE')
|
||||
field = fields.Char("Field", required=True)
|
||||
value = fields.Boolean("Value")
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super().__setup__()
|
||||
cls.__rpc__.update({
|
||||
'set_optional': RPC(readonly=False),
|
||||
})
|
||||
table = cls.__table__()
|
||||
cls._sql_indexes.add(
|
||||
Index(
|
||||
table,
|
||||
(table.user, Index.Equality()),
|
||||
(table.view_id, Index.Equality())))
|
||||
|
||||
@classmethod
|
||||
def validate_fields(cls, records, fields_names):
|
||||
super().validate_fields(records, fields_names)
|
||||
cls.check_view_id(records, fields_names)
|
||||
|
||||
@classmethod
|
||||
def check_view_id(cls, records, fields_names=None):
|
||||
if fields_names and 'view_id' not in fields_names:
|
||||
return
|
||||
for record in records:
|
||||
if record.view_id and record.view_id.rng_type != 'tree':
|
||||
raise ViewError(gettext(
|
||||
'ir.msg_view_tree_optional_type',
|
||||
view=record.view_id.rec_name))
|
||||
|
||||
@classmethod
|
||||
def create(cls, vlist):
|
||||
records = super().create(vlist)
|
||||
ModelView._fields_view_get_cache.clear()
|
||||
return records
|
||||
|
||||
@classmethod
|
||||
def write(cls, *args):
|
||||
super().write(*args)
|
||||
ModelView._fields_view_get_cache.clear()
|
||||
|
||||
@classmethod
|
||||
def delete(cls, records):
|
||||
ModelView._fields_view_get_cache.clear()
|
||||
super().delete(records)
|
||||
|
||||
@classmethod
|
||||
def set_optional(cls, view_id, fields):
|
||||
"Store optional field that must be displayed"
|
||||
user = Transaction().user
|
||||
records = cls.search([
|
||||
('view_id', '=', view_id),
|
||||
('user', '=', user),
|
||||
])
|
||||
cls.delete(records)
|
||||
to_create = []
|
||||
for field, value in fields.items():
|
||||
to_create.append({
|
||||
'view_id': view_id,
|
||||
'user': user,
|
||||
'field': field,
|
||||
'value': bool(value),
|
||||
})
|
||||
if to_create:
|
||||
cls.create(to_create)
|
||||
|
||||
|
||||
class ViewTreeState(ModelSQL, ModelView):
|
||||
'View Tree State'
|
||||
__name__ = 'ir.ui.view_tree_state'
|
||||
_rec_name = 'model'
|
||||
model = fields.Char('Model', required=True)
|
||||
domain = fields.Char('Domain', required=True)
|
||||
user = fields.Many2One('res.user', 'User', required=True,
|
||||
ondelete='CASCADE')
|
||||
child_name = fields.Char('Child Name')
|
||||
nodes = fields.Text('Expanded Nodes')
|
||||
selected_nodes = fields.Text('Selected Nodes')
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(ViewTreeState, cls).__setup__()
|
||||
cls.__rpc__.update({
|
||||
'set': RPC(readonly=False, check_access=False),
|
||||
'get': RPC(check_access=False, cache=dict(days=1)),
|
||||
})
|
||||
|
||||
table = cls.__table__()
|
||||
cls._sql_indexes.add(
|
||||
Index(
|
||||
table,
|
||||
(table.user, Index.Equality()),
|
||||
(table.model, Index.Equality()),
|
||||
(table.child_name, Index.Equality()),
|
||||
(table.domain, Index.Equality())))
|
||||
|
||||
@staticmethod
|
||||
def default_nodes():
|
||||
return '[]'
|
||||
|
||||
@staticmethod
|
||||
def default_selected_nodes():
|
||||
return '[]'
|
||||
|
||||
@classmethod
|
||||
def set(cls, model, domain, child_name, nodes, selected_nodes):
|
||||
# Normalize the json domain
|
||||
logger.info("VIEWTREESTATE:%s",domain)
|
||||
logger.info("VIEWTREESTATE2:%s",child_name)
|
||||
logger.info("VIEWTREESTATE3:%s",nodes)
|
||||
logger.info("VIEWTREESTATE4:%s",cls.__table__())
|
||||
domain = json.dumps(json.loads(domain), separators=(',', ':'))
|
||||
current_user = Transaction().user
|
||||
records = cls.search([
|
||||
('user', '=', current_user),
|
||||
('model', '=', model),
|
||||
('domain', '=', domain),
|
||||
('child_name', '=', child_name),
|
||||
])
|
||||
cls.delete(records)
|
||||
cls.create([{
|
||||
'user': current_user,
|
||||
'model': model,
|
||||
'domain': domain,
|
||||
'child_name': child_name,
|
||||
'nodes': nodes,
|
||||
'selected_nodes': selected_nodes,
|
||||
}])
|
||||
|
||||
@classmethod
|
||||
def get(cls, model, domain, child_name):
|
||||
# Normalize the json domain
|
||||
domain = json.dumps(json.loads(domain), separators=(',', ':'))
|
||||
current_user = Transaction().user
|
||||
try:
|
||||
expanded_info, = cls.search([
|
||||
('user', '=', current_user),
|
||||
('model', '=', model),
|
||||
('domain', '=', domain),
|
||||
('child_name', '=', child_name),
|
||||
],
|
||||
limit=1)
|
||||
except ValueError:
|
||||
return (cls.default_nodes(), cls.default_selected_nodes())
|
||||
state = cls(expanded_info)
|
||||
return (state.nodes or cls.default_nodes(),
|
||||
state.selected_nodes or cls.default_selected_nodes())
|
||||
|
||||
|
||||
class ViewSearch(ModelSQL, ModelView):
|
||||
"View Search"
|
||||
__name__ = 'ir.ui.view_search'
|
||||
|
||||
name = fields.Char('Name', required=True)
|
||||
model = fields.Char('Model', required=True)
|
||||
domain = fields.Char('Domain', help="The PYSON domain.")
|
||||
user = fields.Many2One('res.user', 'User', ondelete='CASCADE')
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(ViewSearch, cls).__setup__()
|
||||
cls.__rpc__.update({
|
||||
'get': RPC(check_access=False),
|
||||
'set': RPC(check_access=False, readonly=False),
|
||||
'unset': RPC(check_access=False, readonly=False),
|
||||
})
|
||||
|
||||
@classmethod
|
||||
def __register__(cls, module):
|
||||
super().__register__(module)
|
||||
table_h = cls.__table_handler__(module)
|
||||
|
||||
# Migration from 5.6: remove user required
|
||||
table_h.not_null_action('user', 'remove')
|
||||
|
||||
@staticmethod
|
||||
def default_user():
|
||||
return Transaction().user
|
||||
|
||||
@classmethod
|
||||
def validate_fields(cls, searches, field_names):
|
||||
super().validate_fields(searches, field_names)
|
||||
cls.check_domain(searches, field_names)
|
||||
|
||||
@classmethod
|
||||
def check_domain(cls, searches, field_names):
|
||||
decoder = PYSONDecoder()
|
||||
if field_names and 'domain' not in field_names:
|
||||
return
|
||||
for search in searches:
|
||||
try:
|
||||
value = decoder.decode(search.domain)
|
||||
except Exception as exception:
|
||||
raise DomainError(
|
||||
gettext('ir.msg_view_search_invalid_domain',
|
||||
domain=search.domain,
|
||||
search=search.rec_name)) from exception
|
||||
if isinstance(value, PYSON):
|
||||
if not value.types() == set([list]):
|
||||
raise DomainError(
|
||||
gettext('ir.msg_view_search_invalid_domain',
|
||||
domain=search.domain,
|
||||
search=search.rec_name))
|
||||
elif not isinstance(value, list):
|
||||
raise DomainError(
|
||||
gettext('ir.msg_view_search_invalid_domain',
|
||||
domain=search.domain,
|
||||
search=search.rec_name))
|
||||
else:
|
||||
try:
|
||||
fields.domain_validate(value)
|
||||
except Exception as exception:
|
||||
raise DomainError(
|
||||
gettext('ir.msg_view_search_invalid_domain',
|
||||
domain=search.domain,
|
||||
search=search.rec_name)) from exception
|
||||
|
||||
@classmethod
|
||||
def get(cls):
|
||||
decoder = PYSONDecoder()
|
||||
user = Transaction().user
|
||||
searches = cls.search_read(['OR',
|
||||
('user', '=', user),
|
||||
('user', '=', None),
|
||||
],
|
||||
order=[('model', 'ASC'), ('name', 'ASC')],
|
||||
fields_names=['id', 'name', 'model', 'domain', '_delete'])
|
||||
result = {}
|
||||
for search in searches:
|
||||
result.setdefault(search['model'], []).append((
|
||||
search['id'],
|
||||
search['name'],
|
||||
decoder.decode(search['domain']),
|
||||
search['_delete']))
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def set(cls, name, model, domain):
|
||||
user = Transaction().user
|
||||
search, = cls.create([{
|
||||
'name': name,
|
||||
'model': model,
|
||||
'domain': domain,
|
||||
'user': user,
|
||||
}])
|
||||
return search.id
|
||||
|
||||
@classmethod
|
||||
def unset(cls, id):
|
||||
user = Transaction().user
|
||||
cls.delete(cls.search([
|
||||
('id', '=', id),
|
||||
('user', '=', user),
|
||||
]))
|
||||
191
ir/ui/view.xml
Executable file
@@ -0,0 +1,191 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
this repository contains the full copyright notices and license terms. -->
|
||||
<tryton>
|
||||
<data>
|
||||
|
||||
<record model="ir.action.wizard" id="act_view_show">
|
||||
<field name="name">Show View</field>
|
||||
<field name="wiz_name">ir.ui.view.show</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_view_form">
|
||||
<field name="model">ir.ui.view</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">ui_view_form</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="view_view_tree">
|
||||
<field name="model">ir.ui.view</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="priority" eval="10"/>
|
||||
<field name="name">ui_view_list</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="view_view_list_extension">
|
||||
<field name="model">ir.ui.view</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="priority" eval="20"/>
|
||||
<field name="name">ui_view_list_extension</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window" id="act_view_form">
|
||||
<field name="name">Views</field>
|
||||
<field name="type">ir.action.act_window</field>
|
||||
<field name="res_model">ir.ui.view</field>
|
||||
<field name="domain" eval="[('basis', '=', True)]" pyson="1"/>
|
||||
<field name="order" eval="[('model', None)]" pyson="1"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view"
|
||||
id="act_view_form_view1">
|
||||
<field name="sequence" eval="1"/>
|
||||
<field name="view" ref="view_view_tree"/>
|
||||
<field name="act_window" ref="act_view_form"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view"
|
||||
id="act_view_form_view2">
|
||||
<field name="sequence" eval="2"/>
|
||||
<field name="view" ref="view_view_form"/>
|
||||
<field name="act_window" ref="act_view_form"/>
|
||||
</record>
|
||||
<menuitem
|
||||
parent="menu_ui"
|
||||
action="act_view_form"
|
||||
sequence="10"
|
||||
id="menu_view"/>
|
||||
<record model="ir.model.button" id="view_show_button">
|
||||
<field name="model">ir.ui.view</field>
|
||||
<field name="name">show</field>
|
||||
<field name="string">Show</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_tree_width_view_form">
|
||||
<field name="model">ir.ui.view_tree_width</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">ui_view_tree_width_form</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="view_tree_width_view_tree">
|
||||
<field name="model">ir.ui.view_tree_width</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="name">ui_view_tree_width_list</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window" id="act_view_tree_width_form">
|
||||
<field name="name">View Tree Width</field>
|
||||
<field name="type">ir.action.act_window</field>
|
||||
<field name="res_model">ir.ui.view_tree_width</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view"
|
||||
id="act_view_tree_width_form_view1">
|
||||
<field name="sequence" eval="1"/>
|
||||
<field name="view" ref="view_tree_width_view_tree"/>
|
||||
<field name="act_window" ref="act_view_tree_width_form"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view"
|
||||
id="act_view_tree_width_form_view2">
|
||||
<field name="sequence" eval="2"/>
|
||||
<field name="view" ref="view_tree_width_view_form"/>
|
||||
<field name="act_window" ref="act_view_tree_width_form"/>
|
||||
</record>
|
||||
<menuitem
|
||||
parent="menu_ui"
|
||||
action="act_view_tree_width_form"
|
||||
sequence="50"
|
||||
id="menu_view_tree_width"/>
|
||||
|
||||
<record model="ir.ui.view" id="view_tree_optional_view_form">
|
||||
<field name="model">ir.ui.view_tree_optional</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">ui_view_tree_optional_form</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_tree_optional_view_tree">
|
||||
<field name="model">ir.ui.view_tree_optional</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="name">ui_view_tree_optional_list</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.action.act_window" id="act_view_tree_optional_form">
|
||||
<field name="name">View Tree Optional</field>
|
||||
<field name="res_model">ir.ui.view_tree_optional</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_view_tree_optional_form_view1">
|
||||
<field name="sequence" eval="10"/>
|
||||
<field name="view" ref="view_tree_optional_view_tree"/>
|
||||
<field name="act_window" ref="act_view_tree_optional_form"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view" id="act_view_tree_optional_form_view2">
|
||||
<field name="sequence" eval="20"/>
|
||||
<field name="view" ref="view_tree_optional_view_form"/>
|
||||
<field name="act_window" ref="act_view_tree_optional_form"/>
|
||||
</record>
|
||||
|
||||
<menuitem
|
||||
parent="menu_ui"
|
||||
action="act_view_tree_optional_form"
|
||||
sequence="50"
|
||||
id="menu_view_tree_optional"/>
|
||||
|
||||
<record model="ir.ui.view" id="view_tree_state_form">
|
||||
<field name="model">ir.ui.view_tree_state</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">ui_view_tree_state_form</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="view_tree_state_tree">
|
||||
<field name="model">ir.ui.view_tree_state</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="name">ui_view_tree_state_list</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window" id="act_view_tree_state">
|
||||
<field name="name">Tree State</field>
|
||||
<field name="type">ir.action.act_window</field>
|
||||
<field name="res_model">ir.ui.view_tree_state</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view"
|
||||
id="act_view_tree_state_tree">
|
||||
<field name="sequence" eval="10"/>
|
||||
<field name="view" ref="view_tree_state_tree"/>
|
||||
<field name="act_window" ref="act_view_tree_state"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view"
|
||||
id="act_view_tree_state_form">
|
||||
<field name="sequence" eval="20"/>
|
||||
<field name="view" ref="view_tree_state_form"/>
|
||||
<field name="act_window" ref="act_view_tree_state"/>
|
||||
</record>
|
||||
<menuitem
|
||||
parent="menu_ui"
|
||||
action="act_view_tree_state"
|
||||
sequence="50"
|
||||
id="menu_view_tree_state"/>
|
||||
|
||||
<record model="ir.ui.view" id="view_search_form">
|
||||
<field name="model">ir.ui.view_search</field>
|
||||
<field name="type">form</field>
|
||||
<field name="name">ui_view_search_form</field>
|
||||
</record>
|
||||
<record model="ir.ui.view" id="view_search_tree">
|
||||
<field name="model">ir.ui.view_search</field>
|
||||
<field name="type">tree</field>
|
||||
<field name="name">ui_view_search_list</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window" id="act_view_search">
|
||||
<field name="name">View Search</field>
|
||||
<field name="type">ir.action.act_window</field>
|
||||
<field name="res_model">ir.ui.view_search</field>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view"
|
||||
id="act_view_search_tree">
|
||||
<field name="sequence" eval="10"/>
|
||||
<field name="view" ref="view_search_tree"/>
|
||||
<field name="act_window" ref="act_view_search"/>
|
||||
</record>
|
||||
<record model="ir.action.act_window.view"
|
||||
id="act_view_search_form">
|
||||
<field name="sequence" eval="20"/>
|
||||
<field name="view" ref="view_search_form"/>
|
||||
<field name="act_window" ref="act_view_search"/>
|
||||
</record>
|
||||
<menuitem
|
||||
parent="menu_ui"
|
||||
action="act_view_search"
|
||||
sequence="50"
|
||||
id="menu_view_search"/>
|
||||
</data>
|
||||
</tryton>
|
||||