# -*- coding: utf-8 -*-

# vlineedit.py
# This file is part of VWidgets module
# see: http://bazaar.launchpad.net/~vincent-vandevyvre/oqapy/serie-1.0/
#
# Author: Vincent Vande Vyvre <vincent.vandevyvre@swing.be>
# Copyright: 2012-2013 Vincent Vande Vyvre
# Licence: GPL3
#
#
# This file is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this file.  If not, see <http://www.gnu.org/licenses/>.
#
# Define a line edit with buttons inside the edit area

import sys
import os

from PyQt5.QtCore import Qt, pyqtProperty, QObject, QSize, pyqtSignal,\
                        QXmlStreamReader
from PyQt5.QtGui import QIcon, QPixmap, QCursor, QFont, QPainter, QColor
from PyQt5.QtWidgets import (QLineEdit, QLabel, QHBoxLayout, QToolButton, QMenu,
                             QAction, QSizePolicy, QSpacerItem, QBoxLayout)
from PyQt5.QtSvg import QSvgRenderer

# Compatibility Python 2 and 3
try:
    from PyQt5.QtCore import QString as str_
except ImportError:
    str_ = str

try:
    x = unicode('x')
except NameError:
    unicode = str
    basestring = str

class VLineEdit(QLineEdit):
    """The VLineEdit is a widget that allow the user to enter and edit a single 
    line of plain text.

    The line edit area can have a set of three buttons, one button for reset the
    line to the last state, one button to show the historic and one command 
    button used to execute an action related to the entry.

    The line edit area may have also an informative text wich disappears when 
    editing.
    """
    commandTriggered = pyqtSignal(str)
    historicTriggered = pyqtSignal()
    resetTriggered = pyqtSignal()
    def __init__(self, parent=None):
        super(VLineEdit, self).__init__(parent)
        self.parent = parent
        self.informative_text = InformativeText('', self)
        self.historic = Historic()
        self.command_button = False
        self.historic_button = False
        self.reset_button = False
        self.buttonsOrientation = Qt.LeftToRight
        # the end_offset is the right margin for the text, to avoid the
        # overridding of the text by the button's icons
        self.end_offset = 0
        self.layout = QHBoxLayout(self)
        self.layout.setContentsMargins(10, 0, 0, 0)
        self.layout.setSpacing(0)
        self.layout.addWidget(self.informative_text)
        spacer = QSpacerItem(40, 20, QSizePolicy.Expanding, 
                                    QSizePolicy.Minimum)
        self.layout.addItem(spacer)
        self.buttons_layout = QHBoxLayout()
        self.buttons_layout.setContentsMargins(0, 0, 0, 0)
        self.buttons_layout.setSpacing(0)
        self.layout.addLayout(self.buttons_layout)

        self.returnPressed.connect(self._update_historic)
        self.textChanged.connect(self._on_text_changed)
        self.historic.entryAdded.connect(self._on_entry_added)
        self.historic.historicCleared.connect(self._on_historic_cleared)
        
    def informativeText(self):
        """Returns the informative text.

        """
        return self.informative_text.text_

    def setInformativeText(self, txt):
        """Sets the informative text.

        Args:
        txt -- str() or QString()
        """
        if isinstance(txt, str_):
            txt = unicode(txt)

        elif not isinstance(txt, basestring):
            raise TypeError("VLineEdit.setInformativeText(str):"
                                " arg 1 has unexpected type: '{0}'"
                                .format(type(txt)))

        self.informative_text.set_text(txt)

    informativeText_ = pyqtProperty("QString", informativeText, 
                                    setInformativeText)

    def hasResetButton(self):
        """Returns True if the VLineEdit has a reset button, otherwise returns 
        False.

        """
        if self.reset_button:
            return True

        else:
            return False

    def setResetButton(self, b):
        """Set the reset button.

        The reset button is used to reset the text line to the previous state,
        this behaviour can be overridden with:
            VLineEdit.resetTriggered.connect(foo)

        The VLineEdit emit a signal resetTriggered() when clicked.

        Args:
        b -- boolean
        """
        if b and self.reset_button:
            sys.stderr.write('resetButton already exists, ignoring\n')
            return

        if not isinstance(b, bool):
            raise TypeError("VLineEdit.setResetButton(bool):"
                                " arg 1 has unexpected type: '{0}'\n"
                                .format(type(b)))

        if b:
            self._set_reset_button()
            self.end_offset += 16

        else:
            if self.reset_button:
                self._remove_button(self.reset_button)
                self.reset_button = False
                self.end_offset -= 16

        self.setTextMargins(0, 0, self.end_offset, 0)

    resetButton = pyqtProperty('bool', hasResetButton, setResetButton)

    def hasHistoricButton(self):
        """Returns True if the VLineEdit has a historic button, otherwise  
        returns False.

        """
        if self.historic_button:
            return True

        else:
            return False

    def setHistoricButton(self, b):
        """Sets the historic button.

        The VLineEdit emit a signal historicTriggered() when clicked.

        Args:
        b -- boolean
        """
        if b and self.historic_button:
            sys.stderr.write('historicButton already exists, ignoring\n')
            return

        if not isinstance(b, bool):
            raise TypeError("VLineEdit.setHistoricButton(bool):"
                                " arg 1 has unexpected type: '{0}'\n"
                                .format(type(b)))

        if b:
            self._set_historic_button()
            self.end_offset += 10

        else:
            if self.historic_button:
                self._remove_button(self.historic_button)
                self.historic_button = False
                self.end_offset -= 10

        self.setTextMargins(0, 0, self.end_offset, 0)

    historicButton = pyqtProperty('bool', hasHistoricButton, setHistoricButton)

    def hasCommandButton(self):
        """Returns True if the VLineEdit has a command button, otherwise returns 
        False.

        """
        if self.command_button:
            return True

        else:
            return False

    def setCommandButton(self, b):
        """Sets the command button.

        The command button may be used for any action related with the entry,
        like 'Go to this page', 'Search for this item', etc.

        The VLineEdit emit a signal commandTriggered(str) when clicked.

        Args:
        b -- boolean
        """
        
        if b and self.command_button:
            sys.stderr.write('commandButton already exists, ignoring\n')
            return

        if not isinstance(b, bool):
            raise TypeError("VLineEdit.setCommandButton(bool):"
                                " arg 1 has unexpected type: '{0}'\n"
                                .format(type(b)))

        if b:
            self._set_command_button()
            self.end_offset += 18

        else:
            if self.command_button:
                self._remove_button(self.command_button)
                self.command_button = False
                self.end_offset -= 18

        self.setTextMargins(0, 0, self.end_offset, 0)

    commandButton = pyqtProperty('bool', hasCommandButton, setCommandButton)

    def getOrientation(self):
        """Returns the orientation of the button's layout.

        Type: Qt.LayoutDirection
        """
        return self.buttonsOrientation

    def setOrientation(self, orientation):
        """Sets the orientation of the buttons.

        Args:
        orientation -- Qt.LayoutDirection
        """
        if not isinstance(orientation, Qt.LayoutDirection):
            raise ValueError('VToolHeader.setOrientation(Qt.LayoutDirection) '
                        'arg 1 has unexpected value {0}'.format(orientation))

        if orientation != self.buttonsOrientation:
            self.buttonsOrientation = orientation

            if orientation == Qt.LeftToRight:
                self.buttons_layout.setDirection(QBoxLayout.LeftToRight)

            else:
                self.buttons_layout.setDirection(QBoxLayout.RightToLeft)

    orientation = pyqtProperty(Qt.LayoutDirection, getOrientation, 
                                setOrientation)

    def set_command_icon(self, icon):
        """Sets the command button icon.

        Args:
        icon -- QIcon, QPixmap or image file path
        """
        if not self.command_button:
            raise NameError('VLineEdit.set_command_icon(): the line edit does '
                                'not have a command button')

        self.command_button.set_icon(self._get_icon(icon))

    def set_reset_icon(self, icon):
        """Sets the reset button icon.

        Args:
        icon -- QIcon, QPixmap or image file path
        """
        if not self.reset_button:
            raise NameError('VLineEdit.set_reset_icon(): the line edit does '
                                'not have a reset button')

        self.reset_button.set_icon(self._get_icon(icon))

    def add_historic_entry(self, entry):
        """Add an item into the historic.

        Since the historic is a stack, the entry is added at index 0.

        Args:
        entry -- str() or QString()
        """
        if not isinstance(entry, basestring) and not isinstance(entry, str_):
            raise TypeError('VLineEdit.add_historic_entry(str) '
                            'arg 1 has unexpected type {0}'.format(entry))

        if isinstance(entry, str_):
            val = unicode(entry)

        self.historic.add_entry(entry)

    def add_historic_entries(self, entries, clear=False):
        """Add a list of items into the historic.

        Since the historic is a stack, the list is added at the beggining of
        the historic.

        Args:
        entries -- list of str()
        clear -- if True, the historic is cleared before adding the entries,
                 default is False
        """
        if not isinstance(entries, list):
            raise TypeError('VLineEdit.add_historic_entries(list, clear) '
                            'arg 1 has unexpected type {0}'.format(entries))

        if not isinstance(clear, bool):
            raise TypeError('VLineEdit.add_historic_entries(list, clear) '
                            'arg 2 has unexpected type {0}'.format(clear))

        self.historic.add_entries(entries, clear)

    def get_historic_entries(self):
        """Returns the list of the historic's items.

        Returns:
        list(str())
        """
        return self.historic.entries

    def clear_historic(self):
        """Removes all items from the historic.

        """
        self.historic.clear()
        

    #------------------------------------------------------------------
    # Slots
    #------------------------------------------------------------------

    def _on_text_changed(self, txt):
        """Called when the text is changed.

        """
        if not txt:
            self.informative_text.show()
            self._set_command_enabled(False)

        else:
            self.informative_text.hide()
            self._set_command_enabled(True)

    def _on_command_clicked(self):
        """Called when the command button is clicked.

        """
        self._update_historic()
        self.commandTriggered.emit(self.text())

    def _update_historic(self):
        """Called when the command button is clicked or Return key is pressed.

        """
        self.historic.add_entry(unicode(self.text()))

    def _show_historic(self):
        """Called when the historic button is clicked.

        """
        self.historic_button.showMenu()
        self.historicTriggered.emit()

    def _on_entry_added(self, entry):
        """Called when an entry is added to the historic.

        """
        if self.historic_button:
            self.historic_button.update_menu()
            self._set_historic_enabled(True)

    def _on_historic_cleared(self):
        """Called when the historic is cleared.

        """
        if self.historic_button:
            self.historic_button.update_menu()
            self._set_historic_enabled(False)

    def _set_line(self, idx):
        """Called when an item into the historic is clicked.

        Args:
        idx -- index of the item
        """
        self.setText(self.historic.entries[idx])

    def _reset_text(self):
        """Called when the reset button is clicked.

        """
        txt = self.historic.get_last_entry()
        if txt is None:
            self.setText('')

        else:
            self.setText(txt)

        self.resetTriggered.emit()

    #------------------------------------------------------------------

    def _set_command_button(self):
        """Create the command button.

        """
        self.command_button = Button(self)

        stream = self.get_xmlstream(COMMAND)
        if stream is not None:
            pix = self.svg_to_pixmap(stream, 16, 16)
            self.command_button.set_icon(self._get_icon(pix))

        self.command_button.setMaximumSize(QSize(18, 999))
        self.buttons_layout.addWidget(self.command_button)

        self.command_button.clicked.connect(self._on_command_clicked)

    def _set_historic_button(self):
        """Create the historic button.

        """
        self.historic_button = HistoricButton(self)
        self.buttons_layout.addWidget(self.historic_button)
        self._set_historic_enabled(not self.historic.is_empty())
            
        self.historic_button.clicked.connect(self._show_historic)

    def _set_reset_button(self):
        """Create the reset button.

        """
        self.reset_button = Button(self)

        stream = self.get_xmlstream(RESET)
        if stream is not None:
            pix = self.svg_to_pixmap(stream, 12, 15)
            self.reset_button.set_icon(self._get_icon(pix))

        self.reset_button.setMaximumSize(QSize(16, 999))
        self.buttons_layout.addWidget(self.reset_button)
        self.reset_button.setEnabled(True)

        self.reset_button.clicked.connect(self._reset_text)

    def _remove_button(self, btn):
        """Remove a button.

        Args:
        btn -- button instance
        """
        pos = self.layout.indexOf(btn)
        self.layout.takeAt(pos)
        btn.deleteLater()
        del btn

    def _set_command_enabled(self, b):
        if self.command_button:
            self.command_button.setEnabled(b)

    def _set_historic_enabled(self, b):
        if self.historic_button:
            self.historic_button.setEnabled(b)

    def _get_icon(self, icon):
        if isinstance(icon, QIcon):
            return icon

        if isinstance(icon, QPixmap):
            return QIcon(icon)

        else:
            try:
                if os.path.isfile(icon):
                    img = QPixmap(icon)

                    if img.isNull(): 
                        sys.stderr.write('VLineEdit icon is null: {0}\n'
                                    .format(icon))
                        return

                    return QIcon(img)

                else:
                    sys.stderr.write('VLineEdit icon file not found: {0}\n'
                                    .format(icon))

            except Exception as why:
                sys.stderr.write('VLineEdit.__get_icon error: {0}\n'
                                        .format(why))

    def svg_to_pixmap(self, data, w, h):
        self.rnd = QSvgRenderer(data)
        pix = QPixmap(w, h)
        pix.fill(QColor(0, 0, 0, 0))
        painter = QPainter()
        painter.begin(pix)
        self.rnd.render(painter)
        painter.end()
        return pix

    def get_xmlstream(self, name):
        stream = QXmlStreamReader(name)
        if stream.hasError():
            sys.stderr.write('QXmlStreamReader error: {0} with icon: {1}\n'
                                .format(stream.error(), name))
            sys.stderr.write(stream.errorString())
            return

        return stream


class InformativeText(QLabel):
    """Define the informative text.

    By default the text is styled with an italic font and a color light grey.
    """
    def __init__(self, text='', parent=None):
        super(InformativeText, self).__init__(parent)
        self.setStyleSheet('QLabel {color: #A0A0A0;}')
        self.font = QFont()
        self.font.setFamily("Trebuchet MS")
        self.font.setItalic(True)
        self.set_font(self.font)
        self.set_text(text)

    def set_text(self, text):
        self.text_ = text
        self.setText(text)

    def set_font(self, font):
        if not isinstance(font, QFont):
            raise TypeError('InformativeText.set_font(QFont) argument has ' 
                            'unexpected type: {0}'.format(font))

        self.setFont(font)
        self.font = font


class Button(QToolButton):
    """Define a tool button used for the command and the reset buttons.

    """
    def __init__(self, parent=None):
        super(Button, self).__init__(parent)
        self.parent = parent
        self.icon = None
        self.setAutoRaise(True)
        self.setCursor(QCursor(Qt.ArrowCursor))
        self.setFocusPolicy(Qt.NoFocus)
        self.setEnabled(False)

    def set_icon(self, icon):
        if icon is None:
            return

        size = self.height() - 8
        self.setIconSize(QSize(size, size))
        self.setIcon(icon)


class HistoricButton(QToolButton):
    """Define a tool button with menu used for the historic buttons.

    """
    def __init__(self, parent=None):
        super(HistoricButton, self).__init__(parent)
        self.parent = parent
        self.setAutoRaise(True)
        self.setCursor(QCursor(Qt.ArrowCursor))
        self.setFocusPolicy(Qt.NoFocus)
        self.setMaximumSize(QSize(15, 99))

        self.update_menu()

    def update_menu(self):
        self.menu_ = QMenu(self)

        for idx, line in enumerate(self.parent.historic.entries):
            act = QAction(line, self)
            self.menu_.addAction(act)

        self.setMenu(self.menu_)
        self.menu_.triggered.connect(self.on_line_activated)

    def on_line_activated(self, line):
        idx = self.menu_.actions().index(line)
        self.parent._set_line(idx)


class Historic(QObject):
    """Define the historic.

    The historic may emit two signals:
        entryAdded(str) where str is the string added
        historicCleared() when the historic is cleared
    """
    entryAdded = pyqtSignal(str)
    historicCleared = pyqtSignal()
    def __init__(self, parent=None):
        super(Historic, self).__init__()
        self.entries = []
        self.last_entry = None

    def is_empty(self):
        """Returns True if the historic is empty.

        """
        return not len(self.entries)

    def add_entry(self, entry):
        """Add an entry into the historic.

        Since the historic is a stack, the entry is inserted at the index 0.

        Args:
        entry -- str() or QString()
        """
        if not entry:
            return

        elif entry in self.entries:
            self.entries.remove(entry)

        self.entries.insert(0, entry)
        self.entryAdded.emit(entry)

    def add_entries(self, lst, clear=True):
        """Add a list of strings into the historic.

        Args:
        lst -- list of str()
        clear -- if True (default), clear the historic before adding the new
                 entries
        """
        if isinstance(lst, list):
            if clear:
                self.clear()

            lst.extend(self.entries)
            self.entries = lst
            self.entryAdded.emit('')

        else:
            raise TypeError('VLineEdit.historic.add_entries(list), arg 1 has '
                                'unexpected type: {0}'.format(type(lst)))

    def remove_last_entry(self):
        """Remove the last added string.

        """
        if not self.is_empty():
            self.entries.pop[0]

        if self.is_empty():
            self.historicCleared.emit()

    def remove_entry(self, idx):
        """Remove an entry from the historic.

        Args:
        idx -- index of the item
        """
        if len(self.entries) <= idx:
            raise IndexError('VLineEdit.remove_entry(idx) index out of range: '
                                '{0}'.format(idx))

        self.entries.pop[idx]

        if self.is_empty():
            self.historicCleared.emit()

    def clear(self):
        """Clear the historic.

        """
        self.entries = []
        self.historicCleared.emit()

    def get_last_entry(self):
        """Returns the last added entry.

        """
        if not self.is_empty():
            return self.entries[0]


# Default icon for the command button
COMMAND = str_("""<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

<svg
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   width="16"
   height="16"
   id="svg3088"
   version="1.1"
   inkscape:version="0.47 r22583"
   sodipodi:docname="command.svg">
  <defs
     id="defs3090">
    <inkscape:perspective
       sodipodi:type="inkscape:persp3d"
       inkscape:vp_x="0 : 526.18109 : 1"
       inkscape:vp_y="0 : 1000 : 0"
       inkscape:vp_z="744.09448 : 526.18109 : 1"
       inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
       id="perspective3096" />
    <inkscape:perspective
       id="perspective3083"
       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
       inkscape:vp_z="1 : 0.5 : 1"
       inkscape:vp_y="0 : 1000 : 0"
       inkscape:vp_x="0 : 0.5 : 1"
       sodipodi:type="inkscape:persp3d" />
    <inkscape:perspective
       id="perspective2843"
       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
       inkscape:vp_z="1 : 0.5 : 1"
       inkscape:vp_y="0 : 1000 : 0"
       inkscape:vp_x="0 : 0.5 : 1"
       sodipodi:type="inkscape:persp3d" />
  </defs>
  <sodipodi:namedview
     id="base"
     pagecolor="#ffffff"
     bordercolor="#666666"
     borderopacity="1.0"
     inkscape:pageopacity="0.0"
     inkscape:pageshadow="2"
     inkscape:zoom="10.426822"
     inkscape:cx="7.8448188"
     inkscape:cy="18.286786"
     inkscape:document-units="px"
     inkscape:current-layer="layer1"
     showgrid="false"
     inkscape:window-width="1041"
     inkscape:window-height="772"
     inkscape:window-x="12"
     inkscape:window-y="28"
     inkscape:window-maximized="0" />
  <metadata
     id="metadata3093">
    <rdf:RDF>
      <cc:Work
         rdf:about="">
        <dc:format>image/svg+xml</dc:format>
        <dc:type
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
        <dc:title />
      </cc:Work>
    </rdf:RDF>
  </metadata>
  <g
     inkscape:label="Calque 1"
     inkscape:groupmode="layer"
     id="layer1"
     transform="translate(-225.54439,-532.46933)">
    <path
       style="fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;display:inline"
       d="m 226.54439,533.46933 0,7 0,7 3.30709,-2.16072 0,2.16072 5.35432,-3.5 5.33859,-3.5 -5.33859,-3.5 -5.35432,-3.5 0,2.16071 -3.30709,-2.16071 z"
       id="path3906" />
  </g>
</svg>""")

# Default icon for the reset button
RESET = str_("""<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->

<svg
   xmlns:dc="http://purl.org/dc/elements/1.1/"
   xmlns:cc="http://creativecommons.org/ns#"
   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
   xmlns:svg="http://www.w3.org/2000/svg"
   xmlns="http://www.w3.org/2000/svg"
   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
   width="13.480923"
   height="15.068281"
   id="svg3088"
   version="1.1"
   inkscape:version="0.47 r22583"
   sodipodi:docname="reset.svg">
  <defs
     id="defs3090">
    <inkscape:perspective
       sodipodi:type="inkscape:persp3d"
       inkscape:vp_x="0 : 526.18109 : 1"
       inkscape:vp_y="0 : 1000 : 0"
       inkscape:vp_z="744.09448 : 526.18109 : 1"
       inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
       id="perspective3096" />
    <inkscape:perspective
       id="perspective3083"
       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
       inkscape:vp_z="1 : 0.5 : 1"
       inkscape:vp_y="0 : 1000 : 0"
       inkscape:vp_x="0 : 0.5 : 1"
       sodipodi:type="inkscape:persp3d" />
  </defs>
  <sodipodi:namedview
     id="base"
     pagecolor="#ffffff"
     bordercolor="#666666"
     borderopacity="1.0"
     inkscape:pageopacity="0.0"
     inkscape:pageshadow="2"
     inkscape:zoom="10.426822"
     inkscape:cx="26.516038"
     inkscape:cy="16.863613"
     inkscape:document-units="px"
     inkscape:current-layer="layer1"
     showgrid="false"
     inkscape:window-width="1041"
     inkscape:window-height="772"
     inkscape:window-x="12"
     inkscape:window-y="28"
     inkscape:window-maximized="0" />
  <metadata
     id="metadata3093">
    <rdf:RDF>
      <cc:Work
         rdf:about="">
        <dc:format>image/svg+xml</dc:format>
        <dc:type
           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
        <dc:title></dc:title>
      </cc:Work>
    </rdf:RDF>
  </metadata>
  <g
     inkscape:label="Calque 1"
     inkscape:groupmode="layer"
     id="layer1"
     transform="translate(-224.75973,-533.81928)">
    <g
       id="g3601"
       transform="matrix(0.50635922,0,0,0.50635922,111.31609,270.58776)">
      <path
         id="path3591"
         d="m 232.78505,525.85738 c 1.25835,-0.50891 2.63445,-0.78924 4.07631,-0.78924 5.98535,0 10.83743,4.83062 10.83743,10.78948 0,5.95887 -4.85208,10.78948 -10.83743,10.78948"
         style="fill:none;stroke:#000000;stroke-width:5.92464781;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0" />
      <path
         transform="translate(229.57246,523.21611)"
         d="M 4.9871378,5.8801031 1.2074383,6.1441837 -2.572261,6.4082642 -0.91111169,3.0029081 0.75003752,-0.40244775 2.8685877,2.7388278 4.9871378,5.8801031 z"
         inkscape:randomized="0"
         inkscape:rounded="0"
         inkscape:flatsided="false"
         sodipodi:arg2="1.5010416"
         sodipodi:arg1="0.453844"
         sodipodi:r2="2.1875303"
         sodipodi:r1="4.3750606"
         sodipodi:cy="3.9619732"
         sodipodi:cx="1.0549715"
         sodipodi:sides="3"
         id="path3593"
         style="fill:none;stroke:#000000;stroke-width:5.92464781;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
         sodipodi:type="star" />
    </g>
  </g>
</svg>
""")
