コード例 #1
0
    def parse(self, str):
        """Parse equation object string representation."""

        str = str.rstrip("\r\n")
        l = str.split(';')
        if len(l) != 5:
            _logger.error(_('Equation.parse() string invalid (%s)'), str)
            return False

        if l[2].startswith("<svg>"):
            l[2] = SVGImage(data=base64.b64decode(l[2][5:]))


# Should figure out how to use MathLib directly in a non-hacky way
        else:
            try:
                l[2] = Decimal(l[2])
            except Exception, inst:
                pass
コード例 #2
0
    def parse(self, str):
        """Parse equation object string representation."""

        str = str.rstrip("\r\n")
        k = str.split(';')
        if len(k) != 5:
            _logger.error(_('Equation.parse() string invalid (%s)'), str)
            return False

        if k[2].startswith("<svg>"):
            k[2] = SVGImage(data=base64.b64decode(k[2][5:]))

        # Should figure out how to use MathLib directly in a non-hacky way
        else:
            try:
                k[2] = Decimal(k[2])
            except Exception:
                pass

        self.set(k[0], k[1], k[2], XoColor(color_string=k[3]), k[4])
コード例 #3
0
    def process(self):
        """Parse the equation entered and show the result."""

        s = _s(self.text_entry.get_text())
        label = self.label_entry.get_text()
        _logger.debug('process(): parsing %r, label: %r', s, label)
        try:
            tree = self.parser.parse(s)
            res = self.parser.evaluate(tree)
        except ParserError as e:
            res = e
            self.showing_error = True

        if isinstance(res, str) and res.find('</svg>') > -1:
            res = SVGImage(data=res)

        _logger.debug('Result: %r', res)

        # Check whether assigning this label would cause recursion
        if not isinstance(res, ParserError) and len(label) > 0:
            lastpos = self.parser.get_var_used_ofs(label)
            if lastpos is not None:
                res = RuntimeError(
                    _('Can not assign label: will cause recursion'),
                    lastpos)

        # If parsing went ok, see if we have to replace the previous answer
        # to get a (more) exact result
        if self.ans_inserted and not isinstance(res, ParserError) \
                and not isinstance(res, SVGImage):
            ansvar = self.format_insert_ans()
            pos = s.find(ansvar)
            if len(ansvar) > 6 and pos != -1:
                s2 = s.replace(ansvar, 'LastEqn')
                _logger.debug(
                    'process(): replacing previous answer %r: %r', ansvar, s2)
                tree = self.parser.parse(s2)
                res = self.parser.evaluate(tree)

        if isinstance(res, ParserError):
            eqn = Equation(label, _n(s), res, self.color,
                           self.get_owner_id(), ml=self.ml)
            self.set_error_equation(eqn)
        else:
            eqn = Equation(label, _n(s), _n(str(res)), self.color,
                           self.get_owner_id(), ml=self.ml)
            self.add_equation(eqn, drawlasteq=True, tree=tree)
            self.send_message("add_eq", value=str(eqn))

            self.parser.set_var('Ans', eqn.result)

            # Setting LastEqn to the parse tree would certainly be faster,
            # however, it introduces recursion problems
            self.parser.set_var('LastEqn', eqn.result)

            self.showing_error = False
            self.ans_inserted = False
            self.text_entry.set_text('')
            self.label_entry.set_text('')

        return res is not None
コード例 #4
0
    def size_for_node(self, node, client):
        '''Given a docutils image node, returns the size the image should have
        in the PDF document, and what 'kind' of size that is. 
        That involves lots of guesswork'''

        uri = os.path.join(client.basedir, str(node.get("uri")))
        srcinfo = client, uri

        # Extract all the information from the URI
        imgname, extension, options = self.split_uri(uri)

        if not os.path.isfile(imgname):
            imgname = missing

        scale = float(node.get('scale', 100)) / 100
        size_known = False

        # Figuring out the size to display of an image is ... annoying.
        # If the user provides a size with a unit, it's simple, adjustUnits
        # will return it in points and we're done.

        # However, often the unit wil be "%" (specially if it's meant for
        # HTML originally. In which case, we will use a percentage of
        # the containing frame.

        # Find the image size in pixels:
        kind = 'direct'
        xdpi, ydpi = client.styles.def_dpi, client.styles.def_dpi
        extension = imgname.split('.')[-1].lower()
        if extension in ['svg', 'svgz'] and SVGImage.available():
            iw, ih = SVGImage(imgname, srcinfo=srcinfo).wrap(0, 0)
            # These are in pt, so convert to px
            iw = iw * xdpi / 72
            ih = ih * ydpi / 72

        elif extension in [
                "ai", "ccx", "cdr", "cgm", "cmx", "sk1", "sk", "xml", "wmf",
                "fig"
        ] and VectorImage.available():
            iw, ih = VectorImage(imgname, srcinfo=srcinfo).wrap(0, 0)
            # These are in pt, so convert to px
            iw = iw * xdpi / 72
            ih = ih * ydpi / 72

        elif extension == 'pdf':
            if VectorPdf is not None:
                box = VectorPdf.load_xobj(srcinfo).BBox
            else:
                pdf = LazyImports.pdfinfo
                if pdf is None:
                    log.warning(
                        'PDF images are not supported without pyPdf or pdfrw [%s]',
                        nodeid(node))
                    return 0, 0, 'direct'
                reader = pdf.PdfFileReader(open(imgname, 'rb'))
                box = [float(x) for x in reader.getPage(0)['/MediaBox']]
            x1, y1, x2, y2 = box
            # These are in pt, so convert to px
            iw = float((x2 - x1) * xdpi / 72)
            ih = float((y2 - y1) * ydpi / 72)
            size_known = True  # Assume size from original PDF is OK

        else:
            keeptrying = True

            if LazyImports.PILImage:
                try:
                    img = LazyImports.PILImage.open(imgname)
                    img.load()
                    iw, ih = img.size
                    xdpi, ydpi = img.info.get('dpi', (xdpi, ydpi))
                    keeptrying = False
                except IOError:  # PIL throws this when it's a broken/unknown image
                    pass
            if keeptrying and LazyImports.PMImage:
                img = LazyImports.PMImage(imgname)
                iw = img.size().width()
                ih = img.size().height()
                density = img.density()
                # The density is in pixelspercentimeter (!?)
                xdpi = density.width() * 2.54
                ydpi = density.height() * 2.54
                keeptrying = False
            if keeptrying:
                log.error(
                    "The image (%s, %s) is broken or in an unknown format",
                    imgname, nodeid(node))
                raise ValueError

        # Try to get the print resolution from the image itself via PIL.
        # If it fails, assume a DPI of 300, which is pretty much made up,
        # and then a 100% size would be iw*inch/300, so we pass
        # that as the second parameter to adjustUnits
        #
        # Some say the default DPI should be 72. That would mean
        # the largest printable image in A4 paper would be something
        # like 480x640. That would be awful.
        #

        w = node.get('width')
        h = node.get('height')
        if h is None and w is None:  # Nothing specified
            # Guess from iw, ih
            log.warning(
                "Using image %s without specifying size."
                "Calculating based on image size at %ddpi [%s]", imgname, xdpi,
                nodeid(node))
            w = iw * inch / xdpi
            h = ih * inch / ydpi
        elif w is not None:
            # Node specifies only w
            # In this particular case, we want the default unit
            # to be pixels so we work like rst2html
            if w[-1] == '%':
                kind = 'percentage_of_container'
                w = int(w[:-1])
            else:
                # This uses default DPI setting because we
                # are not using the image's "natural size"
                # this is what LaTeX does, according to the
                # docutils mailing list discussion
                w = client.styles.adjustUnits(w,
                                              client.styles.tw,
                                              default_unit='px')

            if h is None:
                # h is set from w with right aspect ratio
                h = w * ih / iw
            else:
                h = client.styles.adjustUnits(h,
                                              ih * inch / ydpi,
                                              default_unit='px')
        elif h is not None and w is None:
            if h[-1] != '%':
                h = client.styles.adjustUnits(h,
                                              ih * inch / ydpi,
                                              default_unit='px')

                # w is set from h with right aspect ratio
                w = h * iw / ih
            else:
                log.error('Setting height as a percentage does **not** work. '\
                          'ignoring height parameter [%s]', nodeid(node))
                # Set both from image data
                w = iw * inch / xdpi
                h = ih * inch / ydpi

        # Apply scale factor
        w = w * scale
        h = h * scale

        # And now we have this probably completely bogus size!
        log.info("Image %s size calculated:  %fcm by %fcm [%s]", imgname,
                 w / cm, h / cm, nodeid(node))

        return w, h, kind
コード例 #5
0
    def process(self):
        """Parse the equation entered and show the result"""

        s = unicode(self.text_entry.get_text())
        label = unicode(self.label_entry.get_text())
        _logger.debug('process(): parsing %r, label: %r', s, label)
        try:
            tree = self.parser.parse(s)
            res = self.parser.evaluate(tree)
        except ParserError, e:
            res = e
            self.showing_error = True

        if isinstance(res, str) and res.find('</svg>') > -1:
            res = SVGImage(data=res)

        _logger.debug('Result: %r', res)

        # Check whether assigning this label would cause recursion
        if not isinstance(res, ParserError) and len(label) > 0:
            lastpos = self.parser.get_var_used_ofs(label)
            if lastpos is not None:
                res = RuntimeError(
                    _('Can not assign label: will cause recursion'), lastpos)

# If parsing went ok, see if we have to replace the previous answer
# to get a (more) exact result
        if self.ans_inserted and not isinstance(res, ParserError) \
                and not isinstance(res, SVGImage):
            ansvar = self.format_insert_ans()
コード例 #6
0
class Calculate(ShareableActivity):

    TYPE_FUNCTION = 1
    TYPE_OP_PRE = 2
    TYPE_OP_POST = 3
    TYPE_TEXT = 4

    SELECT_NONE = 0
    SELECT_SELECT = 1
    SELECT_TAB = 2

    KEYMAP = {
        'Return': lambda o: o.process(),
        'period': '.',
        'equal': '=',
        'plus': '+',
        'minus': '-',
        'asterisk': '*',
        'multiply': '×',
        'divide': '÷',
        'slash': '/',
        'BackSpace': lambda o: o.remove_character(-1),
        'Delete': lambda o: o.remove_character(1),
        'parenleft': '(',
        'parenright': ')',
        'exclam': '!',
        'ampersand': '&',
        'bar': '|',
        'asciicircum': '^',
        'less': '<',
        'greater': '>',
        'percent': '%',
        'comma': ',',
        'underscore': '_',
        'Left': lambda o: o.move_left(),
        'Right': lambda o: o.move_right(),
        'Up': lambda o: o.get_older(),
        'Down': lambda o: o.get_newer(),
        'colon': lambda o: o.label_entered(),
        'Home': lambda o: o.text_entry.set_position(0),
        'End':
        lambda o: o.text_entry.set_position(len(o.text_entry.get_text())),
        'Tab': lambda o: o.tab_complete(),
    }

    CTRL_KEYMAP = {
        'c': lambda o: o.text_copy(),
        'v': lambda o: o.text_paste(),
        'x': lambda o: o.text_cut(),
        'q': lambda o: o.close(),
        'a': lambda o: o.text_select_all(),
    }

    SHIFT_KEYMAP = {
        'Left': lambda o: o.expand_selection(-1),
        'Right': lambda o: o.expand_selection(1),
        'Home': lambda o: o.expand_selection(-1000),
        'End': lambda o: o.expand_selection(1000),
    }

    IDENTIFIER_CHARS = \
        u"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_ "

    def __init__(self, handle):
        ShareableActivity.__init__(self, handle)

        self.old_eqs = []

        self.ml = MathLib()
        self.parser = AstParser(self.ml)

        # These will result in 'Ans <operator character>' being inserted
        self._chars_ans_diadic = [
            op[0] for op in self.parser.get_diadic_operators()
        ]
        try:
            self._chars_ans_diadic.remove('-')
        except:
            pass

        self.KEYMAP['multiply'] = self.ml.mul_sym
        self.KEYMAP['divide'] = self.ml.div_sym
        self.KEYMAP['equal'] = self.ml.equ_sym

        self.clipboard = gtk.Clipboard()
        self.select_reason = self.SELECT_SELECT
        self.buffer = u""
        self.showing_version = 0
        self.showing_error = False
        self.ans_inserted = False
        self.show_vars = False

        self.connect("key_press_event", self.keypress_cb)
        self.connect("destroy", self.cleanup_cb)
        self.color = sugar.profile.get_color()

        self.layout = CalcLayout(self)
        self.label_entry = self.layout.label_entry
        self.text_entry = self.layout.text_entry
        self.last_eq_sig = None
        self.last_eqn_textview = None

        self.reset()
        self.layout.show_it()

        self.connect('joined', self._joined_cb)

        self.parser.log_debug_info()

    def ignore_key_cb(self, widget, event):
        return True

    def cleanup_cb(self, arg):
        _logger.debug('Cleaning up...')

    def equation_pressed_cb(self, eqn):
        """Callback for when an equation box is clicked"""

        if isinstance(eqn.result, SVGImage):
            return True

        if len(eqn.label) > 0:
            text = eqn.label
        else:
            # don't insert plain text
            if type(eqn.result) in (types.StringType, types.UnicodeType):
                text = ''
            else:
                text = self.parser.ml.format_number(eqn.result)

        self.button_pressed(self.TYPE_TEXT, text)
        return True

    def set_last_equation(self, eqn):
        """Set the 'last equation' TextView"""

        if self.last_eq_sig is not None:
            self.layout.last_eq.disconnect(self.last_eq_sig)
            self.last_eq_sig = None

        if not isinstance(eqn.result, ParserError):
            self.last_eq_sig = self.layout.last_eq.connect(
                'button-press-event',
                lambda a1, a2, e: self.equation_pressed_cb(e), eqn)

        self.layout.last_eq.set_buffer(eqn.create_lasteq_textbuf())

    def set_error_equation(self, eqn):
        """Set equation with error markers. Since set_last_equation implements
        this we can just forward the call."""
        self.set_last_equation(eqn)

    def clear_equations(self):
        """Clear the list of old equations."""
        self.old_eqs = []
        self.showing_version = 0

    def add_equation(self, eq, prepend=False, drawlasteq=False, tree=None):
        """
        Insert equation in the history list and set variable if assignment.
        Input:
            eq: the equation object
            prepend: if True, prepend to list, else append
            drawlasteq: if True, draw in 'last equation' textbox and queue the
            buffer to be added to the history next time an equation is added.
            tree: the parsed tree, this will be used to set the label variable
            so that the equation can be used symbolicaly.
            """
        if eq.equation is not None and len(eq.equation) > 0:
            if prepend:
                self.old_eqs.insert(0, eq)
            else:
                self.old_eqs.append(eq)

            self.showing_version = len(self.old_eqs)

        if self.last_eqn_textview is not None and drawlasteq:
            # Prepending here should be the opposite: prepend -> eqn on top.
            # We always own this equation
            self.layout.add_equation(self.last_eqn_textview,
                                     True,
                                     prepend=not prepend)
            self.last_eqn_textview = None

        own = (eq.owner == self.get_owner_id())
        w = eq.create_history_object()
        w.connect('button-press-event',
                  lambda w, e: self.equation_pressed_cb(eq))
        if drawlasteq:
            self.set_last_equation(eq)

            # SVG images can't be plotted in last equation window
            if isinstance(eq.result, SVGImage):
                self.layout.add_equation(w, own, prepend=not prepend)
            else:
                self.last_eqn_textview = w
        else:
            self.layout.add_equation(w, own, prepend=not prepend)

        if eq.label is not None and len(eq.label) > 0:
            w = self.create_var_textview(eq.label, eq.result)
            if w is not None:
                self.layout.add_variable(eq.label, w)

            if tree is None:
                tree = self.parser.parse(eq.equation)
            self.parser.set_var(eq.label, tree)

    # FIXME: to be implemented
    def process_async(self, eqn):
        """Parse and process an equation asynchronously."""

    def process(self):
        """Parse the equation entered and show the result"""

        s = unicode(self.text_entry.get_text())
        label = unicode(self.label_entry.get_text())
        _logger.debug('process(): parsing %r, label: %r', s, label)
        try:
            tree = self.parser.parse(s)
            res = self.parser.evaluate(tree)
        except ParserError, e:
            res = e
            self.showing_error = True

        if isinstance(res, str) and res.find('</svg>') > -1:
            res = SVGImage(data=res)

        _logger.debug('Result: %r', res)

        # Check whether assigning this label would cause recursion
        if not isinstance(res, ParserError) and len(label) > 0:
            lastpos = self.parser.get_var_used_ofs(label)
            if lastpos is not None:
                res = RuntimeError(
                    _('Can not assign label: will cause recursion'), lastpos)

# If parsing went ok, see if we have to replace the previous answer
# to get a (more) exact result
        if self.ans_inserted and not isinstance(res, ParserError) \
                and not isinstance(res, SVGImage):
            ansvar = self.format_insert_ans()
            pos = s.find(ansvar)
            if len(ansvar) > 6 and pos != -1:
                s2 = s.replace(ansvar, 'LastEqn')
                _logger.debug('process(): replacing previous answer %r: %r',
                              ansvar, s2)
                tree = self.parser.parse(s2)
                res = self.parser.evaluate(tree)

        eqn = Equation(label,
                       s,
                       res,
                       self.color,
                       self.get_owner_id(),
                       ml=self.ml)

        if isinstance(res, ParserError):
            self.set_error_equation(eqn)
        else:
            self.add_equation(eqn, drawlasteq=True, tree=tree)
            self.send_message("add_eq", value=str(eqn))

            self.parser.set_var('Ans', eqn.result)

            # Setting LastEqn to the parse tree would certainly be faster,
            # however, it introduces recursion problems
            self.parser.set_var('LastEqn', eqn.result)

            self.showing_error = False
            self.ans_inserted = False
            self.text_entry.set_text(u'')
            self.label_entry.set_text(u'')

        return res is not None