def parse(self, model, root_node, fields, container): attrs = Common.nodeAttributes(root_node) self.title = attrs.get('string', 'Unknown') onWriteFunction = '' axis = [] groups = [] axis_data = {} for node in root_node.childNodes: if node.localName == 'field': node_attrs = Common.nodeAttributes(node) if node_attrs.get('group', False): groups.append(str(node_attrs['name'])) else: axis.append(str(node_attrs['name'])) axis_data[str(node_attrs['name'])] = node_attrs # # TODO: parse root_node to fill in axis # chart = ChartGraphicsView(container) chart.setModel(self.parent.currentRecord()) chart.setType(attrs.get('type', 'pie')) chart.setAxis(axis) chart.setGroups(groups) chart.setFields(fields) chart.setAxisData(axis_data) if attrs.get('orientation', 'vertical') == 'vertical': chart.setOrientation(Qt.Vertical) else: chart.setOrientation(Qt.Horizontal) return chart, onWriteFunction
def _parseDiagram(self, model, view, rootNode): # The parsing part: mainNod = None for node in rootNode.childNodes: if node.nodeType != xml.dom.Node.ELEMENT_NODE: continue natrs = Common.nodeAttributes(node) itno = None if node.localName == 'linear': itno = KsmLinear(view.scene) try: dx, dy = _dxy2deltas(natrs.get('dxy', 'right')) itno.setSpacing(dx, dy) except: pass itno.setFreeMove(True) chnod = self._parseDiaNode(model, view, node) itno.setChildProj(chnod) #elif node.localName == 'main': else: print "Unknown node in diagram:", node.localName if itno: view.projections.append(itno) if itno and not natrs.get('name', False): if mainNod: raise Exception("Two unnamed nodes found in diagram") mainNod = itno return mainNod
def executeKeyword(keyword, data=None, context=None): if data is None: data = {} if context is None: context = {} actions = None if 'id' in data: try: id = data.get('id', False) actions = Rpc.session.execute('/object', 'execute', 'ir.values', 'get', 'action', keyword, [(data['model'], id)], False, Rpc.session.context) actions = [x[2] for x in actions] except Rpc.RpcException as e: return None if not actions: return None keyact = {} for action in actions: keyact[action['name']] = action res = Common.selection(_('Select your action'), keyact) if not res: return None (name, action) = res Api.instance.executeAction(action, data, context=context) return (name, action)
def create(self, viewId, parent, viewModel, rootNode, fields, filter=None): self.viewModel = viewModel self.filter = filter self.widgetList = [] # Create the view self.view = SvgView(parent) self.view.id = viewId self.view directory = os.path.abspath(os.path.dirname(__file__)) for node in rootNode.childNodes: if node.localName == 'field': attributes = Common.nodeAttributes(node) name = attributes['name'] type = attributes.get('widget', fields[name]['type']) fields[name].update(attributes) fields[name]['model'] = viewModel # Create the appropiate widget for the given field type widget = FieldWidgetFactory.create(type, None, self.view, fields[name]) if not widget: continue self.view.widgets[name] = widget self.view.fields = fields self.view.setSvg(os.path.join(directory, 'restaurant.svg')) return self.view
def storeValue(self): # As the HTML returned can be different than the one we set in # showValue() even if the text hasn't been modified by the user # we need to track modifications using QTextDocument property if self.uiText.document().isModified(): html = Common.simplifyHtml( self.uiText.document().toHtml() ) self.record.setValue(self.name, html or False )
def openPdfManual(self): try: pdf = Rpc.session.call('/object', 'execute', 'ir.documentation.paragraph', 'export_to_pdf', Rpc.session.context) except: return False if not pdf: return False pdf = base64.decodestring(pdf) fd, fileName = tempfile.mkstemp('.pdf') os.write(fd, pdf) os.close(fd) Common.openFile(fileName) return True
def showAboutDialog(self): dialog = QDialog(self) loadUi(Common.uiPath('about.ui'), dialog) from Koo.Common import Version dialog.uiOpenErp.setHtml( str(dialog.uiOpenErp.toHtml()) % Version.Version) dialog.exec_()
def addWidget(self, widget, attributes=None, labelText=None): if attributes is None: attributes = {} colspan = int(attributes.get('colspan', 1)) helpText = attributes.get('help', False) if Settings.value('koo.developer_mode', False) and isinstance(widget, AbstractFieldWidget): helpText = (helpText or '') + \ _('<p><i>Field name: %s</i></p>') % widget.name helpAttributes = attributes.copy() helpAttributes.update(self.fields.get(widget.name, {})) helpAttributes = ['<b>%s</b>: %s<br/>' % (x, helpAttributes[x]) for x in sorted(helpAttributes.keys())] helpAttributes = '\n'.join(helpAttributes) helpText += _('<p><i>Attributes:<br/>%s</i></p>') % helpAttributes attributes['help'] = helpText stylesheet = attributes.get('stylesheet', False) # Get colspan if colspan > self.maxColumns: colspan = self.maxColumns a = labelText and 1 or 0 colspan -= a colspan = max(colspan, 1) if colspan + self.column + a > self.maxColumns: self.newRow() # Get rowspan rowspan = int(attributes.get('rowspan', 1)) if labelText: label = QLabel(self) label.setText(str(Common.normalizeLabel(labelText))) label.setAlignment(Qt.AlignRight | Qt.AlignVCenter) label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) if helpText: color = 'blue' helpText = '<b>%s</b><br/>%s' % (labelText, helpText) label.setToolTip(helpText) label.setWhatsThis(helpText) widget.setWhatsThis(helpText) else: color = 'black' label.setText(str( '<small><a style="color: %s" href="help">?</a></small> %s' % (color, labelText))) label.linkActivated['QString'].connect(widget.showHelp) self.layout.addWidget(label, self.row, self.column) self.column = self.column + 1 self.layout.addWidget(widget, self.row, self.column, rowspan, colspan) if stylesheet: widget.setStyleSheet(stylesheet) self.column += colspan
def translate(self): if not self.record.id: QMessageBox.information( self, _('Translation dialog'), _('You must save the resource before adding translations')) return html = Common.simplifyHtml( self.uiText.document().toHtml() ) dialog = TranslationDialog( self.record.id, self.record.group.resource, self.attrs['name'], html, TranslationDialog.RichEdit, self ) if dialog.exec_() == QDialog.Accepted: self.record.setValue(self.name, unicode( dialog.result ) or False )
def open(self): if not self.record.value(self.name): return # Under windows platforms we need to create the temporary # file with an appropiate extension, otherwise the system # won't be able to know how to open it. The only way we have # to know what kind of file it is, is if the filename property # was set, and pick up the extension from that field. extension = '' if self.fileName() and '.' in self.fileName(): extension = '.%s' % self.fileName().rpartition('.')[2] else: extension = '' fileName = tempfile.mktemp(extension) fp = file(fileName, 'wb+') fp.write(self.record.value(self.name)) fp.close() Common.openFile(fileName)
def openApplication(self): if not self.getImage(): return extension = '' # Under windows platforms we need to create the temporary # file with an appropiate extension, otherwise the system # won't be able to know how to open it. So we let Qt guess # what image format it is and use that as an extension. byte = QByteArray(str(self.getImage())) buf = QBuffer(byte) buf.open(QBuffer.ReadOnly) reader = QImageReader(buf) if reader.canRead(): extension = '.%s' % str(reader.format()) fileName = tempfile.mktemp(extension) fp = file(fileName, 'wb') fp.write(self.getImage()) fp.close() Common.openFile(fileName)
def inheritView(self): view_id = self.attrs.get('x-view') if not view_id: return view_id = re.findall('\d+', view_id) if not view_id: return view_id = int(view_id[0]) view = Rpc.RpcProxy('ir.ui.view') records = view.read([view_id], ['name', 'model', 'xml_id']) record = records[0] id = record['xml_id'].split('.')[-1] arch = """ <openerp> <data> <record model="ir.ui.view" id="%(id)s"> <field name="name">%(name)s</field> <field name="model">%(model)s</field> <field name="type">form</field> <field name="inherit_id" ref="%(xml_id)s"/> <field name="arch" type="xml"> <field name="%(field)s" position="after"> <field name=""/> </field> </field> </record> </data> </openerp>""" % { 'id': id, 'name': record['name'], 'model': record['model'], 'xml_id': record['xml_id'], 'field': self.attrs.get('name', ''), } fd, fileName = tempfile.mkstemp(suffix='.txt') os.write(fd, arch) os.close(fd) Common.openFile(fileName)
def __init__(self, arch, fields, state, name, datas, parent=None): QDialog.__init__(self, parent) self.setModal(True) buttons = [] self.datas = datas self.buttonsLayout = QHBoxLayout() self.buttonsLayout.addStretch() for x in state: but = QPushButton(Common.normalizeLabel(x[1])) # We store the value to return into objectName property but.setObjectName(x[0]) # The third element is the gtk-icon if len(x) >= 3: but.setIcon(Icons.kdeIcon(x[2])) # The forth element is True if the button is the default one if len(x) >= 4 and x[3]: but.setDefault(True) self.buttonsLayout.addWidget(but) but.clicked.connect(self.slotPush) val = {} for f in fields: if 'value' in fields[f]: val[f] = fields[f]['value'] self.group = RecordGroup('wizard.' + name) # Do not allow record loading as most probably 'wizard.'+name model # won't exist in the server self.group.setDomainForEmptyGroup() self.screen = Screen(self) self.screen.setRecordGroup(self.group) self.screen.new(default=False) # We don't want the toolbar to be shown at the wizard self.screen.setToolbarVisible(False) self.screen.addView(arch, fields, display=True) # Set default values self.screen.currentRecord().set(val) # Set already stored values self.screen.currentRecord().set(self.datas) self.screen.display() # Set minimum and maximum dialog size size = self.screen.sizeHint() self.setMinimumSize(size.width() + 100, min(600, size.height() + 25)) size = QApplication.desktop().availableGeometry(self).size() size -= QSize(50, 50) self.setMaximumSize(size) self.layout = QVBoxLayout(self) self.layout.addWidget(self.screen) self.layout.addLayout(self.buttonsLayout) self.setWindowTitle(self.screen.currentView().title)
def __init__(self, parent, view, attributes): AbstractFieldWidget.__init__(self, parent, view, attributes) self.button = QPushButton(self) layout = QHBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self.button) self.button.setText( Common.normalizeLabel(attributes.get('string', 'unknown'))) if 'icon' in attributes: self.button.setIcon(Icons.kdeIcon(attributes['icon'])) self.connect(self.button, SIGNAL('clicked()'), self.click)
def __init__(self, action, datas, state='init', parent=None, context=None): QObject.__init__(self, parent) if context is None: context = {} if not 'form' in datas: datas['form'] = {} self.action = action self.datas = datas self.state = state self.context = context self.wizardId = Rpc.session.execute('/wizard', 'create', self.action) self.finished = False self.progress = Common.ProgressDialog(QApplication.activeWindow()) self.thread = None
def batchButton(self): viewTypes = self.viewTypes viewIds = self.viewIds group = RecordGroup(self.model, context=self.context) group.setDomainForEmptyGroup() group.load(self.screen.selectedIds()) screen = Screen(self) screen.setRecordGroup(self.group) screen.setEmbedded(True) if 'form' in viewTypes: queue = ViewQueue() queue.setup(viewTypes, viewIds) type = '' while type != 'form': ident, type = next(queue) screen.setupViews(['form'], [ident]) else: screen.setupViews(['form'], [False]) from Koo.Fields.Button import ButtonFieldWidget from Koo.Common import Common buttons = {} for key, widget in screen.currentView().widgets.items(): if isinstance(widget, ButtonFieldWidget): buttons[str(widget.button.text())] = widget.name selectionDialog = Common.SelectionDialog( _('Choose action to apply to selected records'), buttons, self) if selectionDialog.exec_() == QDialog.Rejected: return buttonString = selectionDialog.result[0] buttonName = selectionDialog.result[1] if QMessageBox.question( self, _("Batch Update"), _("Do you really want to push button '%s' of all selected records?") % buttonString, QMessageBox.Yes|QMessageBox.No ) == 1: return for ident in self.screen.selectedIds(): screen.display(ident) screen.currentView().widgets[buttonName].executeButton(screen, ident) self.reload()
def _parseDiaNode(self, model, view, dNode): # The parsing part: for node in dNode.childNodes: itno = None if node.nodeType != ELEMENT_NODE: continue natrs = Common.nodeAttributes(node) if node.localName == 'lincols': itno = KsmColumns(view.scene) # FIXME try: dx, dy = _dxy2deltas(natrs.get('dxy', 'right')) itno.setSpacing(dx, dy) except: pass #itno.setDrawBox(True) pbox = KsmBox(view.scene) pbox.setDrawBox(False) view.projections.append(pbox) itno.setChildProj(pbox) for chn in node.childNodes: if chn.nodeType != ELEMENT_NODE: continue if chn.localName == 'field': chnat = Common.nodeAttributes(chn) self.header.append({'name': chnat['name']}) elif node.localName == 'box': itno = KsmBox(view.scene) else: print "Unknown node in projection:", node.localName if itno: # TODO view.projections.append(itno) return itno return None
def create(parent, definition, model): if not definition: # If definition is not set we initialize it appropiately # to be able to add the 'Print Screen' action. definition = {'print': [], 'action': [], 'relate': []} # We always add the 'Print Screen' action. definition['print'].append({ 'name': 'Print Screen', 'string': _('Print Screen'), 'report_name': 'printscreen.list', 'type': 'ir.actions.report.xml' }) actions = [] auto_shortcuts = Settings.value('koo.auto_shortcuts', False, bool) for icontype in ('print', 'action', 'relate'): for tool in definition[icontype]: action = Action(parent) action.setIcon(QIcon(":/images/%s.png" % icontype)) action.setText(Common.normalizeLabel(tool['string'])) action.setType(icontype) action.setData(tool) action.setModel(model) number = len(actions) shortcut = 'Ctrl+' if auto_shortcuts and number > 9: shortcut += 'Shift+' number -= 10 if auto_shortcuts and number < 10: shortcut += str(number) action.setShortcut(QKeySequence(shortcut)) action.setToolTip(action.text() + ' (%s)' % shortcut) actions.append(action) plugs = Plugins.list(model) for p in sorted(plugs.keys(), key=lambda x: plugs[x].get('string', '')): action = Action(parent) action.setIcon(QIcon(":/images/exec.png")) action.setText(unicode(plugs[p]['string'])) action.setData(p) action.setType('plugin') action.setModel(model) actions.append(action) return actions
def headerData(self, section, orientation, role): if orientation == Qt.Vertical: return QVariant() if role == Qt.DisplayRole: field = self.fields.get(self.field(section)) if not field: field = self.buttons.get(self.field(section)) return QVariant(Common.normalizeLabel(str(field['string']))) elif role == Qt.FontRole and not self._readOnly: fieldName = self.field(section) if self.group.fieldExists( fieldName) and self.group.isFieldRequired(fieldName): font = QFont() font.setBold(True) return QVariant(font) return QVariant()
def _parse_fields(self, node, fields): if node.nodeType == node.ELEMENT_NODE: if node.localName == 'field': attrs = Common.nodeAttributes(node) if attrs.get('widget', False): if attrs['widget'] == 'one2many_list': attrs['widget'] = 'one2many' attrs['type'] = attrs['widget'] try: fields[attrs['name']].update(attrs) except: print("-" * 30, "\n malformed tag for :", attrs) print("-" * 30) raise for node2 in node.childNodes: self._parse_fields(node2, fields)
def create(parent, definition, model): """ Creates a list of Action objects given a parent, model and definition. The 'definition' parameter is the 'toolbar' parameter returned by server function fields_view_get. :param parent: :param definition: :param model: :return: """ if not definition: # If definition is not set we initialize it appropiately # to be able to add the 'Print Screen' action. definition = {'print': [], 'action': [], 'relate': []} # Save action definition['action'].append({ 'name': 'save', 'string': _('Save'), 'action': parent.parentWidget().save, }) # Cancel action definition['action'].append({ 'name': 'cancel', 'string': _('Cancel'), 'action': parent.parentWidget().cancel, }) actions = [] for tool in definition['action']: action = Action(parent) if tool['name'] in ("save", "cancel"): action.setIcon(QIcon(":/images/{}.png".format(tool['name']))) else: action.setIcon(QIcon(":/images/{}.png".format('action'))) action.setText(Common.normalizeLabel(tool['string'])) action.setType('action') action.setData(tool) action.setModel(model) if 'action' in tool: action.triggered.connect(tool['action']) actions.append(action) return actions
def create(self, viewId, parent, viewModel, node, fields): self.viewModel = viewModel self.parent = parent attrs = Common.nodeAttributes(node) # Create the view self.view = ChartView(parent) self.view.id = viewId self.view.title = attrs.get('string', _('Unknown')) self.view.model = self.parent.currentRecord() widget, onWriteFunction = self.parse(self.parent.currentRecord(), node, fields, self.view) self.view.setWidget(widget) self.view.setOnWriteFunction(onWriteFunction) return self.view
def restoreState(self, value): if not value: return raw = eval(str(value)) cookieList = [] for cookie in raw: name = QByteArray.fromBase64(cookie[0]) value = QByteArray.fromBase64(cookie[1]) networkCookie = QNetworkCookie(name, value) networkCookie.setPath(str(cookie[2], 'utf-8')) networkCookie.setDomain(str(cookie[3], 'utf-8')) networkCookie.setExpirationDate( QDateTime.fromString(str(cookie[4], 'utf-8'))) if Common.isQtVersion45(): networkCookie.setHttpOnly(eval(cookie[5])) networkCookie.setSecure(eval(cookie[6])) cookieList.append(networkCookie) self.cookieJar.setAllCookies(cookieList) self.uiWeb.page().networkAccessManager().setCookieJar(self.cookieJar)
def headerData(self, section, orientation, role): if orientation == Qt.Vertical: return QVariant() if role == Qt.DisplayRole: field = self.fields.get(self.field(section), None) if not field: field = self.buttons.get(self.field(section)) if not field: self._log.warning("Could not get field %s: %s for %s header display role" % \ (section, self.field(section) or 'in %d fields' % len(self.visibleFields), self.group.resource)) return QVariant() return QVariant(Common.normalizeLabel(unicode(field['string']))) elif role == Qt.FontRole and not self._readOnly: fieldName = self.field(section) if self.group.fieldExists( fieldName) and self.group.isFieldRequired(fieldName): font = QFont() font.setBold(True) return QVariant(font) return QVariant()
def setup(self): fields = Rpc.session.execute('/object', 'execute', self.model, 'fields_view_get', False, 'form', Rpc.session.context) fields = fields['fields'] if self.availableFields: for field in list(fields.keys()): if not field in self.availableFields: del fields[field] oneToManyFields = [(fields[field]['string'], field) for field in fields if fields[field]['type'] == 'many2one'] oneToManyFields = dict(oneToManyFields) selectionDialog = Common.SelectionDialog( _('Choose field to insert in batch action'), oneToManyFields, self) if selectionDialog.exec_() == QDialog.Rejected: return False fieldString = selectionDialog.result[0] fieldName = selectionDialog.result[1] self.newField = fieldName fieldModel = fields[fieldName]['relation'] fields = { 'many2many': { 'string': fieldString, 'name': 'many2many', 'type': 'many2many', 'relation': fieldModel, } } arch = '' arch += '<?xml version="1.0"?>' arch += '<form string="%s">\n' % _('Batch Insert') arch += '<label string="%s" colspan="4"/>' % fieldString arch += '<field name="many2many" colspan="4" nolabel="1"/>' arch += '</form>' group = RecordGroup(fieldModel, fields) self.screen.setRecordGroup(group) self.screen.new(default=False) self.screen.addView(arch, fields, display=True) return True
def executeKeyword(keyword, data=None, context=None): """ Executes the given keyword action (it could be a report, wizard, etc). :param keyword: :param data: :param context: :return: Name, action :rtype: tuple """ if data is None: data = {} if context is None: context = {} actions = None if 'id' in data: try: ident = data.get('id', False) actions = Rpc.session.execute('/object', 'execute', 'ir.values', 'get', 'action', keyword, [(data['model'], ident)], False, Rpc.session.context) actions = [x[2] for x in actions] except Rpc.RpcException: return None if not actions: return None keyact = {} for action in actions: keyact[action['name']] = action res = Common.selection(_('Select your action'), keyact) if not res: return None (name, action) = res Api.instance.executeAction(action, data, context=context) return name, action
def saveState(self): cookieList = self.cookieJar.allCookies() raw = [] for cookie in cookieList: # We don't want to store session cookies if cookie.isSessionCookie(): continue # Store cookies in a list as a dict would occupy # more space and we want to minimize network bandwidth if Common.isQtVersion45(): isHttpOnly = str(cookie.isHttpOnly()) else: isHttpOnly = True raw.append([ str(cookie.name().toBase64()), str(cookie.value().toBase64()), str(cookie.path()).encode('utf-8'), str(cookie.domain()).encode('utf-8'), str(cookie.expirationDate().toString()).encode('utf-8'), str(isHttpOnly), str(cookie.isSecure()), ]) return QByteArray(str(raw))
from PyQt5.QtGui import * from Koo.Common.Ui import * from Koo.Common import Common from Koo.Common import Api from Koo.Common import Shortcuts from Koo.Dialogs.SearchDialog import SearchDialog from Koo.Fields.AbstractFieldWidget import * from Koo.Screen.ScreenDialog import ScreenDialog from Koo import Rpc from Koo.Rpc import RpcProxy (ReferenceFieldWidgetUi, ReferenceFieldWidgetBase) = loadUiType( Common.uiPath('reference.ui')) # This widget requires some ugly hacks. Mainly clearing the text fields once it's been # modified and searched afterwards. This is due to the fact that the 'name' the server # returns, if searched, might not be found again :( class ReferenceFieldWidget(AbstractFieldWidget, ReferenceFieldWidgetUi): def __init__(self, parent, model, attrs={}): AbstractFieldWidget.__init__(self, parent, model, attrs) ReferenceFieldWidgetUi.__init__(self) self.setupUi(self) self.pushNew.clicked.connect(self.new) self.pushOpen.clicked.connect(self.open) self.pushClear.clicked.connect(self.clear)
def open(fileName): Common.openFile(fileName)
import gettext from Koo.Common import Common from Koo.Common.Settings import * from Koo import Rpc from Koo.Screen import Screen from Koo.Screen.ScreenDialog import ScreenDialog from Koo.Model.Group import RecordGroup from PyQt4.QtGui import * from PyQt4.QtCore import * from Common.Ui import * (SearchDialogUi, SearchDialogBase) = loadUiType(Common.uiPath('win_search.ui')) class SearchDialog(QDialog, SearchDialogUi): def __init__(self, model, sel_multi=True, ids=None, context=None, domain=None, parent=None): QDialog.__init__(self, parent) SearchDialogUi.__init__(self) self.setupUi(self) if ids is None: