buildframework/helium/external/python/lib/common/docutils-0.5-py2.5.egg/docutils/parsers/rst/directives/images.py
author wbernard
Wed, 23 Dec 2009 19:29:07 +0200
changeset 179 d8ac696cc51f
permissions -rw-r--r--
helium_7.0-r14027
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
179
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
     1
# $Id: images.py 4667 2006-07-12 21:40:56Z wiemann $
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
     2
# Author: David Goodger <goodger@python.org>
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
     3
# Copyright: This module has been placed in the public domain.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
     4
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
     5
"""
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
     6
Directives for figures and simple images.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
     7
"""
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
     8
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
     9
__docformat__ = 'reStructuredText'
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    10
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    11
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    12
import sys
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    13
from docutils import nodes, utils
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    14
from docutils.parsers.rst import Directive
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    15
from docutils.parsers.rst import directives, states
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    16
from docutils.nodes import fully_normalize_name, whitespace_normalize_name
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    17
from docutils.parsers.rst.roles import set_classes
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    18
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    19
try:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    20
    import Image as PIL                        # PIL
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    21
except ImportError:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    22
    PIL = None
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    23
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    24
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    25
class Image(Directive):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    26
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    27
    align_h_values = ('left', 'center', 'right')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    28
    align_v_values = ('top', 'middle', 'bottom')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    29
    align_values = align_v_values + align_h_values
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    30
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    31
    def align(argument):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    32
        # This is not callable as self.align.  We cannot make it a
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    33
        # staticmethod because we're saving an unbound method in
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    34
        # option_spec below.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    35
        return directives.choice(argument, Image.align_values)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    36
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    37
    required_arguments = 1
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    38
    optional_arguments = 0
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    39
    final_argument_whitespace = True
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    40
    option_spec = {'alt': directives.unchanged,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    41
                   'height': directives.length_or_unitless,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    42
                   'width': directives.length_or_percentage_or_unitless,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    43
                   'scale': directives.nonnegative_int,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    44
                   'align': align,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    45
                   'target': directives.unchanged_required,
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    46
                   'class': directives.class_option}
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    47
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    48
    def run(self):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    49
        if self.options.has_key('align'):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    50
            if isinstance(self.state, states.SubstitutionDef):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    51
                # Check for align_v_values.
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    52
                if self.options['align'] not in self.align_v_values:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    53
                    raise self.error(
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    54
                        'Error in "%s" directive: "%s" is not a valid value '
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    55
                        'for the "align" option within a substitution '
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    56
                        'definition.  Valid values for "align" are: "%s".'
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    57
                        % (self.name, self.options['align'],
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    58
                           '", "'.join(self.align_v_values)))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    59
            elif self.options['align'] not in self.align_h_values:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    60
                raise self.error(
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    61
                    'Error in "%s" directive: "%s" is not a valid value for '
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    62
                    'the "align" option.  Valid values for "align" are: "%s".'
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    63
                    % (self.name, self.options['align'],
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    64
                       '", "'.join(self.align_h_values)))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    65
        messages = []
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    66
        reference = directives.uri(self.arguments[0])
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    67
        self.options['uri'] = reference
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    68
        reference_node = None
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    69
        if self.options.has_key('target'):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    70
            block = states.escape2null(
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    71
                self.options['target']).splitlines()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    72
            block = [line for line in block]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    73
            target_type, data = self.state.parse_target(
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    74
                block, self.block_text, self.lineno)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    75
            if target_type == 'refuri':
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    76
                reference_node = nodes.reference(refuri=data)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    77
            elif target_type == 'refname':
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    78
                reference_node = nodes.reference(
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    79
                    refname=fully_normalize_name(data),
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    80
                    name=whitespace_normalize_name(data))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    81
                reference_node.indirect_reference_name = data
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    82
                self.state.document.note_refname(reference_node)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    83
            else:                           # malformed target
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    84
                messages.append(data)       # data is a system message
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    85
            del self.options['target']
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    86
        set_classes(self.options)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    87
        image_node = nodes.image(self.block_text, **self.options)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    88
        if reference_node:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    89
            reference_node += image_node
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    90
            return messages + [reference_node]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    91
        else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    92
            return messages + [image_node]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    93
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    94
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    95
class Figure(Image):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    96
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    97
    def align(argument):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    98
        return directives.choice(argument, Figure.align_h_values)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
    99
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   100
    def figwidth_value(argument):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   101
        if argument.lower() == 'image':
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   102
            return 'image'
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   103
        else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   104
            return directives.nonnegative_int(argument)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   105
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   106
    option_spec = Image.option_spec.copy()
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   107
    option_spec['figwidth'] = figwidth_value
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   108
    option_spec['figclass'] = directives.class_option
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   109
    option_spec['align'] = align
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   110
    has_content = True
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   111
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   112
    def run(self):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   113
        figwidth = self.options.get('figwidth')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   114
        if figwidth:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   115
            del self.options['figwidth']
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   116
        figclasses = self.options.get('figclass')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   117
        if figclasses:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   118
            del self.options['figclass']
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   119
        align = self.options.get('align')
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   120
        if align:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   121
            del self.options['align']
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   122
        (image_node,) = Image.run(self)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   123
        if isinstance(image_node, nodes.system_message):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   124
            return [image_node]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   125
        figure_node = nodes.figure('', image_node)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   126
        if figwidth == 'image':
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   127
            if PIL and self.state.document.settings.file_insertion_enabled:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   128
                # PIL doesn't like Unicode paths:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   129
                try:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   130
                    i = PIL.open(str(image_node['uri']))
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   131
                except (IOError, UnicodeError):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   132
                    pass
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   133
                else:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   134
                    self.state.document.settings.record_dependencies.add(
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   135
                        image_node['uri'])
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   136
                    figure_node['width'] = i.size[0]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   137
        elif figwidth is not None:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   138
            figure_node['width'] = figwidth
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   139
        if figclasses:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   140
            figure_node['classes'] += figclasses
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   141
        if align:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   142
            figure_node['align'] = align
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   143
        if self.content:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   144
            node = nodes.Element()          # anonymous container for parsing
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   145
            self.state.nested_parse(self.content, self.content_offset, node)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   146
            first_node = node[0]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   147
            if isinstance(first_node, nodes.paragraph):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   148
                caption = nodes.caption(first_node.rawsource, '',
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   149
                                        *first_node.children)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   150
                figure_node += caption
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   151
            elif not (isinstance(first_node, nodes.comment)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   152
                      and len(first_node) == 0):
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   153
                error = self.state_machine.reporter.error(
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   154
                      'Figure caption must be a paragraph or empty comment.',
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   155
                      nodes.literal_block(self.block_text, self.block_text),
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   156
                      line=self.lineno)
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   157
                return [figure_node, error]
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   158
            if len(node) > 1:
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   159
                figure_node += nodes.legend('', *node[1:])
d8ac696cc51f helium_7.0-r14027
wbernard
parents:
diff changeset
   160
        return [figure_node]