UserFields class via python dictionary api

Shared Libraries
Forum rules
For sharing working examples of macros / scripts. These can be in any script language supported by OpenOffice.org [Basic, Python, Netbean] or as source code files in Java or C# even - but requires the actual source code listing. This section is not for asking questions about writing your own macros.
Post Reply
Induane
Posts: 28
Joined: Fri Mar 28, 2014 4:49 am

UserFields class via python dictionary api

Post by Induane »

Getting, setting, and editing metadata can be a troublesome prospect at times - it takes a bit to setup, verify, etc... I've written a simple class that exposes the userfields using the same api as a python dictionary. This makes it easy to setup, one merely needs to create an instance of this class using the document model from the uno api.

Code: Select all

'''
User Fields
-----------
'''
# Standard
import logging
import collections

LOG = logging.getLogger(__name__)
TEXTFIELD_MASTERS = 'getTextFieldMasters'
FIELDMASTER_USER = 'com.sun.star.text.fieldmaster.User'
FIELDMASTER_TEMPLATE = 'com.sun.star.text.fieldmaster.User.%s'


class UserFields(collections.MutableMapping):
    """
    Treat user field values sets as a key, value mapping which allows them to
    be exposed with the same api as a traditional python dictionary
    """

    def __init__(self, model):
        """h
        Verify the provided model is a document model object and set the base
        model attribute for this class.

        :type model: object
        :param model: Document model from uno api
        :raises: TypeError
        """
        if not hasattr(model, TEXTFIELD_MASTERS):
            raise TypeError('Invalid document model object.')
        self._model = model

    def __dict__(self):
        """Return a representation of user fields as a true dictionary"""
        return self._get_all()

    def keys(self):
        """Return a list of keys"""
        return self._get_all().keys()

    def values(self):
        """Return a list of all values"""
        return self._get_all().values()

    @property
    def model(self):
        """
        Return the model object that this instance wraps

        :type model: object
        :param model: OpenOffice/LibreOffice model object
        """
        return self._model

    def _create_metadata(self, name, value, overwrite=True):
        """
        Create new metadata in document. If the metadata field already exists
        in the document, a warning will be logged and the value of the existing
        field will be updated unless overwrite is set to False.

        :type name: str
        :param name: metadata field name
        :type value: str
        :param value: metadata field value
        :type overwrite: bool
        :param overwrite: Flag to overwrite existing value if field exists
        """
        field_obj = self.model.getTextFieldMasters()
        if not field_obj.hasByName(FIELDMASTER_TEMPLATE % name):
            new_field = self.model.createInstance(FIELDMASTER_USER)
            new_field.Name = name
            new_field.Content = value
            LOG.info('Created new user field "%s: %s"' % (name, value))
        else:
            if overwrite:
                LOG.warning('A field with the name %s already exists' % name)
                self._update_metadata(name, value)
            else:
                raise Exception('Metadata key %s already exists.' % name)

    def _update_metadata(self, name, value, autocreate=True):
        """
        Update metadata in document.

        :type name: str
        :param name: metadata field name
        :type value: str
        :param value: metadata field value
        :type autocreate: bool
        :param autocreate: Automatically create non-existant fields flag
        :raises: KeyError
        """
        field_obj = self.model.getTextFieldMasters()
        if not field_obj.hasByName(FIELDMASTER_TEMPLATE % name):
            if autocreate:
                LOG.debug("Creating new field %s: %s" % (name, value))
                self._create_metadata(name, value)
            else:
                raise KeyError('Metadata key %s does not exist.' % name)
        else:
            field = field_obj.getByName(FIELDMASTER_TEMPLATE % name)
            field.Content = value
            LOG.info("Updated metadata field %s to %s" % (name, value))

    def _delete_metadata(self, name):
        """
        Remove metadata in document

        :type name: str
        :param name: field name of metadata to remove from document
        """
        field_obj = self.model.getTextFieldMasters()
        if field_obj.hasByName(FIELDMASTER_TEMPLATE % name):
            field = field_obj.getByName(FIELDMASTER_TEMPLATE % name)
            field.dispose()

    def _get_metadata(self, name, **kwargs):
        """
        Retrieve metadata in document

        :type name: str
        :param name: field name of metadata to retrive value for
        """
        default_value = kwargs.get('default_value', '')
        raise_error = kwargs.get('raise_error', False)
        field_obj = self.model.getTextFieldMasters()
        fieldname = FIELDMASTER_TEMPLATE % name

        if field_obj.hasByName(fieldname):
            field = field_obj.getByName(fieldname)
            return field.Content
        else:
            if raise_error:
                raise KeyError('Metadata key %s does not exist.' % name)
            else:
                LOG.debug('Fieldname "%s" does not exist.' % name)
                return default_value

    def field_exists(self, name):
        """
        Check whether that a metadata field exists in a document

        :type name: str
        :param name: field name of metadata to check existance of
        :returns: True if field exists, otherwise False
        :rtype: bool
        """
        field_obj = self.model.getTextFieldMasters()
        return field_obj.hasByName(FIELDMASTER_TEMPLATE % name)

    def _get_all(self):
        """
        Retrieve all metadata from a document

        :returns: dictionary of user fields and values
        :rtype: dict
        """
        meta_dict = {}
        field_obj = self.model.getTextFieldMasters()
        field_names = field_obj.getElementNames()
        for field_name in field_names:
            if FIELDMASTER_USER in field_name:
                field = field_obj.getByName(field_name)
                meta_dict[field.Name] = field.Content
        return meta_dict

    def __getitem__(self, key):
        try:
            return self._get_metadata(key, raise_error=True)
        except KeyError:
            raise KeyError(key)

    def __setitem__(self, key, value):
        self._update_metadata(key, value, autocreate=True)

    def __delitem__(self, key):
        self._delete_metadata(key)

    def __iter__(self):
        return iter(self.__dict__())

    def __len__(self):
        return len(self.keys())

    def __repr__(self):
        return self._get_all()

    def __str__(self):
        return "<UserFields instance: %s>" % ", ".join(self.keys())
OpenOffice 3.1 on Windows 7 / LibreOffice 3.6 on Ubuntu 13.10 / LibreOffice 4.1 on Ubuntu 13.10
Post Reply