#@+leo-ver=4-thin
#@+node:mork.20041010095009:@thin xsltWithNodes.py
#@<< docstring >>
#@+node:ekr.20050226120104:<< docstring >>
"""Adds XSLT-Node Command submen item to the Outline menu.

This menu contains the following items:

- Set StyleSheet Node:
    - Selects the current node as the xsl stylesheet the plugin will use.

- Process Node with Stylesheet Node:
    - Processes the current node as an xml document,
      resolving section references and Leo directives.
    - Creates a sibling containing the results.

Requires 4Suite 1.0a3 or better, downloadable from http://4Suite.org.
"""
#@nonl
#@-node:ekr.20050226120104:<< docstring >>
#@nl

#@@language python
#@@tabwidth -4

#@<< imports >>
#@+node:mork.20041025113509:<< imports >>
import leoGlobals as g
import leoNodes
import leoPlugins
from xml.dom import minidom

try:
    import Ft
    from Ft.Xml import InputSource 
    from Ft.Xml.Xslt.Processor import Processor
except ImportError:
    Ft = g.cantImport("Ft",__name__)

Tk = g.importExtension('Tkinter',pluginName=__name__,verbose=True)

import weakref 
import cStringIO
#@nonl
#@-node:mork.20041025113509:<< imports >>
#@nl
#@<<parser problems>>
#@+node:mork.20041024091024:<<parser problems>>
#@@killcolor

#@+at 
# 1. Having space before the start of the document caused it not to work.  I 
# fixed this by striping the whitespace from the start
# and end of the data at xslt time.
# 
# 2. having a @ right before a tag causes it to not process.
#     It appears to be safe to follow this pattern:
#     @ </end>
#     but not:
#     @</end>
# 
#     I dont know at this point if its just illegal xml, or its a problem in 
# the parser. ??
#@-at
#@nonl
#@-node:mork.20041024091024:<<parser problems>>
#@nl
#@<<future directions>>
#@+node:mork.20041025101943:<<future directions>>
#@+at
# 1. Add more XSLT boilerplate insertions.( done in .3 )
# 2. Maybe add a well-formedness check. (done in .3, test with minidom )
#@-at
#@nonl
#@-node:mork.20041025101943:<<future directions>>
#@nl
__version__ = '0.6'
#@<< version history >>
#@+node:mork.20041025113211:<< version history >>
#@@killcolor

#@+at
# 
# 0.1: Original code.
# 
# 0.2 EKR: Converted to outline.
# 
# 0.3: Added more XSLT boilerplate. Added Test with Minidom Discovered parser 
# problem(?).
# 
# 0.4 EKR:
#     - Added init function.
#     - Use g.importExtension to import Tkinter.
# 0.5 EKR:
#     - Remove 'start2' hook & haveseen dict.
#     - Use keywords.get('c') instead of g.top().
# 0.6 EKR:
#     - Removed g.top from example code.
#@-at
#@nonl
#@-node:mork.20041025113211:<< version history >>
#@nl

#@+others
#@+node:ekr.20050226120104.1:init
def init():

    ok = Ft and Tk
    if not ok: return

    if g.app.gui is None:
        g.app.createTkGui(__file__)

    ok = g.app.gui.guiName() == "tkinter"

    if ok:
        leoPlugins.registerHandler(('open2',"new"),addMenu)
        g.plugin_signon(__name__)

    return ok
#@nonl
#@-node:ekr.20050226120104.1:init
#@+node:mork.20041025115037:xslt elements
#This dict contains elements that go into a stylesheet
xslt = {

'apply-imports': '<xsl:apply-imports/>',
'apply-templates': "<xsl:apply-templates select ='' mode='' />",
'attribute': "<xsl:attribute name=''> </xsl:attribute>",
'attribute-set': "<xsl:attribute-set name=''> </xsl:attribute-set>",
'call-template': "<xsl:call-template name=''> </xsl:call-template>",
'choose': "<xsl:choose> </xsl:choose>",
'comment': "<xsl:comment> </xsl:comment>",
'copy': "<xsl:copy> </xsl:copy>",
'copy-of': "<xsl:copy-of select='' />",
'decimal-format' : "<xsl:decimal-format   />",
'element': "<xsl:element name='' > </xsl:element>",
'fallback': "<xsl:fallback> </xsl:fallback>",
'for-each': "<xsl:for-each select='' >  </xsl:for-each>",
'if': "<xsl:if test=''> </xsl:if>",
'import': "<xsl:import href='' />",
'include': "<xsl:include href='' />",
'key': "<xsl:key name='' match='' use='' />",
'message': "<xsl:message> </xsl:message>",
'namespace-alias': "<xsl:namespace-alias stylesheet-prefix='' result-prefix='' />",
'number': "<xsl:number />",
'otherwise': "<xsl:otherwise> </xsl:otherwise>",
'output': "<xsl:output />",
'param': "<xsl:param name='' >  </xsl:param>",
'preserve-space': "<xsl:preserve-space elements='' />",
'processing-instruction': "<xsl:processing-instruction name='' > </xsl:processing-instruction>",
'sort': "<xsl:sort />",
'strip-space': "<xsl:strip-space elements='' />",
'stylesheet': "<xsl:stylesheet xmlns:xsl='' version='' > </xsl:stylesheet>",
'template': "<xsl:template > </xsl:template>",
'text': "<xsl:text > </xsl:text>",
'transform': "<xsl:transform >  </xsl:transform>",
'value-of': "<xsl:value-of select='' />",
'variable': "<xsl:variable name=''> </xsl:variable>",
'when': "<xsl:when text='' > </xsl:when>",
'with-param': "<xsl:with-param name=''> </xsl:with-param>",

}
#@nonl
#@-node:mork.20041025115037:xslt elements
#@+node:mork.20041010095202:setStyleNode
stylenodes = weakref.WeakKeyDictionary()

def setStyleNode( c ):
    '''this command sets what the current style node is'''
    position = c.currentPosition()
    stylenodes[ c ] = position


#@-node:mork.20041010095202:setStyleNode
#@+node:mork.20041010095202.1:processDocumentNode
def processDocumentNode( c ):
    '''this executes the stylesheet node against the current node'''
    try:
        if not styleNodeSelected( c ): return
        proc = Processor()
        stylenode = stylenodes[ c ]
        pos = c.currentPosition()
        c.beginUpdate()
        c.selectPosition( stylenode )
        sIO = getString( c )
        mdom1 = minidom.parseString( sIO )
        sIO = str( mdom1.toxml() )
        hstring = str( stylenode.headString() )
        if hstring == "": hstring = "no headline"
        stylesource = InputSource.DefaultFactory.fromString( sIO, uri = hstring)
        proc.appendStylesheet( stylesource )
        c.selectPosition( pos )
        xmlnode = pos.v.t
        xIO = getString( c )
        mdom2 = minidom.parseString( xIO )
        xIO = str( mdom2.toxml())
        xhead = str( xmlnode.headString )
        if xhead == "": xhead = "no headline"
        xmlsource = InputSource.DefaultFactory.fromString( xIO, uri = xhead ) 
        result = proc.run( xmlsource )
        nhline = "xsl:transform of " + str( xmlnode.headString )
        tnode = leoNodes.tnode( result, nhline )
        pos.insertAfter( tnode )
        c.endUpdate()

    except Exception, x:
        g.es( 'exception ' + str( x ))
    c.endUpdate()


#@-node:mork.20041010095202.1:processDocumentNode
#@+node:mork.20041025121608:addXSLTNode
def addXSLTNode (c):
    '''creates a node and inserts some xslt boilerplate'''
    pos = c.currentPosition()

    #body = '''<?xml version="1.0"?>'''
    # body = '''<?xml version="1.0"?>
    #<xsl:transform xmlns:xsl="http:///www.w3.org/1999/XSL/Transform" version="1.0">'''

    body = '''<?xml version="1.0"?>
<xsl:transform xmlns:xsl="http:///www.w3.org/1999/XSL/Transform" version="1.0">    
</xsl:transform>'''

    tnode = leoNodes.tnode(body,"xslt stylesheet")
    c.beginUpdate()
    pos.insertAfter(tnode)
    c.endUpdate()
#@-node:mork.20041025121608:addXSLTNode
#@+node:mork.20041010110121:addXSLTElement
def addXSLTElement( c , element):
    '''adds some xslt to the text node'''
    bodyCtrl = c.frame.body.bodyCtrl
    bodyCtrl.insert( 'insert', element )
    bodyCtrl.event_generate( '<Key>' )
    bodyCtrl.update_idletasks()

#@-node:mork.20041010110121:addXSLTElement
#@+node:mork.20041025113021:getString
def getString (c):
    '''This def turns a node into a string based off of Leo's file-nosent write logic'''
    at = c.atFileCommands
    pos = c.currentPosition()
    cS = cStringIO.StringIO()

    if not hasattr( at, 'new_df' ):
    #if new_at_file: # 4.3 code base.
        at.toStringFlag = True
        # at.outputFile = cS 
        at.writeOpenFile(pos,nosentinels=True,toString=True) #How the heck does this fill cS with data, if at.outputFile is never set?
        # at.outputFile = None 
        # at.toStringFlag = False 

    else: # 4.2 code base
        at.new_df.toStringFlag = True
        at.new_df.outputFile = cS
        at.new_df.writeOpenFile(pos,nosentinels=True,toString=True)
        at.new_df.outputFile = None
        at.new_df.toStringFlag = False

    cS.seek(0)
    return cleanString( cS.getvalue() )
#@nonl
#@-node:mork.20041025113021:getString
#@+node:mork.20041025120706:doMinidomTest
def doMinidomTest( c ):
    '''This def performs a simple test on a node.  Can the data be successfully parsed by minidom or not.  Results are output to the log'''
    s = getString( c )
    try:
        mdom = minidom.parseString( s )
    except Exception, x:
        g.es( "Minidom could not parse node because of:\n %s" % x, color='red' )
        return
    g.es( "Minidom could parse the node", color='blue'  )
#@-node:mork.20041025120706:doMinidomTest
#@+node:mork.20041025090303:cleanString
def cleanString( data ):
    '''This method cleans a string up for the processor.  It currently just removes
       leading and trailing whitespace'''

    val = data.strip()
    return val

#@-node:mork.20041025090303:cleanString
#@+node:mork.20041010125444:jumpToStyleNode
def jumpToStyleNode( c ):
    '''Simple method that jumps us to the current XSLT node'''
    if not styleNodeSelected( c ): return
    pos = stylenodes[ c ]
    c.beginUpdate()
    c.selectPosition( pos )
    c.endUpdate()


#@-node:mork.20041010125444:jumpToStyleNode
#@+node:mork.20041010125444.1:styleNodeSelected
def styleNodeSelected( c ):
    '''Determines if a XSLT Style node has not been selected'''
    if not stylenodes.has_key( c ):
        g.es( "No Style Node selected" ) 
        return False
    return True


#@-node:mork.20041010125444.1:styleNodeSelected
#@+node:mork.20041010100633:addMenu
def addMenu( tag, keywords ):
    c = keywords.get('c')
    if not c: return

    men = c.frame.menu
    men = men.getMenu( 'Outline' )
    xmen = Tk.Menu( men , tearoff = False)
    xmen.add_command( label = "Set Stylesheet Node", command = lambda c = c : setStyleNode( c ) )
    xmen.add_command( label = "Jump To Style Node", command = lambda c = c: jumpToStyleNode( c ) )
    xmen.add_command( label = "Process Node with Stylesheet Node", command = lambda c=c : processDocumentNode( c ) )
    xmen.add_separator()
    xmen.add_command( label = "Create Stylesheet Node", command = lambda c = c : addXSLTNode( c ) )
    elmen= Tk.Menu( xmen, tearoff = False )
    xmen.add_cascade( label = "Insert XSL Element", menu = elmen )
    xsltkeys = xslt.keys()
    xsltkeys.sort()
    for z in xsltkeys:
        elmen.add_command( label = z, command = lambda c = c, element = xslt[ z ]: addXSLTElement( c, element ) )
    men.add_cascade( menu = xmen, label = "XSLT-Node Commands" )
    xmen.add_command( label = 'Test Node with Minidom', command = lambda c=c: doMinidomTest( c ) )



#@-node:mork.20041010100633:addMenu
#@+node:mork.20041025100716:examples/tests
#@+at
# table.leo contains the xml.  xslt is in the other node.
# 
# To test this plugin, set the xslt node to be the xslt node.
# 
# Process it against the table.leo node.
# 
# 
#@-at
#@@c

r'''
#@+others
#@+node:mork.20041025100851:table.leo

<?xml version="1.0" encoding="UTF-8"?>
<leo_file>
<leo_header file_format="2" tnodes="0" max_tnode_index="3" clone_windows="0"/>
<globals body_outline_ratio="0.5">
	<global_window_position top="43" left="161" height="600" width="800"/>
	<global_log_window_position top="0" left="0" height="0" width="0"/>
</globals>
<preferences>
</preferences>
<find_panel_settings>
	<find_string></find_string>
	<change_string></change_string>
</find_panel_settings>
<vnodes>
<v t="mork.20041015144717" a="E"><vh>table</vh>
<v t="mork.20041015144717.1" a="E" tnodeList="mork.20041015144717.1,mork.20041015163641,mork.20041015163641.1,mork.20041015154946,mork.20041015152916,mork.20041016141748,mork.20041017102304,mork.20041017102304.1,mork.20041016151554,mork.20041016152412,mork.20041017110545,mork.20041017105444,mork.20041015144717.2,mork.20041017111049,mork.20041017111248,mork.20041016180930,mork.20041016181326,mork.20041015144717.3,mork.20041015144717.4"><vh>@file-nosent table.py</vh>
<v t="mork.20041015163641" a="E"><vh>class CSVVisualizer</vh>
<v t="mork.20041015163641.1"><vh>init</vh></v>
<v t="mork.20041015154946"><vh>addData</vh></v>
<v t="mork.20041015152916"><vh>readData</vh></v>
<v t="mork.20041016141748"><vh>writeData</vh></v>
<v t="mork.20041017102304"><vh>addColumn</vh></v>
<v t="mork.20041017102304.1"><vh>deleteColumn</vh></v>
<v t="mork.20041016151554"><vh>addRow</vh></v>
<v t="mork.20041016152412"><vh>deleteRow</vh></v>
<v t="mork.20041017110545"><vh>createDefaultRecord</vh></v>
</v>
<v t="mork.20041017105444"><vh>newTable</vh></v>
<v t="mork.20041015144717.2" a="TV"><vh>viewTable</vh></v>
<v t="mork.20041017111049"><vh>fireButton</vh></v>
<v t="mork.20041017111248"><vh>createDialog</vh></v>
<v t="mork.20041016180930"><vh>createTable</vh></v>
<v t="mork.20041016181326"><vh>createBBox</vh></v>
<v t="mork.20041015144717.3"><vh>addMenu</vh></v>
<v t="mork.20041015144717.4"><vh>if 1:</vh></v>
</v>
</v>
</vnodes>
<tnodes>
<t tx="mork.20041015144717">@path /boboo/leo-4.2-final/plugins</t>
<t tx="mork.20041015144717.1">import Tkinter as Tk
import tktable as tktab
import leoGlobals as g
from leoPlugins import *
import leoNodes
import csv
import cStringIO
import weakref
import Pmw


#@+others
#@-others
</t>
<t tx="mork.20041015144717.2">def viewTable( c, new = False ):

    pos = c.currentPosition()
    dialog = createDialog( pos )
    csvv = CSVVisualizer( c )
    sframe = Pmw.ScrolledFrame( dialog.interior() )
    sframe.pack()
    tab = createTable( sframe.interior(), csvv.arr )
    createBBox( dialog.interior(), csvv, tab )
    if not new:
        n = csvv.addData()
    else:
        n = ( 4, 1 )
        csvv.createDefaultRecord( n[ 1 ], n[ 0 ] )
    tab.configure( cols = n[ 0 ], rows = n[ 1 ] )
    dialog.configure( command = lambda name, d = dialog, csvv = csvv:
                         fireButton( name, d, csvv ) )
    dialog.activate()


</t>
<t tx="mork.20041015144717.3">haveseen = weakref.WeakKeyDictionary()
def addMenu( tag, keywords ):
    c = keywords.get('c') or keywords.get('new_c')
    if haveseen.has_key( c ):
        return
    haveseen[ c ] = None
    men = c.frame.menu
    men = men.getMenu( 'Outline' )
    tmen = Tk.Menu( men, tearoff = 0 )
    men.add_cascade( menu = tmen, label = "Table Commands" )
    tmen.add_command( label = "Edit Node With Table", command = lambda c = c: viewTable( c ) )
    tmen.add_command( label = "Create New Table", command = lambda c = c: newTable( c ) )





</t>
<t tx="mork.20041015144717.4">if 1:

    registerHandler( ('start2' , 'open2', "new") , addMenu )
    __version__ = ".125"
    g.plugin_signon( __name__ )  

</t>
<t tx="mork.20041015152916">def readData( self ):

    c = self.c
    pos = c.currentPosition()
    data = pos.bodyString()
    cS = cStringIO.StringIO()
    cS.write( data )
    cS.seek( 0 )
    sniff = csv.Sniffer()
    self.type = sniff.sniff( data ) 
    reader = csv.reader( cS, self.type ) 
    return reader

</t>
<t tx="mork.20041015154946">def addData( self ):

    arr = self.arr
    reader = self.readData() 
    hc = False
    for n, d in enumerate( reader ):
        for n1, d2 in enumerate( d ):
            arr.set( "%s,%s" %( n, n1 ), str(d2) )

    self.columns = n1 + 1
    self.rows = n + 1
    return self.columns, self.rows


</t>
<t tx="mork.20041015163641">class CSVVisualizer:

    arrays = []

    #@    @+others
    #@-others
</t>
<t tx="mork.20041015163641.1">def __init__( self, c ):

    self.c = c
    self.arr = tktab.ArrayVar()
    CSVVisualizer.arrays.append( self.arr )
    self.rows = 0
    self.columns = 0
    self.type = 'excel'



</t>
<t tx="mork.20041016141748">def writeData( self, save ):

    pos = self.c.currentPosition()
    n2 = self.rows
    n = self.columns
    data = []
    for z in xrange( n2 ):
        ndata = []
        for z2 in xrange( n ):
            ndata.append( self.arr.get( "%s,%s" % ( z, z2 ) ) )        
        data.append( ndata )
    cS = cStringIO.StringIO()
    csv_write = csv.writer( cS, self.type )
    for z in data:
        csv_write.writerow( z )
    cS.seek( 0 )
    self.c.beginUpdate() 
    if not save:
        tnd = leoNodes.tnode( cS.getvalue(), "Save of Edited " + str( pos.headString() ) )
        pos.insertAfter( tnd )
    else:
        pos.setTnodeText( cS.getvalue() )
    self.c.endUpdate()





</t>
<t tx="mork.20041016151554">def addRow( self , tab ):

    self.rows = self.rows + 1
    tab.configure( rows = self.rows )
    rc =  '%s,0' % (self.rows -1 )
    for z in xrange( self.columns ):
        self.arr.set( '%s,%s' %( self.rows - 1, z ), "" ) 
    tab.activate( rc )
    tab.focus_set()



</t>
<t tx="mork.20041016152412">def deleteRow( self, tab ):

    i = tab.index( 'active' )
    if i:
        tab.delete_rows( i[ 0 ], 1 )
        self.rows = self.rows - 1
</t>
<t tx="mork.20041016180930">def createTable( parent , arr ):

    tab = tktab.Table( parent , rows = 0, cols = 0, variable = arr, sparsearray=1,
    background = 'white', foreground = 'blue', selecttype = 'row' )
    tab.tag_configure( 'active', background = '#FFE7C6', foreground = 'blue' )
    tab.tag_configure( 'sel', background = '#FFE7C6', foreground = 'blue', bd =2 )
    tab.pack()
    return tab 

</t>
<t tx="mork.20041016181326">def createBBox( parent, csvv, tab ):

    bbox = Pmw.ButtonBox( parent )
    bconfig = ( ( "Add Row", lambda tab = tab : csvv.addRow( tab ) ),
                ( "Delete Row", lambda tab = tab: csvv.deleteRow( tab ) ),
                ( "Add Column", lambda tab = tab: csvv.addColumn( tab ) ),
                ( "Delete Column", lambda tab = tab: csvv.deleteColumn( tab ) ) )
    for z in bconfig:
        bbox.add( z[ 0 ], command = z[ 1 ], background = 'white', foreground = 'blue' )
    bbox.pack()     


</t>
<t tx="mork.20041017102304">def addColumn( self, tab ):

    self.columns = self.columns + 1
    tab.configure( cols = self.columns )
    for z in xrange( self.rows ):
        self.arr.set( '%s,%s' %( z , self.columns -1 ), "" ) 



</t>
<t tx="mork.20041017102304.1">def deleteColumn( self, tab ):

    i = tab.index( 'active' )
    if i:
        tab.delete_cols( i[ 1 ], 1 )
        self.columns = self.columns - 1

</t>
<t tx="mork.20041017105444">def newTable( c ):

    tnd = leoNodes.tnode( "", "New Table" )
    pos = c.currentPosition()
    c.beginUpdate()
    npos = pos.insertAfter( tnd )
    c.endUpdate()
    c.selectPosition( npos )
    viewTable( c , True )


</t>
<t tx="mork.20041017110545">def createDefaultRecord( self, rows, columns ):

    self.rows = rows
    self.columns = columns
    for z in xrange( rows ):
        for z1 in xrange( columns ):
            self.arr.set( '%s,%s' %( z, z1 ), "" )

</t>
<t tx="mork.20041017111049">def fireButton( name, dialog, csvv ):

    if name == "Close":
        dialog.deactivate()
        dialog.destroy()
    elif name == "Write To New":
        csvv.writeData( False )
    elif name == "Save To Current":
        csvv.writeData( True )

</t>
<t tx="mork.20041017111248">def createDialog( pos ):

    dialog = Pmw.Dialog( title = "Table Editor for " + str( pos.headString()),
                         buttons = [ 'Save To Current', 'Write To New', 'Close' ] )
    dbbox = dialog.component( 'buttonbox' )
    for z in xrange( dbbox.numbuttons() ):
        dbbox.button( z ).configure( background = 'white', foreground = 'blue' )
    return dialog


</t>
</tnodes>
</leo_file>
#@-node:mork.20041025100851:table.leo
#@+node:mork.20041025100851.1:xslt to turn leo file into html
<?xml version="1.0"?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method = 'xml' />
<xsl:preserve-space elements='leo_file/tnodes/t'/>


<xsl:template match='v'>

    <ul type='square'>

        <xsl:variable name ='t' select ='@t' />
            <h1><xsl:value-of select='vh'/></h1>
                <xsl:for-each select='ancestor::leo_file/tnodes/t'>
                    <xsl:if test="./attribute::tx=$t">
                    <li>
                        <pre>
                            <xsl:value-of select='.' />
                        </pre>
                    </li>
                    </xsl:if>
                </xsl:for-each>

    <xsl:if test ='./v' >
        <xsl:apply-templates select = 'v'/>
     </xsl:if> 
     </ul>
      </xsl:template>


<xsl:template match ='leo_file'>
    <html><head>
        <style>
            ul{ position:relative;right=25;
                border:thin ridge blue}
            li{ position:relative;right=25} 
            pre{ background:#FFE7C6 }       
        </style>
        </head>
            <body>
                <xsl:apply-templates select='vnodes'/>
            </body>
    </html>
</xsl:template>

<xsl:template match = 'vnodes'>
    <xsl:for-each select = 'v'>
        <frame>
            <xsl:apply-templates select ='.'/>
        </frame>
    </xsl:for-each>
</xsl:template>


</xsl:transform>
#@-node:mork.20041025100851.1:xslt to turn leo file into html
#@-others
'''
#@nonl
#@-node:mork.20041025100716:examples/tests
#@-others
#@nonl
#@-node:mork.20041010095009:@thin xsltWithNodes.py
#@-leo
