#@+leo-ver=4-thin
#@+node:mork.20050127125058.31:@thin leoSwingFrame.py
"""The Central Gui components for jyleo."""

import leoSwingMenu
import leoSwingGui
import leoSwingUndo
import leoFrame
import leoGlobals as g            
from utilities.DefCallable import DefCallable
from utilities.TabManager import TabManager
from utilities.WeakMethod import WeakMethod
import weakref
import java
import java.awt.datatransfer as datatransfer
import java.lang
import java.lang.Exception
import javax.swing as swing
import java.awt as awt
import java.io as io
import javax.imageio as imageio
import javax.swing.tree as stree
import javax.swing.event as sevent
import javax.swing.text as stext  
import javax.swing.undo as undo
import javax.swing.plaf.synth as synth
import javax.swing.border as sborder
import java.awt.event as aevent
import java.util as util #
import java.util.concurrent as concurrent
import java.util.concurrent.atomic as atomic
import java.util.concurrent.locks as locks
import java.util.regex as jregex
import leoEditorKit2
import EditorBackground
import SwingMacs
import string
import leoPlugins
import base64
import leoIconTreeRenderer
import leoHeadlineTreeCellEditor
import jarray
import LeoUtilities
import copy
import leoLanguageManager
import PositionSpecification


#@<< About handling events >>
#@+node:mork.20050127125058.32:<< About handling events >>
#@+at 
#@nonl
# Leo must handle events or commands that change the text in the outline or 
# body panes.  It is surprisingly difficult to ensure that headline and body 
# text corresponds to the vnode and tnode corresponding to presently selected 
# outline, and vice versa. For example, when the user selects a new headline 
# in the outline pane, we must ensure that 1) the vnode and tnode of the 
# previously selected node have up-to-date information and 2) the body pane is 
# loaded from the correct data in the corresponding tnode.
# 
# Early versions of Leo attempted to satisfy these conditions when the user 
# switched outline nodes.  Such attempts never worked well; there were too 
# many special cases.  Later versions of Leo, including leo.py, use a much 
# more direct approach.  The event handlers make sure that the vnode and tnode 
# corresponding to the presently selected node are always kept up-to-date.  In 
# particular, every keystroke in the body pane causes the presently selected 
# tnode to be updated immediately.  There is no longer any need for the 
# c.synchVnode method.  (That method still exists for compatibility with old 
# scripts.)
# 
# The leoTree class contains all the event handlers for the tree pane, and the 
# leoBody class contains the event handlers for the body pane.  The actual 
# work is done in the idle_head_key and idle_body_key methods.  These routines 
# are surprisingly complex; they must handle all the tasks mentioned above, as 
# well as others. The idle_head_key and idle_body_key methods should not be 
# called outside their respective classes.  However, sometimes code in the 
# Commands must simulate an event.  That is, the code needs to indicate that 
# headline or body text has changed so that the screen may be redrawn 
# properly.   The leoBody class defines the following simplified event 
# handlers: onBodyChanged, onBodyWillChange and onBodyKey. Similarly, the 
# leoTree class defines onHeadChanged and onHeadlineKey.  Commanders and 
# subcommanders call these event handlers to indicate that a command has 
# changed, or will change, the headline or body text.  Calling event handlers 
# rather than c.beginUpdate and c.endUpdate ensures that the outline pane is 
# redrawn only when needed.
#@-at
#@-node:mork.20050127125058.32:<< About handling events >>
#@nl

#@+others
#@+node:mork.20050127125058.33:class leoSwingBody
class leoSwingBody(  sevent.DocumentListener, aevent.KeyAdapter, sevent.UndoableEditListener ):
    
    """The base class for the body pane in Leo windows."""
    
    #@    @+others
    #@+node:mork.20050127125058.34:leoSwingBody.__init__
    def __init__ (self,frame,parentFrame):
        
        self.editors = []
        self.ignore_insert = 0
        self.frame = frame
        self.c = c = frame.c
        self.forceFullRecolorFlag = False
        frame.body = self
        # May be overridden i
        #leoFrame.leoBody.__init__( self, frame, parentFrame )
        self.parentFrame = parentFrame
        self._current_editor = None
        self._undo_manager = None
        self.jdp = jdp = swing.JDesktopPane()
        self.jdp.addMouseListener( self.SimplifiedUtilityRightClick( self ) )
        #class AddEditor( event.MouseAdapter ):
        #    def __init__( self ):
        #        event.MouseAdapter.__init__( self )
        #    
        #    def mouse
                
            
        #self.mAdapter = leoSwingBody.UtilityRightClick( frame.c ) 
        #self.jdp.addMouseListener( self.mAdapter )
        self.editor = leoSwingBody.Editor( jdp, frame.c, self )
        #self.tabed_pane = swing.JTabbedPane()
        self.tab_manager = TabManager()
        self.tab_manager.add( "Editors", jdp )
        g.doHook( "body_pane_added", c = self.c, tabmanager = self.tab_manager )
        parentFrame.bottomComponent = self.tab_manager.base
        self.editor.frame.setMaximum( True )
        self.oldText = ""
        self.oldSel = ""
        self.oldYview = None
        self.ch = None
        
        #self.frame = frame
        #self.c = c = frame.c
        #self.forceFullRecolorFlag = False
        #frame.body = self
        
        # May be overridden in subclasses...
        #self.bodyCtrl = self
        
        # Must be overridden in subclasses...
        #self.colorizer = None
    #@-node:mork.20050127125058.34:leoSwingBody.__init__
    #@+node:zorcanda!.20050918155613:tabs
    def addTab( self, name, widget ):
        
        self.tab_manager.add( name, widget )
        
        
    
    def removeTab( self, widget ):
        
        self.tab_manager.remove( widget )
            
        
    #@nonl
    #@-node:zorcanda!.20050918155613:tabs
    #@+node:zorcanda!.20051214134754:nextEditor previousEditor
    def nextEditor( self, reverse = False ):
        
        editor = self.editor
        next = False
        editors = list( self.editors )
        if reverse:
            editors.reverse()
        for z in editors:
            z = z.get()
            if next:
                tl = z.editor.getTopLevelAncestor()
                tl.toFront()
                z.editor.requestFocus()
                return
            if z == editor: next = True
        if next:
            for z in editors:
                z = z.get()
                if z:
                    tl = z.editor.getTopLevelAncestor()
                    tl.toFront()
                    z.editor.requestFocus()
                    return
    
        
    def previousEditor( self ):
        self.nextEditor( reverse = True )
    
       
    #@-node:zorcanda!.20051214134754:nextEditor previousEditor
    #@+node:orkman.20050212184341:classes: Editor and a multitude of helpers
    #@+others
    #@+node:orkman.20050202102136:class Editor -- contains the code that makes and controls editors
    class Editor( aevent.FocusListener ):
        
        ipath = g.os_path_join( g.app.loadDir ,"..","Icons","Leoapp2.GIF")
        icon = swing.ImageIcon( "../Icons/Leoapp2.GIF" )
        icon = swing.ImageIcon( ipath ) 
        #ifile = java.io.File( ipath )
        #iimage = imageio.ImageIO.read( ifile ) 
    
        
        #@    @+others
        #@+node:orkman.20050210123306:Note on Editor design
        #@+at
        # The key to making:
        #     1. Autocompleter
        #     2. Line numbers
        #     3. Any any future floaters
        # work is in the use of the JLayeredPane.  The JLayeredPane is made 
        # for floating widgets on top of one another.
        # 
        # 
        # This allows the autocompleter to appear on top of the JTextPane when 
        # needed.  It also allows
        # the easy placement of the Line number label to the left.
        # 
        # The line number label was tried as a JTextPane to start with, this 
        # gave us numbers parralel to the editor.
        # But this seemed to introduce a scroll bug that became apparent when 
        # the editor had a large volume of lines in it.  My
        # assumption is that this was because of some event the Caret for the 
        # line number editor was executing when its contents
        # changed.  By moving to a Label that is drawn on my a method in the 
        # LeoView class this problem no longer presented itself,
        # mainly because a JLabel doesnt have a Cursor.  If that was the 
        # source of the problem.
        # 
        # The viewport is secretly tied to the JTextPane by a specialised 
        # jython JLayeredPane that returns the preferred size of the
        # JTextPane instead of itself.  This causes the JScrollPane to 
        # actually scroll with the editor.
        # 
        # To calculate the coordinates of a floater you need to do the 
        # minimum:
        # 1. Translate the viewports visible rectangle into the JLayeredPanes 
        # coord system.
        #     2. Translate the JTextPane into the JLayeredPanes coord system.
        #     3. Do calculations based off of those two pieces of information.
        # 
        # 
        #@-at
        #@@c
        #@-node:orkman.20050210123306:Note on Editor design
        #@+node:orkman.20050212183815:__init__
        def __init__( self, parent, c , body, x = 0, y = 0):
                
            self.c = c
            self.body = body
            wr = java.lang.ref.WeakReference( self )
            self.body.editors.append( wr )
            self.synchers = []
            self._parent = parent 
            self.frame = swing.JInternalFrame( "", 1, 1, 1, 1, 
                                              size = ( 400, 400 ) )
            self.frame.setFocusTraversalPolicy( c.frame.ftp )
            self._attached = True
                      
            cpane = self.frame.getContentPane()
            self.tab_manager = TabManager()
            self.tab_manager.tabsToBottom()
            self.visible_informer = VisibleInformer( self.tab_manager.jtp )
            cpane.add( self.tab_manager.base, java.awt.BorderLayout.CENTER )
            self.editorlomanager = self.leoLayoutManager()
            self.epane = swing.JPanel()
            self.epane.setLayout( self.editorlomanager )
            self.frame.setFrameIcon( leoSwingBody.Editor.icon )
                
            self.initializeEditor()        
            self.initializeFont()
            #@    << add EditorKit>>
            #@+node:orkman.20050212180331:<< add EditorKit >>
            self.cdeterminer = cdeterminer = leoSwingBody.Editor.ColorKeywordsProvider( self.c )
            self.cdeterminer = weakref.proxy( cdeterminer )
            #use_line_numbers = g.app.config.getBool( c, "use_line_numbering" )  
            use_line_numbers = 0 
            if use_line_numbers:
                pass
                #self.initializeLineNumbering()
            else:
                self.numbers = None
                
            #self.ekit = leoEditorKit( cdeterminer, self.numbers )
            import leoEditorKit2
            self.ekit = leoEditorKit2( self.editor, cdeterminer, leoSwingBody.Editor.icon )
            self.editor.setEditorKit( self.ekit )
            #self.editor.setDocument( ekit.createDefaultDocument() )
            cdeterminer.setEditor( self.editor )
            import JyLeoColorizer
            self.jlc = JyLeoColorizer.JyLeoColorizer( self.editor, cdeterminer )
            self.foldprotection = self.FoldProtector( self.editor, self.ekit )
            self.editor.getDocument().setDocumentFilter( self.foldprotection )
            #self.editor.getDocument().addUndoableEditListener( self.body )
            
            #@-node:orkman.20050212180331:<< add EditorKit >>
            #@nl
            
            #self.editor.addFocusListener( self.tFocusListener())
            self.editor.addMouseListener( leoSwingBody.UtilityRightClick( c , detach_retach = True, editor = self ) )
            self.addMinibuffer()
            self.swingmacs = SwingMacs.SwingMacs( self.editor, self.minibuffer, self.minilabel, c )
            c.frame.isMenuInitialized( self.createCommanderCommander )
            
            #self.swingmacs.addCommands( commandercommander, commandercommander.getCommands() )
            self.addCompleters()
            self.addMenus()    
            
            self.brackethighlighter = self.BracketHighlighter( self.editor, c ) # initializeCaret needs this to work
            self.initializeCaret()
                            
        
            self.editor.setName( "Editor" )
        
            self.editor.getDocument().addDocumentListener( body )
            self.editor.addKeyListener( body )
            #@    << add autocompleter >>
            #@+node:orkman.20050212175531:<< add autocompleter >>
            self.autocompleter = self.autolistener( self )
            self.editor.getDocument().addDocumentListener( self.autocompleter )
            self.editor.addKeyListener( self.autocompleter )
            g.app.config.manager.addNotificationDef( "use_autocompleter", self.useAutocompleter )
            self.useAutocompleter()
            
                
            
            #@-node:orkman.20050212175531:<< add autocompleter >>
            #@nl
            #@    << add scrollpane >>
            #@+node:orkman.20050212180138:<< add scrollpane >>
            spc = swing.ScrollPaneConstants
            #self.view = swing.JScrollPane( layeredpane )
            self.view = swing.JScrollPane( self.editor )
            self.editorlomanager.jscrollpane = self.view
            self.editor.addFocusListener( leoJSPFocusListener( self.view, self.c  ) )
            self.view.setHorizontalScrollBarPolicy( swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER )
            self._vport = vport = self.view.getViewport()
            vport.addComponentListener( self.resizer2( self.editorlomanager ) )
            vport.setScrollMode( vport.BLIT_SCROLL_MODE ) #fastest, removes alot of the flicker I saw
            mwl = self.view.getMouseWheelListeners()[ 0 ]
            self.editor.addMouseWheelListener( mwl )
            self.frame.addMouseWheelListener( mwl )
            self.epane.add( self.view )
            #jtp.add( "Editor", self.epane )
            self.tab_manager.add( "Editor", self.epane )
            self.visible_informer.addCallback( self.epane, self.nowShowing )
            #jtp.add( "Editor", self.view )
            #cpane.add( self.view )
            #@nonl
            #@-node:orkman.20050212180138:<< add scrollpane >>
            #@nl
        
        
            self.configureMedia()
            self.editor.addFocusListener( self )
            self.frame.setLocation( x, y )
            parent.add( self.frame, swing.JLayeredPane.DEFAULT_LAYER )
            self.initializeEditorColors()
            self.frame.visible = 1
            self.lastPosition = None
            self.chapter = None
            wm1 = WeakMethod( self, "chapterChanged" )
            wm2 = WeakMethod( self, "headlineChanged" )
            leoPlugins.registerHandler( "chapter-changed", wm1 )
            leoPlugins.registerHandler( "chapter-removed", wm1 )
            leoPlugins.registerHandler( "headline-editing-finished", wm2 )
            
            bd = self.ekit.getBorder()
            vpb = self.view.getViewportBorder()
            if vpb:
                bd = sborder.CompoundBorder( bd, vpb )
            self.view.setViewportBorder( bd )
            self.sync()
            self.chapter = c.chapters.current_chapter
            g.doHook( "editor-created", editor = self )
        
            
            
            
        
        
        
        #@-node:orkman.20050212183815:__init__
        #@+node:orkman.20050212183628:helper methods and classes
        #@+others
        #@+node:orkman.20050210120520:constuctor methods
        #@+at
        # Just some methods the constructor calls to build the gui components.
        # 
        #@-at
        #@@c
        
        
        
        #@+others
        #@+node:orkman.20050210120520.1:addMenus
        def addMenus( self ):
            
            self.menu = swing.JMenuBar()
            self.frame.setJMenuBar( self.menu )
            self.gotoMenu = gm = swing.JMenu( "Goto" )
            recmen = swing.JMenu( "Recent" )
            self.recent = []
            recmen.addMenuListener( leoSwingBody.Editor.RecentVisitsMenuListener( recmen, self.c, self.recent ) )
            gm.add( recmen )
            self.menu.add( gm ) 
            self.configureGotoMenu( gm )
        
            self.bodyMenu = body = swing.JMenu( "Body" )
            self.menu.add( body )
            directives = swing.JMenu( "Directives" )
            self.directiveMenu( directives )
            #self.menu.add( directives )
            body.add( directives )
            self.addLanguageMenu( body )
            headline = swing.JMenu( "Headline" )
            self.headlineMenu( headline )
            self.menu.add( headline )
            isSR = swing.JMenu( "Insert<%s%s>" % ('<','>' ) )
            self.insertSR( isSR )
            body.add( isSR )
        
            
            insPath = swing.JMenuItem( "Insert @path With File Dialog" )
            self.addInsertPath( insPath )
            body.add( insPath )
            
            #self.addFootNodeMenu( body )
            
            config = g.app.config
            wrap = config.getBool( self.c, "body_pane_wraps" )
            self.ekit.setLineWrap( wrap )
            wrapmenuitem = swing.JCheckBoxMenuItem( "Wrap Lines" )
            wrapmenuitem.setState( wrap )
            def wrapcommand( event ):
                source = event.getSource()
                wrap = source.getState()
                self.ekit.setLineWrap( wrap )
                if wrap:
                    self.view.setHorizontalScrollBarPolicy( swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER )
                else: self.view.setHorizontalScrollBarPolicy( swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED )
                    
            wrapmenuitem.actionPerformed = wrapcommand
            body.add( wrapmenuitem )
            if config.getBool( self.c, "use_text_undo" ):
                umenu = swing.JMenuItem( "" )
                rmenu = swing.JMenuItem( "" )
                gtnu = swing.JMenuItem( "Goto Next Undo Spot" )
                gtnr = swing.JMenuItem( "Goto Next Redo Spot" )
                vunstack = swing.JMenuItem( "Visualise Undo Stack" )
                clear_undo = swing.JMenuItem( "Clear Undo" )
                self._node_undoer = leoSwingUndo.NodeUndoer( self.c, umenu, rmenu, gtnu, gtnr, vunstack, clear_undo, self.editor )
                #print self._node_undoer
                body.addSeparator()
                body.add( umenu )
                body.add( rmenu )
                body.addSeparator()
                body.add( gtnu )
                body.add( gtnr )
                body.addSeparator()
                body.add( vunstack )
                body.add( clear_undo )
            else:
                self._node_undoer = None
            
            self.viewMenu = vmenu = swing.JMenu( "Views" )
            self.menu.add( vmenu )
            jmi = swing.JCheckBoxMenuItem( "CompositeView" )
            vmenu.add( jmi )
            jmi.actionPerformed = self.addCompositeView 
            
            
            self.helpmenu = swing.JMenu( "Help" )
            self.menu.add( self.helpmenu )
            self.helpmenu.add( self.smacs_help( self.c, self.swingmacs, "Keystrokes" ) )
            self.helpmenu.add( self.smacs_help( self.c, self.swingmacs, "Commands" ) )
            self.helpmenu.add( self.autocompleter_help() )
            if hasattr( self.body, 'ebm' ):
                ccomp = self.body.ebm.getControlPanelComponent()
                self.menu.add( ccomp )
        
        
        #@-node:orkman.20050210120520.1:addMenus
        #@+node:orkman.20050210120736:addMinibuffer
        def addMinibuffer( self ):
        
            self.minilabel = swing.JLabel()
            self.minibuffer = minibuffer = swing.JTextField( 15 )
            frame = swing.JPanel()
            frame.setLayout( swing.BoxLayout( frame, swing.BoxLayout.X_AXIS ) )
            frame.add( self.minilabel )
            frame.add( minibuffer )
            frame.setName( "Minibufferbackground" )
            self.epane.add( frame )# awt.BorderLayout.SOUTH )
            self.editorlomanager.minibuffer = frame
            #cpane = self.frame.getContentPane()
            #cpane.add( frame, awt.BorderLayout.SOUTH )
        #@-node:orkman.20050210120736:addMinibuffer
        #@+node:zorcanda!.20050411133032:addCompleters
        def addCompleters( self ):
            
            config = g.app.config
            if config.getBool( self.c, "complete-<" ):
                self.swingmacs.addCompleter( "<", ">" )
            if config.getBool( self.c, "complete-(" ):
                self.swingmacs.addCompleter( "(", ")" )
            if config.getBool( self.c, "complete-[" ):
                self.swingmacs.addCompleter( "[", "]" )
            if config.getBool( self.c, "complete-{"):
                self.swingmacs.addCompleter( "{", "}" )
            if config.getBool( self.c, "complete-'" ):
                self.swingmacs.addCompleter( "'", "'" )
            if config.getBool( self.c, 'complete-"' ):
                self.swingmacs.addCompleter( '"', '"' )
            if config.getBool( self.c, "add_tab_for-:" ):
                self.swingmacs.addTabForColon( True )
                
            
                
                
        #@-node:zorcanda!.20050411133032:addCompleters
        #@+node:zorcanda!.20050530154955:initializeEditor
        def initializeEditor( self ):
            
        
            self.editor = self.leoJTextPane( self.c )
            self.editor.setLineColor()
            self.body._current_editor = self.editor
            manager = g.app.config.manager
            wm1 = WeakMethod( self.editor, "setLineColor" )
            manager.addNotificationDef( "highlight_current_line", wm1 )
            manager.addNotificationDef( "current_line_highlight_color", wm1 )
        #@-node:zorcanda!.20050530154955:initializeEditor
        #@+node:zorcanda!.20050307121447:initializeEditorColors
        def initializeEditorColors( self ):
            
            self.setEditorColors()
            manager = g.app.config.manager
            wm1 = WeakMethod( self, "setEditorColors" )
            manager.addNotificationDef( 'body_text_foreground_color', wm1 )
            manager.addNotificationDef( 'body_text_background_color', wm1 )
            manager.addNotificationDef( 'body_selection_color', wm1 )
            manager.addNotificationDef( 'body_text_selected_color', wm1 )
        
        
        #@-node:zorcanda!.20050307121447:initializeEditorColors
        #@+node:zorcanda!.20050307153345:initializeFont
        def initializeFont( self ):
            
            self.setFont()
            manager = g.app.config.manager
            wm1 = WeakMethod( self, "setFont" )
            manager.addNotificationDef( "body_text_font_family", wm1 )
            manager.addNotificationDef( "body_text_font_size", wm1 )
            manager.addNotificationDef( "body_text_font_weight", wm1 )    
        
        #@-node:zorcanda!.20050307153345:initializeFont
        #@+node:zorcanda!.20050530154220:initializeCaret
        def initializeCaret( self ):
            
            self.setCaret()
            wm1 = WeakMethod( self, "setCaret" )
            g.app.config.manager.addNotificationDef( "which_caret", wm1 )
           
        #@-node:zorcanda!.20050530154220:initializeCaret
        #@+node:zorcanda!.20050530165136:initializeLineNumbering
        def initializeLineNumbering( self ):
            
            fg, bg, cl = self.getLineNumberColors()
            #self.numbers = leoEditorKit.LeoNumberLabel( bg, fg, cl )
            manager = g.app.config.manager
            wm1 = WeakMethod( self, "setLineNumberColors" )
            manager.addNotificationDef( "line_number_background", wm1 )
            manager.addNotificationDef( "line_number_foreground", wm1 )
            manager.addNotificationDef( "line_number_current", wm1 )    
        
        #@-node:zorcanda!.20050530165136:initializeLineNumbering
        #@+node:zorcanda!.20050418115307:createCommanderCommander
        def createCommanderCommander( self, menu ):
            
            commandercommander = self.CommanderCommander( self.c, self.swingmacs, menu )
            self.swingmacs.addCommands( commandercommander, commandercommander.getAltXCommands() )
        #@nonl
        #@-node:zorcanda!.20050418115307:createCommanderCommander
        #@-others
        #@nonl
        #@-node:orkman.20050210120520:constuctor methods
        #@+node:zorcanda!.20050407101020:config methods
        #@+others
        #@+node:zorcanda!.20050407101020.1:configureMedia
        def configureMedia( self ):
            
            c = self.c 
            use_background = g.app.config.getBool( c, "use_media_background" )    
            if use_background:
                try:
                    background_which = g.app.config.getString( c, "media_background_type" )
                    if background_which=='image':
                        self.setBackgroundImage()
                    elif background_which=='movie':
                        movie = g.app.config.getString( c, "movie_location@as-filedialog" )
                        if movie:
                            self.background = swing.JPanel()
                            self.background.setOpaque( False )
                            import EditorBackgroundMovie
                            ebm = EditorBackgroundMovie( movie, self.background )
                            if ebm.loadOk():
                                self.epane.add( self.background )
                                self.editorlomanager.media = self.background
                                #self.layeredpane.add( self.background, self.layeredpane.DEFAULT_LAYER )
                                #self._vport.addChangeListener( self._resizer )
                                self.editor.setOpaque( False )
                                vport = self.view.getViewport()
                                vport.setOpaque( False )
                                self.view.setOpaque( False )
                                self.ebm = ebm
                                #print self.epm
                                ebm.addControllerToMenu( self.menu )
                            else: self.background = None
                finally:
                    if not hasattr( self, 'background' ): 
                        self.background = None
            else:
                self.background = None
        #@-node:zorcanda!.20050407101020.1:configureMedia
        #@+node:zorcanda!.20050530194404:setBackgroundImage
        def setBackgroundImage( self, notification = None, handback = None ):
            
            c = self.c
            alpha = g.app.config.getFloat( c, "background_alpha" )
            if alpha == None: alpha = 1.0
            image_path = g.app.config.getString( c, "image_location@as-filedialog" )
            if image_path:
                imfile = java.io.File( image_path ) 
                if imfile.exists():
                    bimage = imageio.ImageIO.read( imfile )
                    if not hasattr( self, 'background' ): 
                        self.background = EditorBackground( bimage, bimage.getWidth(), bimage.getHeight(), alpha )
                        self.epane.add( self.background )
                        
                    #    self.layeredpane.add( self.background, self.layeredpane.DEFAULT_LAYER )
                    #    self._vport.addChangeListener( self._resizer )
                    self.editor.setOpaque( False )
                    vport = self.view.getViewport()
                    vport.setOpaque( False )
                    self.view.setOpaque( False )
                    #self.epane.setBackedWidget( self.view.getViewport() )
                    #self.epane.setImage( bimage )
                    #self.epane.setAlpha( alpha )
                    self.editorlomanager.media = self.background
                    g.app.config.manager.addNotificationDef( "background_alpha", self.setBackgroundImage )
                    g.app.config.manager.addNotificationDef( "image_location@as-filedialog", self.setBackgroundImage )
                          
                    #else:
                    #    #self.background.setBackground( bimage, bimage.getWidth(), bimage.getHeight(), alpha )
                    #    #self.background.repaint()
        
        
        #@-node:zorcanda!.20050530194404:setBackgroundImage
        #@+node:zorcanda!.20050530130012:useAutocompleter
        def useAutocompleter( self, notification = None, handback = None ):
        
            use = g.app.config.getBool( self.c, "use_autocompleter" )
            if use:  
                self.autocompleter.on = 1
            else:
                self.autocompleter.on = 0
                self.autocompleter.hideAutoBox()
        #@nonl
        #@-node:zorcanda!.20050530130012:useAutocompleter
        #@+node:zorcanda!.20050530144549:setCaret
        def setCaret( self, notification = None, handback = None ):
            c = self.c
            if g.app.config.getString( c, "which_caret" ):
                caret = g.app.config.getString( c, "which_caret" )
                carets= { 'Box': (self.SeeThroughBoxCaret, 'box_color' ),
                          'Underliner': ( self.UnderlinerCaret, 'underliner_color' ),
                          'GhostlyLeo': ( self.GhostlyLeoCaret , None ),
                          'ImageCaret': ( self.ImageCaret, None ),
                          '<none>': (stext.DefaultCaret, None ) }
        
                if caret == 'ImageCaret':
                    try:
                        path_to_image = g.app.config.getString( c, "path_to_caret_image@as-filedialog" )
                        ifile = java.io.File( path_to_image )
                        cimage = imageio.ImageIO.read( ifile )
                        #cicon = swing.ImageIcon( path_to_image )
                        self.editor.setCaret( carets[ caret ]( cimage ) )
                    except java.lang.Exception, x:
                        x.printStackTrace()
                        g.es( "Could not load image for caret" )
                else:
                    caret, color = carets[ caret ]
                    args = None
                    if color:
                        color = g.app.config.getColor( c, color )
                        color = getColorInstance( color )
                        args = ( color )
                        self.editor.setCaret( caret( color ) ) 
                    else:
                        self.editor.setCaret( caret() )    
            self.editor.getCaret().addChangeListener( self.brackethighlighter )
        #@-node:zorcanda!.20050530144549:setCaret
        #@+node:zorcanda!.20050530144949:setFont
        def setFont( self, notification = None, handback = None ):
            
            config = g.app.config
            c = self.c  
            family = config.get( c, "body_text_font_family", "family" )
            size = config.get( c, "body_text_font_size", "size" )
            weight = config.get( c, "body_text_font_weight", "weight" )
            slant = None
            font = config.getFontFromParams( c, "body_text_font_family", "body_text_font_size", None, "body_text_font_weight")
            if font:
                self.editor.setFont( font )
        #@nonl
        #@-node:zorcanda!.20050530144949:setFont
        #@+node:zorcanda!.20050530153629:setEditorColors
        def setEditorColors( self, notification = None, handback = None ):
            
            c = self.c
        
            fg = g.app.config.getColor( c, 'body_text_foreground_color' )
            bg = g.app.config.getColor( c, 'body_text_background_color' )
            sc = g.app.config.getColor( c, 'body_selection_color' )
            stc = g.app.config.getColor( c, 'body_text_selected_color' )
            
            fg = getColorInstance( fg, awt.Color.GRAY )
            bg = getColorInstance( bg, awt.Color.WHITE )
            sc = getColorInstance( sc, awt.Color.GREEN )
            stc = getColorInstance( stc, awt.Color.WHITE )
        
            self.editor.setForeground( fg )
            self.editor.setBackground( bg )
            self.editor.setSelectionColor( sc )
            self.editor.setSelectedTextColor( stc )
        
        
        #@-node:zorcanda!.20050530153629:setEditorColors
        #@+node:zorcanda!.20050530163940:setLineNumberColors
        def getLineNumberColors( self ):
            
            c = self.c
        
            bg = g.app.config.getColor( c, "line_number_background" )
            fg = g.app.config.getColor( c, "line_number_foreground" )
            cl = g.app.config.getColor( c, "line_number_current" )
            try:
                bg = getColorInstance( bg )
                if bg == None: bg = awt.Color.BLACK
                fg = getColorInstance( fg )
                if fg == None: fg = awt.Color.RED
                cl = getColorInstance( cl )
                if cl == None: cl = awt.Color.YELLOW
            except:
                bg = awt.Color.BLACK
                fg = awt.Color.RED
                cl = awt.Color.YELLOW    
            return fg, bg, cl
        
        def setLineNumberColors( self, notification = None, background = None ):  
            
            fg, bg, cl = self.getLineNumberColors()      
            if self.numbers:
                self.numbers.setBackground( bg )
                self.numbers.setForeground( fg )
                self.numbers.setCurrent( cl )
                    
        #@-node:zorcanda!.20050530163940:setLineNumberColors
        #@-others
        #@-node:zorcanda!.20050407101020:config methods
        #@+node:orkman.20050210114856:methods
        #@+others
        #@+node:orkman.20050210120144:sync
        def sync( self, pos=None ):
              
            try:
                if pos == None:
                    pos = self.c.currentPosition()
        
                if pos in self.recent:
                    self.recent.remove( pos )
                else:
                    if len( self.recent ) == 10:
                        self.recent.pop()
                self.recent.insert( 0, pos )
                            
                if self.lastPosition:
                    self.foldprotection.cacheFolds( self.lastPosition.v.t )
                self.lastPosition = pos.copy()
                hs = pos.headString()
                bs = pos.bodyString()
                #self.editor.setText( bs )
                doc = self.editor.getDocument()
                doc.setPosition( pos )
                #doc.sync( bs )
                body = self.c.frame.body
                try:
                    body.ignore_insert = 1
                    self.jlc.ignoreEvents()
                    self.foldprotection.clearFolds()
                    self.foldprotection.defoldViews()
                    doc.remove( 0,  doc.getLength() )
                    doc.insertString( 0, bs, None )
                    self.frame.setTitle( hs )
                    self.jlc.recolorizenow()
                    self.foldprotection.restoreFolds( pos.v.t )
                    if hasattr( self, '_node_undoer' ):
                        self._node_undoer.setNode( pos )
                finally:
                    self.jlc.watchEvents()
                    body.ignore_insert = 0
            except Exception, x:
                pass
                #x.printStackTrace()
             
        #@-node:orkman.20050210120144:sync
        #@+node:zorcanda!.20050810151510:nowShowing
        def nowShowing( self ):
            
            self.body._current_editor = self.editor 
            self.sync()
            
        #@nonl
        #@-node:zorcanda!.20050810151510:nowShowing
        #@+node:orkman.20050210115438:menu methods
        #@+others
        #@+node:orkman.20050210115438.1:configureGotoMenu
        def configureGotoMenu( self, menu ):                    
            oltraveler = leoSwingBody.Editor.outlinetraveler( menu , self.c )
            menu.addMenuListener( oltraveler )
        #@nonl
        #@-node:orkman.20050210115438.1:configureGotoMenu
        #@+node:orkman.20050210115438.2:directiveMenu
        def directiveMenu( self, menu ):
                
            import leoColor
            directives = []
            for z in leoColor.leoKeywords:
                directives.append( z )
            directives.sort()
            InsertTextIntoBody = leoSwingBody.Editor.InsertTextIntoBody
            for z in directives:
                menu.add( InsertTextIntoBody( self.c, z ) ) 
                
        #@-node:orkman.20050210115438.2:directiveMenu
        #@+node:orkman.20050210115438.3:headlineMenu
        def headlineMenu( self, menu ):
                
            import leoNodes
            tnode = leoNodes.tnode()
            v = leoNodes.vnode( self.c, tnode )
            def getValue( names, self = v ):
                return names
            olFindAtFileName = v.findAtFileName
            v.findAtFileName = getValue
            names = v.anyAtFileNodeName()
            v.findAtFileName = olFindAtFileName
            names = list( names )
            names.sort()
            SetHeadline = leoSwingBody.Editor.SetHeadline
            self.addSR( menu )
            for z in names: 
                menu.add( SetHeadline( self.c, z ) )    
                        
            rmvSymbol = leoSwingBody.Editor.rmvSymbol
            rS = rmvSymbol( self.c, '@' )
            menu.add( rS )
            SetHeadlineToSelection = leoSwingBody.Editor.SetHeadlineToSelection
            sTaction = SetHeadlineToSelection( self.c, "Set Headline to Selection" )
            menu.add( sTaction )
            
        #@-node:orkman.20050210115438.3:headlineMenu
        #@+node:orkman.20050210115438.4:insertSR
        def insertSR( self, menu ):
                
            inSRMenuListener = leoSwingBody.Editor.inSRMenuListener
            menu.addMenuListener( inSRMenuListener(  menu, self.c ) )
        #@nonl
        #@-node:orkman.20050210115438.4:insertSR
        #@+node:orkman.20050210115751:addSR
        def addSR( self, menu ):
                
            class aa( swing.AbstractAction ):
                    
                def __init__( self, c ):
                    swing.AbstractAction.__init__( self, 'toggle <%s%s>' %( '<','>' ) )
                    self.c = c
                        
                def actionPerformed( self, event ):
                    cp = self.c.currentPosition()
                    hs = cp.headString()
                    hs = hs.strip()
                    if hs.startswith( '<%s'%'<' ) and hs.endswith( '>%s' %'>' ):
                        hs = hs[ 2: ]
                        hs = hs[ : -2 ]
                    else:
                        hs = '<%s%s%s>' %( '<', hs,'>' )
                    
                    self.c.beginUpdate()
                    cp.setHeadString( hs )
                    self.c.endUpdate()    
                
            menu.add( aa( self.c ) )      
        #@nonl
        #@-node:orkman.20050210115751:addSR
        #@+node:orkman.20050221210604:addLanguageMenu
        def addLanguageMenu( self, pmenu ):
            pass
        #@+at
        #     lmenu = swing.JMenu( "language" )
        #     kI = self.keywordInserter( lmenu, self.c )
        #     lmenu.addMenuListener( kI )
        #     pmenu.add( lmenu )
        #     lS = self.languageSetter( kI )
        #     pmenu.addMenuListener( lS )
        # 
        #@-at
        #@-node:orkman.20050221210604:addLanguageMenu
        #@+node:zorcanda!.20050502090502:addInsertPath
        def addInsertPath( self, menu ):
            
            def __insertHeadline( event ):
                
                jfc = swing.JFileChooser()
                jfc.setFileSelectionMode( jfc.DIRECTORIES_ONLY )
                jfc.setDialogTitle( "Select Directory for %s%s" % ( "@", "path" ) )
                jfc.setApproveButtonText( "Select" )
                result = jfc.showOpenDialog( self.c.frame.top )
                if result == jfc.APPROVE_OPTION:
                    sfile = jfc.getSelectedFile()
                    self.c.frame.body.insertAtInsertPoint( "%s %s" % ( "@path", sfile.getAbsolutePath() ) )
                    
            
            menu.actionPerformed = __insertHeadline
            
        
        #@-node:zorcanda!.20050502090502:addInsertPath
        #@+node:zorcanda!.20050602210537:addCompositeView
        def addCompositeView( self, event ):
            
            if not hasattr( self, 'lcv' ):
                import leoCompositeView
                jpanel = swing.JPanel( awt.BorderLayout() )
                #self.jtab.addTab( "CompositeView", jpanel )
                #self.jtab.setSelectedComponent( jpanel )
                self.tab_manager.add( "CompositeView", jpanel )
                self.lcv = lcv = leoCompositeView.CompositeView( self.c , jpanel )
                self.visible_informer.addCallback( jpanel, lambda : lcv.sync( force = 1 ) )
                self.body._current_editor = self.lcv.jtp
            else:
                parent = self.lcv.parent
                #if self.jtab.indexOfComponent( parent ) == -1:
                if not self.tab_manager.holdsComponent( parent ):
        
                    self.tab_manager.add( "CompositeView", parent )
                    #self.jtab.addTab( "CompositeView", parent )
                    #self.jtab.setSelectedComponent( parent )
                else:
                    #self.jtab.remove( parent )
                    self.tab_manager.remove( parent )
                    
        #@nonl
        #@-node:zorcanda!.20050602210537:addCompositeView
        #@+node:zorcanda!.20050617161327:addFlashCardView
        def addFlashCardView( self, event ):
            
            import leoFlashCardView
            if not hasattr( self, 'fcv' ):
                jpanel = swing.JPanel( awt.BorderLayout() )
                self.jtab.addTab( "FlashCardView", jpanel )
                self.jtab.setSelectedComponent( jpanel )
                self.fcv = fcv = leoFlashCardView.FlashCardView( self.c , jpanel )
                self.visible_informer.addCallback( jpanel, lambda : fcv.sync( force = 1 ) )
            else:
                parent = self.fcv.parent
                if self.jtab.indexOfComponent( parent ) == -1:
                    self.jtab.addTab( "FlashCardView", parent )
                    self.jtab.setSelectedComponent( parent )
                else:
                    self.jtab.remove( parent )
        #@-node:zorcanda!.20050617161327:addFlashCardView
        #@+node:zorcanda!.20051030202903:addFootNodeMenu
        def addFootNodeMenu( self, menu ):
            
            menu.addSeparator()
            addfn = swing.JMenuItem( "Add FootNode" )
            menu.add( addfn )
            rmvfn = swing.JMenu( "Remove FootNode" )
            menu.add( rmvfn )
            fnoderemover = self.footnoderemover( rmvfn, self.c )
            rmvfn.addMenuListener( fnoderemover )
            
            def addFootNode( event, c ):
                
                pos = c.currentPosition()
                t = pos.v.t
                if not hasattr( t, "unknownAttributes" ):
                    uas = t.unknownAttributes = {}
                    fn = []
                    uas[ "footnodes" ] = fn
                else:
                    uas = t.unknownAttributes
                    if uas.has_key( "footnodes" ):
                        fn = uas[ "footnodes" ]
                    else:
                        fn = []
                        uas[ "footnodes" ] = fn
                        
                jd = swing.JDialog()
                jd.title = "Add a FootNode"
                cpane = jd.getContentPane()
                cpane.setLayout( awt.BorderLayout() )
                jtf = swing.JTextField()
                tborder1 = sborder.TitledBorder( "Title" )
                jtf.setBorder( tborder1 )
                cpane.add( jtf, awt.BorderLayout.NORTH )
                jta = swing.JTextArea()
                jsp = swing.JScrollPane( jta )
                tborder2 = sborder.TitledBorder( "FootNode" )
                jsp.setBorder( tborder2 )
                cpane.add( jsp )
                jp = swing.JPanel()
                b1 = swing.JButton( "Cancel" )
                b1.actionPerformed = lambda event, jd = jd: jd.dispose()
                jp.add( b1 )
                b2 = swing.JButton( "Ok" )
                def ok( event, fn, jtf, jta, jd , c = c):
                    headline = jtf.getText()
                    body = jta.getText()
                    fn.append( ( headline, body ) )
                    c.frame.body.editor.ekit.relayout()
                    jd.dispose()
                b2.actionPerformed = lambda event, fn = fn, jtf = jtf, jta = jta, jd = jd, c = c: ok( event, fn, jtf, jta, jd,c  )    
                jp.add( b2 )
                cpane.add( jp, awt.BorderLayout.SOUTH )
                jd.size = ( 250, 250 )
                jd.preferredSize = ( 250, 250 )
                #jd.pack()
                g.app.gui.center_dialog( jd )
                jd.show()
            addfn.actionPerformed = lambda event, c = self.c: addFootNode( event, c )
        
                
                
                
                
                
        #@-node:zorcanda!.20051030202903:addFootNodeMenu
        #@-others
        #@nonl
        #@-node:orkman.20050210115438:menu methods
        #@+node:orkman.20050210115924:implementation of FocusListener interface
        def focusGained( self, fe ):
                
            lasteditor = self.body.editor
            self.body.editor = self
            if self.lastPosition:
                if lasteditor != self:
                    if self.chapter.isValid():
                        cc = self.c.chapters.getChapter()
                        if self.chapter != cc:
                            self.c.chapters.selectChapter( self.chapter )
                        
                        try:    
                            self.c.beginUpdate() #This part if not done right can cause weird tree sync issues
                            lp = self.lastPosition
                            self.lastPosition = None
                            self.c.frame.tree.select( lp )
                        finally:
                            self.c.endUpdate()
                    else:
                        self.sync()
        
            if hasattr( self, '_node_undoer' ):
                self._node_undoer.setMenu()
                
        def focusLost( self, fe ):
            
            self.chapter = self.c.chapters.getChapter()
            if hasattr( self, '_node_undoer' ):
                if self.lastPosition:
                    self._node_undoer.checkSumNode( self.lastPosition.v.t )
        #@-node:orkman.20050210115924:implementation of FocusListener interface
        #@+node:zorcanda!.20050307105645:detach and retach
        def detach( self, event = None ):
            
            self._parent2 = jf = swing.JFrame()
            bounds = self.frame.getBounds()
            self._parent.remove( self.frame )
            jf.getContentPane().add( self.frame )
            jf.setBounds( bounds )
            km = self.editor.getKeymap()
            k_and_a = self.c.frame.menu.keystrokes_and_actions
            for z in k_and_a.keys():
                action = k_and_a[ z ]
                km.addActionForKeyStroke( z, action )
            self._attached = False
            jf.visible = 1
            self._parent.validate()
            self._parent.repaint()
        
        
        def retach( self, event = None ):
            
            parent = self._parent2
            self._parent2 = None
            parent.remove( self.frame )
            self._parent.add( self.frame )
            parent.dispose()
            parent.visible = 0
            self._attached = True
            self._parent.validate()
            self._parent.repaint()
            self.frame.validate()
            self.frame.repaint()
            
            
        
        #@-node:zorcanda!.20050307105645:detach and retach
        #@+node:zorcanda!.20050516143406:turnSelectionIntoNode
        def turnSelectionIntoNode( self ):
            
            editor = self.editor
            txt = editor.getSelectedText()
            if txt == None: return
            spot = txt.find( '\n' )
            headline = txt[ :spot]
            editor.replaceSelection( "" )
            c = self.c
            c.beginUpdate()
            cp = c.currentPosition()
            np = cp.insertAsLastChild()
            np.setHeadString( headline )
            np.setBodyStringOrPane( txt )
            c.endUpdate()
        #@nonl
        #@-node:zorcanda!.20050516143406:turnSelectionIntoNode
        #@+node:zorcanda!.20050516143849:insertTextIntoBody
        def insertTextIntoBody( self, txt ):
            
            cpos = self.editor.getCaretPosition()
            start = swing.text.Utilities.getRowStart( self.editor, cpos )
            doc = self.editor.getStyledDocument()
            txt2 = doc.getText( start, cpos - start )
            start_text = []
            for z in txt2:
                if z.isspace():
                    start_text.append( z )
                else:
                    start_text.append( ' ' )
            
            indent = ''.join( start_text )
            
            lines = txt.split( '\n' )
            if len( lines ) > 1:
                for z in xrange( len( lines ) - 1 ):
                    line = lines[ z + 1 ]
                    nwline = "%s%s" %( indent, line )
                    lines[ z + 1 ] = nwline
            itext = '\n'.join( lines )
            doc.insertString( cpos, itext, None )
            
            
                    
                       
        
        #@-node:zorcanda!.20050516143849:insertTextIntoBody
        #@+node:zorcanda!.20050516160611:splitNode
        def splitNode( self ):
            
            c = self.c
            editor = self.editor
            cpos = editor.getCaretPosition()
            start = swing.text.Utilities.getRowStart( editor, cpos )
            doc = editor.getDocument()
            nn_txt = doc.getText( start, doc.getLength() - start ) 
            doc.remove( start, doc.getLength() - start )
            c.beginUpdate()
            cp = c.currentPosition()
            nn = cp.insertAfter()
            nn.setBodyStringOrPane( nn_txt )
            c.selectPosition( nn )
            c.endUpdate()
            
            dc = DefCallable( lambda : c.frame.tree.editLabel( nn ) )
            ft = java.util.concurrent.FutureTask( dc )
            java.awt.EventQueue.invokeLater( ft )
        #@-node:zorcanda!.20050516160611:splitNode
        #@+node:zorcanda!.20050516185304:sectionReferenceToWidget
        def sectionReferenceToWidget( self ):
            
            c = self.c 
            cp = c.currentPosition()
            bs = cp.bodyString()
            pattern = java.util.regex.Pattern.compile( "<"+"<" +"[^<>]*>"+">" )
            
            children = {}
            for z in cp.children_iter( copy = True ):
                children[ z.headString() ] = z
            
            
            matcher = pattern.matcher( java.lang.String( bs ) )
            results =[]
            while matcher.find():
                result = matcher.toMatchResult()
                results.append( result )
            
            doc = self.editor.getDocument()
            for z in results:
                begin = z.start()
                end = z.end()
                sr = bs[ begin: end ]
        #@+at
        #         if sr in children:
        #             jtp = swing.JTextArea()
        #             child = children[ sr ]
        #             jtp.setText( child.bodyString() )
        #             jb = swing.JButton( "Mooo" )
        #             mas = swing.text.SimpleAttributeSet()
        #             swing.text.StyleConstants.setComponent( mas, jb )
        #             swing.text.StyleConstants.setForeground( mas, 
        # java.awt.Color.RED )
        #             doc.setCharacterAttributes( begin, end - begin, mas, 1 )
        #             doc.insertString( 0, "\n", mas )
        #@-at
        #@@c
                    
            
            
            
        #@-node:zorcanda!.20050516185304:sectionReferenceToWidget
        #@+node:zorcanda!.20050926105453:chapterChanged
        def chapterChanged( self, tag, *args, **kwords ):
            
            try:
                chapter = args[ 0 ][ 'chapter' ]
                if tag == "chapter-changed":
                    if self.c.frame.body.editor is self:
                        cp = chapter.getCurrentPosition(); rp = chapter.getRootPosition()
                        if cp or rp:
                            self.sync()
                elif tag == "chapter-removed":
                    if self.c.frame.body.editor is self:
                        self.sync()
            except java.lang.Exception, x:
                pass
        #@-node:zorcanda!.20050926105453:chapterChanged
        #@+node:zorcanda!.20050927134320:headlineChanged
        def headlineChanged( self, tag, *args, **kwords ):
        
            p = args[ 0 ][ 'p' ]
            if self.lastPosition == p:
                self.frame.setTitle( p.headString() )
        
        #@-node:zorcanda!.20050927134320:headlineChanged
        #@+node:zorcanda!.20050618153212:splitting the editor
        #@+others
        #@+node:zorcanda!.20050618153212.1:splitVertically
        def splitVertically( self, event ):
            
            widget = self.editor
            parent = widget.getParent()
            
        #@-node:zorcanda!.20050618153212.1:splitVertically
        #@+node:zorcanda!.20050618153507:createEditor
        def createEditor( self ):
            
            editor = self.leoJTextPane( self.c )
            editor.setLineColor()
            manager = g.app.config.manager
            manager.addNotificationDef( "highlight_current_line", editor.setLineColor )
            manager.addNotificationDef( "current_line_highlight_color", editor.setLineColor )
            cdeterminer = cdeterminer = leoSwingBody.Editor.ColorKeywordsProvider( self.c )
        
            use_line_numbers = g.app.config.getBool( c, "use_line_numbering" )
            if use_line_numbers:
                #self.initializeLineNumbering()
                fg, bg, cl = self.getLineNumberColors()
                numbers = leoEditorKit.LeoNumberLabel( bg, fg, cl )
                #manager = g.app.config.manager
                #manager.addNotificationDef( "line_number_background", self.setLineNumberColors )
                #manager.addNotificationDef( "line_number_foreground", self.setLineNumberColors )
                #manager.addNotificationDef( "line_number_current", self.setLineNumberColors )
            else:
                numbers = None
            
            ekit = leoEditorKit( cdeterminer, numbers )
            editor.setEditorKit( ekit )
            cdeterminer.setEditor( editor )
            editor.getDocument().addUndoableEditListener( self.body ) 
            editor.addMouseListener( leoSwingBody.UtilityRightClick( c , detach_retach = True, editor = self ) ) 
               
            return editor
        #@nonl
        #@-node:zorcanda!.20050618153507:createEditor
        #@-others
        #@-node:zorcanda!.20050618153212:splitting the editor
        #@-others
        #@nonl
        #@-node:orkman.20050210114856:methods
        #@+node:orkman.20050210114856.1:helper classes
        #@+at
        # In general these are subclasses of java gui listeners.
        # 
        # In CPython and Tk you would be using callbacks most of the time, a 
        # def or a lambda.
        #@-at
        #@@c
        
        
        
        #@+others
        #@+node:orkman.20050203160852:recent visits -- allows the user to jump around recently visited nodes
        class RecentVisitsMenuListener( sevent.MenuListener ):
        
            def __init__( self, menu, c, recent ):
                self.menu = menu
                self.c = c   
                self.recent = recent
                        
            def menuCanceled( self, event ):
                pass
                        
            def menuDeselected( self, event ):
                pass
                        
            def menuSelected( self, event ):
                
                menu = self.menu       
                menu.removeAll()
                goNode = leoSwingBody.Editor.goNode
                for z in self.recent:
                    if z:
                        menu.add( goNode( z, self.c ) )
                  
        #@nonl
        #@-node:orkman.20050203160852:recent visits -- allows the user to jump around recently visited nodes
        #@+node:orkman.20050203154012:colorizer callback -- gives the View its info for colorization
        class ColorKeywordsProvider( leoEditorKit2.ColorDeterminer, sevent.DocumentListener ):
                 
            def __init__( self, c ):
                
        
                lb = leoLanguageManager.LanguageManager.getLanguageBundle( c )
                for z in dir( lb ):
                    if not callable( getattr( lb, z ) ):
                        setattr( self, z, getattr( lb, z ) )
                        
                self.c = c    
                self.last_p = None 
                self.last_language = None   
                self.editor = None    
                self.error_map = util.HashMap()
                fg, bg, cl = self.getLineNumberColors()
                self.line_fg = fg; self.line_bg = bg; self.line_cl = cl
                self.queue = concurrent.LinkedBlockingQueue()
                self.c.invisibleWatchers.append( self )
                return
        
                              
            def getOperators( self ):
                return util.HashMap()
                          
                    
            def getColoredTokens( self ):
                        
                        
                cp = self.c.currentPosition().copy()
                if cp != self.last_p:
                    #language = g.scanForAtLanguage( self.c, cp )
                    language = LeoUtilities.scanForLanguage( cp )
                    self.last_p = cp
                    self.last_language = language
                else:
                    language = self.last_language
                    
                leoLanguageManager.LanguageManager.setLanguageInEffect( self.c, language )
                
                if language == None:
                    language = "python"
                if hasattr( self, "%s_keywords" % language ):
                    return getattr( self, "%s_keywords" % language )
                else:
                    hm = leoLanguageManager.LanguageManager.loadLanguage( self.c, language )
                    setattr( self, "%s_keywords" % language, hm )
                    return hm
        
                
            def getCommentTokens( self ):
                
                cp = self.c.currentPosition().copy()
                if cp != self.last_p:
                    #language = g.scanForAtLanguage( self.c, cp )
                    language = LeoUtilities.scanForLanguage( cp )
                    self.last_p = cp
                    self.last_language = language
                else:
                    language = self.last_language
                if self.comment_cache.has_key( language ):
                    return self.comment_cache[ language ]
                else:
                    rv = g.set_delims_from_language( language )
                    rv = jarray.array( rv, java.lang.String )
                    self.comment_cache[ language ] = rv
                    return rv
                #delim1,delim2, delim3 = g.set_delims_from_language( language )
                #return [ delim1, delim2, delim3 ]
                     
            def underline( self ):
                return self._underline
            
            def getNumericColor( self ):
                return self._numericcolor
                
            def getUndefinedSectionReferenceColor( self ):
                return self._undefinedSectionNameColor
                
            def getSectionReferenceColor( self ):
                return self._sectionNameColor        
        
            def getStringColor( self ):
                return self._stringColor
                
            def getCommentColor( self ):
                return self._commentColor
             
            def getDocColor( self ):
                return self._docColor 
                
            def notify( self ):
                self.c.frame.body.editor.ekit.showInvisibles( self.c.showInvisibles )
            
            def showInvisibles( self ):
                return self.c.showInvisibles 
               
            def getInvisiblesBlock( self ):
                return self._invisibleBlock
            
            def getInvisiblesDot( self ):
                return self._invisibleDot
                
            def whichInvisible( self ):
                return self._which_invisible
                
            def getPunctuationColor( self ):
                return self._punctuationColor
                
            def getFoldedBackgroundColor( self ):
                return self._fbColor
                
            def getFoldedForegroundColor( self ):
                return self._ffColor
        
            
        
            def drawrectangle( self ):
                return self._drawrectangle
                
            def getRectangleColor( self ):
                return self._rectanglecolor
                
            def setEditor( self, editor ):
                self.editor = editor
                doc = editor.getDocument()
                doc.addDocumentListener( self )
                
                
            def insertUpdate( self, event):
                self.checkForLanguageChange( event )
            
            def removeUpdate( self, event):
                self.checkForLanguageChange( event )
        
                
            def checkForLanguageChange( self, event ):
                
                language = LeoUtilities.scanForLanguageOnLine( self.editor )
                if language:
                    #if not hasattr( self, "%s_keywords" % language ):
                    if self.last_language != language:
                        #self.editor.repaint()
                        self.last_language = language
                        jlc = self.c.frame.body.editor.jlc
                        jlc.fullrecolorize()
        
            
            
            def changedUpdate( self, event ):
                pass #this does Attribute changes
            
            
            def useLineNumbers( self ):
                return g.app.config.getBool( self.c, "use_line_numbering" )
                
            def getLineNumberForeground( self ):
                return self.line_fg
                
            def getCurrentLineNumberForeground( self ):
                return self.line_cl
                
            def getLineNumberBackground( self ):
                return self.line_bg
            
            #public boolean useLineNumbers();
            #public Color getLineNumberForeground();
            #public Color getCurrentLineNumberForeground();
            #public Color getLineNumberBackground();
            def getFootNodeBackgroundColor( self ):
                return self._fnbgColor
                
            def getFootNodeForegroundColor( self ):
                return self._fnfgColor
            
            
            def hasFootNodes( self ):
                
                cp = self.c.currentPosition()
                t = cp.v.t
                if hasattr( t, "unknownAttributes" ):
                    uas = t.unknownAttributes
                    if uas.has_key( "footnodes" ):
                        fn = uas[ "footnodes" ]
                        if fn: return True
                return False
                
            def getFootNodes( self ):
                
                cp = self.c.currentPosition()
                t = cp.v.t
                if hasattr( t, "unknownAttributes" ):
                    uas = t.unknownAttributes
                    if uas.has_key( "footnodes" ):
                        fn = uas[ "footnodes" ]
                        sb = java.lang.StringBuilder()
                        for z in fn:
                            sb.append( z[ 0 ] ).append( " : " ).append( z[ 1 ] )
                            if not z[ 1 ].endswith ( "\n" ): sb.append( "\n" )
                        return sb.toString()
                return ""
            
            #@    @+others
            #@+node:zorcanda!.20051030134638:getLineNumberColors
            def getLineNumberColors( self ):
                
                c = self.c
            
                bg = g.app.config.getColor( c, "line_number_background" )
                fg = g.app.config.getColor( c, "line_number_foreground" )
                cl = g.app.config.getColor( c, "line_number_current" )
                try:
                    bg = getColorInstance( bg )
                    if bg == None: bg = awt.Color.BLACK
                    fg = getColorInstance( fg )
                    if fg == None: fg = awt.Color.RED
                    cl = getColorInstance( cl )
                    if cl == None: cl = awt.Color.YELLOW
                except:
                    bg = awt.Color.BLACK
                    fg = awt.Color.RED
                    cl = awt.Color.YELLOW    
                return fg, bg, cl
            
            
                        
            #@-node:zorcanda!.20051030134638:getLineNumberColors
            #@-others
            
        
        #@-node:orkman.20050203154012:colorizer callback -- gives the View its info for colorization
        #@+node:orkman.20050202143632:class InsertTextIntoBody and relatives --gives menus insert functionality
        class InsertTextIntoBody( swing.AbstractAction ):
            
            def __init__( self, c, txt ):
                swing.AbstractAction.__init__( self, txt )
                self.txt = txt
                self.c = c
                
            def actionPerformed( self, event ):
                
                editor = self.c.frame.body.editor.editor 
                pos = editor.getCaretPosition()
                #editor.insert( self.txt, pos )
                doc = editor.getDocument()
                doc.insertString( pos, self.txt, None )
                
                
                
        class SetHeadline( InsertTextIntoBody ):
            
            def __init__( self, c,txt ):
                leoSwingBody.Editor.InsertTextIntoBody.__init__( self, c, txt )
                
            def actionPerformed( self, event ):
            
                cp = self.c.currentPosition()
                hS = cp.headString()
                newHeadString = "%s %s" %( self.txt, hS )
                cp.setHeadString( newHeadString )
                
                
        class SetHeadlineToSelection( InsertTextIntoBody  ):
            def __init__( self, c, txt ):
                leoSwingBody.Editor.InsertTextIntoBody.__init__( self, c, txt )
                
            def actionPerformed( self, event ):
                
                txt = self.c.frame.body.editor.editor.getSelectedText()
                if txt:
                    cp = self.c.currentPosition()
                    cp.setHeadString( txt )
                
                
                
        class rmvSymbol( swing.AbstractAction ):
            def __init__( self, c, symbol ):
                swing.AbstractAction.__init__( self, "remove %s" % symbol )
                self.c = c
                self.symbol = symbol
                
            def actionPerformed( self, event ):
                
                cp = self.c.currentPosition()
                hS = cp.headString()
                if hS.startswith( self.symbol ):
                    hS = hS.split()
                    hS = hS[ 1: ]
                    hS = " ".join( hS )
                    cp.setHeadString( hS )
                    
        
        
        class inSRMenuListener( sevent.MenuListener ):
        
            def __init__( self, menu, c ):
                self.menu = menu
                self.c = c   
                        
            def menuCanceled( self, event ):
                pass
                        
            def menuDeselected( self, event ):
                pass
                        
            def menuSelected( self, event ):
                
                menu = self.menu       
                menu.removeAll()
                cp = self.c.currentPosition()
                InsertTextIntoBody = leoSwingBody.Editor.InsertTextIntoBody
                for z in cp.children_iter():
                    hS = z.headString()
                    hS = hS.strip()
                    if hS.startswith( "<%s" % '<' ) and hS.endswith( ">%s" % ">" ):
                        menu.add( InsertTextIntoBody( self.c, hS ) )    
        
                    
                
                
        
        
        #@-node:orkman.20050202143632:class InsertTextIntoBody and relatives --gives menus insert functionality
        #@+node:orkman.20050208143204:resizer --keeps components sized right
        #@+at
        # class resizer( aevent.ComponentAdapter, sevent.ChangeListener ):
        #     '''This class keeps the Editor size in sync with the 
        # JLayeredPane.
        #        It also sets where the line numbers go and where, if present,
        #        a background image goes.'''
        #     def __init__( self, editor, side = 'Left' ):
        #         self.editor = editor
        #         self.viewPort = self.editor.view.getViewport()
        #         self.vsbar = self.editor.view.getVerticalScrollBar()
        #         self.side = side
        #     def componentResized( self, event ):
        #         source = event.getSource()
        #         size = source.getSize()
        #         editor = self.editor.editor
        #         esize = editor.getSize()
        #         editor = self.editor.editor
        #         visRect = self.viewPort.getViewRect() #was once 
        # getVisibleRect, bad choice...
        #         if self.editor.numbers:
        #             numbers = self.editor.numbers
        #             lnsize = numbers.getSize()
        #             if lnsize.width == 0: lnsize.width = 30
        #             nswidth = size.width - lnsize.width
        #             nvwidth = visRect.width - lnsize.width
        #             if esize.height != size.height or esize.width not in( 
        # nvwidth, nswidth ):
        #                 if visRect.width > 0:
        #                     size.width = nvwidth
        #                 else:
        #                     size.width = nswidth
        #                 editor.setSize( size )
        #                 if self.side == 'Left':
        #                     editor.setLocation( lnsize.width, 0 )
        #                 else:
        #                     editor.setLocation( 0, 0 )
        #                     numbers.setLocation( size.width, 0 )
        #             numsize = numbers.getSize()
        #             nlocation = numbers.getLocation()
        #             esize = editor.getSize()
        #             edheight = esize.height
        #             edwidth = esize.width
        #             lnsize.height = edheight
        #             if numsize.height < lnsize.height:
        #                 numbers.setSize( lnsize )
        #                 if self.side == 'Left':
        #                     numbers.setLocation( 0, 0 )
        #                 else:
        #                     numbers.setLocation( edwidth, 0 )
        #         else:
        #             self.editor.editor.setSize( size )
        #             self.editor.editor.setLocation( 0, 0 )
        #         if self.editor.background:
        #             self.stateChanged( None )
        # 
        # 
        #     def stateChanged( self, event ):
        #         editor = self.editor.editor
        #         background = self.editor.background
        #         #visRect = editor.getVisibleRect()
        #         visRect = self.viewPort.getViewRect()
        #         x = editor.getX()
        #         minus = x
        #         if x == 0 and self.editor.numbers != None:
        #             minus = self.editor.numbers.getSize().width
        #         background.setSize( visRect.width - minus, visRect.height )
        #         background.setLocation( x , visRect.y )
        #         self.editor.layeredpane.moveToBack( background )
        #@-at
        #@nonl
        #@-node:orkman.20050208143204:resizer --keeps components sized right
        #@+node:zorcanda!.20051106155505:resizer2
        class resizer2( aevent.ComponentAdapter ):
            
            def __init__( self, layoutmanager ):
                aevent.ComponentAdapter.__init__( self )
                self.layoutmanager = layoutmanager
                
            def componentResized( self, event ):        
                self.layoutmanager.layoutMedia()
        #@nonl
        #@-node:zorcanda!.20051106155505:resizer2
        #@+node:orkman.20050210115021:gonode -- actionPerformed takes user to node
        class goNode( swing.AbstractAction ):
            def __init__( self, pos, c ):
                swing.AbstractAction.__init__( self, pos.headString() )
                self.pos = pos.copy()
                self.c = c
                        
            def actionPerformed( self, event ):
                        
                self.c.frame.tree.select( self.pos )
        #@nonl
        #@-node:orkman.20050210115021:gonode -- actionPerformed takes user to node
        #@+node:orkman.20050210115021.1:outlinetraveler --allows the user to traverse the tree quickly
        class outlinetraveler( sevent.MenuListener ):
                    
            def __init__( self, menu, c ):
                self.menu = menu
                self.c = c   
                        
            def menuCanceled( self, event ):
                pass
                        
            def menuDeselected( self, event ):
                pass
                        
            def menuSelected( self, event ):
                         
                count = self.menu.getMenuComponentCount()
                for z in xrange( 1 , count ):
                    self.menu.remove( 1 )
                        
                cp = self.c.currentPosition()
                self._addMenu( "Parents", self.menu, cp.parents_iter(), cp )
                self._addMenu( "Siblings", self.menu, cp.siblings_iter(), cp )
                self._addMenu( "Children", self.menu, cp.children_iter(), cp )
                    
            def _addMenu( self, name, menu, iterator, cp ):
                        
                goNode = leoSwingBody.Editor.goNode
                gmenu = swing.JMenu( name )
                shouldAdd = True
                for z in iterator:
                    if shouldAdd:
                        if not cp == z:
                            shouldAdd = False
                            menu.add( gmenu )
                    if not cp == z:
                        gmenu.add( goNode( z, self.c ) )
                    else:
                        gmenu.addSeparator()
                                
        #@-node:orkman.20050210115021.1:outlinetraveler --allows the user to traverse the tree quickly
        #@+node:zorcanda!.20051030203433:footnoderemover
        class footnoderemover( sevent.MenuListener ):
                    
            def __init__( self, menu, c ):
                    self.menu = menu
                    self.c = c   
                        
            def menuCanceled( self, event ):
                pass
                        
            def menuDeselected( self, event ):
                pass
                        
            def menuSelected( self, event ):
                         
                self.menu.removeAll()
                #count = self.menu.getMenuComponentCount()
                #for z in xrange( 1 , count ):
                #    self.menu.remove( 1 )
                        
                pos = self.c.currentPosition()
                t = pos.v.t
                if hasattr( t, "unknownAttributes" ):
                    uas = t.unknownAttributes
                    if uas.has_key( "footnodes" ):
                        footnodes = uas[ "footnodes" ]
                        def rmv( item, footnodes = footnodes, c = self.c ):
                            footnodes.remove( item )
                            c.frame.body.editor.ekit.relayout()
                            
                        for x in xrange( len( footnodes ) ):
                            fnood = footnodes[ x ]
                            jmi = swing.JMenuItem( fnood[ 0 ] )
                            jmi.actionPerformed = lambda event, item = fnood: rmv( item )
                            self.menu.add( jmi )       
                                    
        #@-node:zorcanda!.20051030203433:footnoderemover
        #@+node:orkman.20050221211225:keywordInserter -- allows the user to insert language keywords
        #@+at
        # class keywordInserter( sevent.MenuListener ):
        #     def __init__( self, menu, c ):
        #         self.menu = menu
        #         self.c = c
        #         self.lastlanguage = None
        #     def setLanguageName( self ):
        #         cp = self.c.currentPosition()
        #         self.language = language = g.scanForAtLanguage( self.c, cp )
        #         self.menu.setText( language )
        #     def menuCanceled( self, event ):
        #         pass
        #     def menuDeselected( self, event ):
        #         pass
        #     def menuSelected( self, event ):
        #         #cp = self.c.currentPosition()
        #         #language = g.scanForAtLanguage( self.c, cp )
        #         language = self.language
        #         if language == self.lastlanguage: return
        #         self.lastlanguage = language
        #         print dir( leoLanguageManager.LanguageManager )
        #         if language == None:
        #             m = leoLanguageManager.LanguageManager.python_tokens
        #         else:
        #             m = getattr( leoLanguageManager.LanguageManager, 
        # "%s_tokens" % language )
        # 
        #         m.sort()
        #         self.menu.removeAll()
        #         for z in m:
        #             self._addInserter( z )
        #     def _addInserter( self, name  ):
        #         self.menu.add( leoSwingBody.Editor.InsertTextIntoBody( 
        # self.c, name ) )
        # 
        # class languageSetter( sevent.MenuListener ):
        #     def __init__( self, kWI ):
        #         self._kWI = kWI
        #     def menuCanceled( self, event ):
        #         pass
        #     def menuDeselected( self, event ):
        #         pass
        #     def menuSelected( self, event ):
        #         self._kWI.setLanguageName()
        #@-at
        #@-node:orkman.20050221211225:keywordInserter -- allows the user to insert language keywords
        #@+node:orkman.20050212174759:swingmacs help
        class smacs_help( swing.AbstractAction ):
                 
            class clz( swing.AbstractAction ):
                def __init__( self, tl ):
                    swing.AbstractAction.__init__( self, "Close" )
                    self.tl = tl
                    
                    
                def actionPerformed( self, event ):
                    self.tl.visible = 0
                    self.tl.dispose()         
           
            def __init__( self, c, emacs, which ):
                
                if which == 'Keystrokes':
                    swing.AbstractAction.__init__( self, "Emacs Keystrokes" )
                else:
                    swing.AbstractAction.__init__( self, "Emacs Commands" )
                   
                self.emacs = weakref.proxy( emacs )
                self.which = which
                fg = g.app.config.getColor( c, 'body_text_foreground_color' )
                bg = g.app.config.getColor( c, 'body_text_background_color' )
                sc = g.app.config.getColor( c, 'body_selection_color' )
                stc = g.app.config.getColor( c, 'body_text_selected_color' )
            
                self.fg = getColorInstance( fg, awt.Color.GRAY )
                self.bg = getColorInstance( bg, awt.Color.WHITE )
                self.sc = getColorInstance( sc, awt.Color.GREEN )
                self.stc = getColorInstance( stc, awt.Color.WHITE )
                        
            def actionPerformed( self, event ):
                
                tl = swing.JFrame( title = self.which )
                ta = swing.JTextArea()
                ta.setForeground( self.fg )
                ta.setBackground( self.bg )
                ta.setSelectionColor( self.sc )
                ta.setSelectedTextColor( self.stc )
                ta.setEditable( False )
                ta.setLineWrap( True )
                sp = swing.JScrollPane( ta )
                tl.getContentPane().add( sp )
                if self.which == 'Keystrokes':
                    ta.setText( self.emacs.getHelp() )
                else:
                    
                    ta.setText( self.emacs.ax.getCommandHelp() )
                gui = g.app.gui
                
                
                cbutt = swing.JButton( self.clz( tl ) )
                tl.getContentPane().add( cbutt, awt.BorderLayout.SOUTH )
                tkit = awt.Toolkit.getDefaultToolkit()
                size = tkit.getScreenSize()
                tl.setSize( size.width/2, size.height/2 )
                tl.setPreferredSize( tl.getSize() )
                x, y = g.app.gui._calculateCenteredPosition( tl )
                tl.setLocation( x, y )
                ta.setCaretPosition( 0 )
                tl.visible = 1
            
        
                
        #@nonl
        #@-node:orkman.20050212174759:swingmacs help
        #@+node:orkman.20050221150625:autocompleter help
        class autocompleter_help( swing.AbstractAction ):
                    
            def __init__( self ):
                swing.AbstractAction.__init__( self, "How to use the Autocompleter" )
                
            def getText( self ):
                
                htext = '''
                The Autcompleter appears upon typing of the '.' character.  Upon
                typing this character an in memory database is searched for the matching prefix.
                For example:
                    object.toString  appears in a node.
                    Typing 'object.' will bring the autocompleter box up with 'toString' as an option.
                               
                    Keystrokes that manipulate the autobox:
                    Ctrl - this inserts the currently selected word
                    Alt-Up, Alt-Down - these move the selection up and down.
                    Esc - desummons the autobox
                           
                The autobox will select the best prefix you have typed so far.  To extend the last example:
                typing 'to' will select 'toString'.  It will not enter the text until the user types 'Ctrl'
                or selects an item with the mouse.'''
                           
                return htext
                        
            def actionPerformed( self, event ):
                tl = swing.JFrame( title = 'Autocompleter Help' )
                ta = swing.JTextArea()
                ta.setEditable( False )
                sp = swing.JScrollPane( ta )
                tl.getContentPane().add( sp )
                #ta.setText( self.emacs.getHelp() )
                ta.setText( self.getText() )
                gui = g.app.gui
                tl.setSize( 600, 400 )
                spot = gui._calculateCenteredPosition( tl )
                tl.setLocation( spot[ 0 ], spot[ 1 ] )
                class clz( swing.AbstractAction ):
                    def __init__( self ):
                        swing.AbstractAction.__init__( self, "Close" )
                    def actionPerformed( self, event ):
                        tl.visible = 0
                        tl.dispose()
                cbutt = swing.JButton( clz() )
                tl.getContentPane().add( cbutt, awt.BorderLayout.SOUTH )
                tl.visible = 1
        #@nonl
        #@-node:orkman.20050221150625:autocompleter help
        #@+node:zorcanda!.20051028173920:class FoldProtector
        class FoldProtector( stext.DocumentFilter ):
            
            cachedfolds = {}
            
            def __init__( self , editor, ekit):
                stext.DocumentFilter.__init__( self )
                self.folds = []
                self.ekit = ekit
                self.editor = editor
                self.doc = editor.getDocument()
                self.editor.addMouseListener( self.Defolder( self )) 
                
            def cacheFolds( self, t ):
                if self.folds:
                    for z in self.folds:
                        z.persist( self.doc )
                    self.cachedfolds[ t ] = self.folds
            
            def defoldViews( self ):
                self.ekit.defoldViews()    
                
            def restoreFolds( self, t ):
                if self.cachedfolds.has_key( t ):
                    self.folds = self.cachedfolds[ t ]
                    doc = self.editor.getDocument()
                    for x in xrange( len(self.folds )):
                        z = self.folds[ x ]
                        if z.restore( doc ):
                            self.foldWithoutAdding( z.pos1, z.pos2 )
                        else:
                            self.folds.remove( z )
                            g.es( "Removing Fold(%s,%s), no longer valid" %( z.pos1, z.pos2 ), color = "red" )
                else:
                    self.folds = []
                
            def foldSelection( self ):
                
                start = self.editor.getSelectionStart()
                end = self.editor.getSelectionEnd()
                if start == end: return
                if start > end:
                    s1 = start
                    start = end
                    end = s1
                cp = self.editor.getCaretPosition()
                self.editor.setCaretPosition( cp )
                self.editor.moveCaretPosition( cp )
                paragraph1 = stext.Utilities.getParagraphElement( self.editor, start )
                paragraph2 = stext.Utilities.getParagraphElement( self.editor, end )
                self.fold( paragraph1.getStartOffset(), paragraph2.getEndOffset() -1  )
            
                
            def fold( self, start, end ):    
            
                fold = self.addFold( start, end, self.editor )
                self.ekit.fold( fold.pos1, fold.pos2 )
                start = fold.pos1.getOffset(); end = fold.pos2.getOffset()
                for z in copy.copy( self.folds ):
                    if z == fold: continue
                    test1 = z.pos1.getOffset()
                    test2 = z.pos2.getOffset()
                    if start <= test1 and end > test1:
                        self.folds.remove( z ) #the folds are now the same
                    
                
            def foldWithoutAdding( self, pos1, pos2 ):
                self.ekit.fold( pos1, pos2 )
            
            def areLinesInFold( self, start, end ):
                for z in self.folds:
                    start2 = z.pos1.getOffset()
                    end2 = z.pos2.getOffset()
                    if start2 <= start and end2 >= end: return True
                return False
                
            def doLinesIntersectFold( self, start, end ):
                
                doc = self.doc
                s = doc.getParagraphElement( start )
                e = doc.getParagraphElement( end )
                for z in self.folds:
                    p1 = doc.getParagraphElement( z.pos1.getOffset() )
                    p2 = doc.getParagraphElement( z.pos2.getOffset() )
                    while p1 != p2:
                        if p1 == e or p1 == s: return True
                        p1 = doc.getParagraphElement( p1.getEndOffset()) 
                    else:
                        if p1 == e or p1 == s: return True
                return False
                
            def areLinesSurroundingFold( self, start, end ):
                for z in self.folds:
                    start2 = z.pos1.getOffset()
                    end2 = z.pos2.getOffset()
                    if start <= start2 and end >= end2: return True
                return False
            
            def getFold( self, start, end ):
                for z in self.folds:
                    start2 = z.pos1.getOffset()
                    end2 = z.pos2.getOffset()
                    if start2 <= start and end2 >= end: return z
                return None
               
            def isFolded( self, x, y ):
                return self.ekit.isFolded( x, y )
                
            def isXInIconArea( self, x ):
                
                i = self.ekit.getFoldIconX()
                if i >= x: return True
                return False
            
            def removeFold( self, fold ):
                self.unfold( fold.pos1, fold.pos2 )
                self.folds.remove( fold )
            
            def unfold( self, pos1, pos2 ):
                self.ekit.unfold( pos1, pos2 )
                
            def unfoldSpot( self, x, y ):
                
                i = self.editor.viewToModel( awt.Point( x, y ) )
                for x in xrange( len( self.folds ) ):
                    z = self.folds[ x ]
                    if i >= z.pos1.getOffset() and i <= z.pos2.getOffset():
                        self.unfold( z.pos1, z.pos2 )
                        self.folds.remove( z )
                        break
            
            def addFold( self, start, end, editor ):
                
                doc = editor.getDocument()
                pos1 = doc.createPosition( start )
                pos2 = doc.createPosition( end )
                fold = self.Fold( pos1, pos2 )
                self.folds.append( fold )
                return fold
                
            def clearFolds( self ):
                self.folds = []            
                    
                
            #@    @+others
            #@+node:zorcanda!.20051030102939:DocumentFilter interface
            def insertString( self, fb, offset, data, attr):
                    
                if self.folds:
                    for x in xrange( len( self.folds ) ):
                        z = self.folds[ x ]
                        if not z.isInsertLegal( offset, fb.getDocument() ):
                            return
                                   
                fb.insertString( offset, data, attr )
                    
            def remove( self, fb, offset, length):
                    
                if self.folds:
                    for z in self.folds:
                        if not z.isRemoveLegal( offset, length , fb.getDocument() ):
                            return        
                fb.remove( offset, length )
                    
            def replace( self, fb, offset, length, text, attrs):
                    
                if self.folds:
                    for x in xrange( len( self.folds ) ):
                        z = self.folds[ x ]
                        if not z.isRemoveLegal( offset, length, fb.getDocument() ):
                            return
                fb.replace( offset, length, text, attrs )
            #@nonl
            #@-node:zorcanda!.20051030102939:DocumentFilter interface
            #@+node:zorcanda!.20051102145654:moveSelectionUp
            def moveSelectionUp( self ):
                
                start = self.editor.getSelectionStart()
                end = self.editor.getSelectionEnd() 
                if( self.areLinesSurroundingFold( start, end ) or self.doLinesIntersectFold( start, end ) ): return
                if start > end:
                    s1 = start
                    start = end
                    end = start
                doc = self.editor.getDocument()
                p1 = doc.getParagraphElement( start )
                p2 = doc.getParagraphElement( end )
                above = doc.getParagraphElement( p1.getStartOffset() -1 )
                #@    <<move partial selection>>
                #@+node:zorcanda!.20051102181315:<<move partial selection>>
                if p1.getStartOffset() != start or p2.getEndOffset() -1 != end:
                    cp = self.editor.getCaretPosition()
                    cpstart = True
                    if cp == end:
                        cpstart = False
                    txt = doc.getText( start, end - start )
                    if not txt.endswith( "\n" ): txt = txt + "\n"
                    self.editor.replaceSelection( "" )
                    pstart = p1.getStartOffset()
                    doc.insertString( p1.getStartOffset() , txt, None )
                    para = doc.getParagraphElement( pstart )
                    para2 = doc.getParagraphElement( pstart + len( txt ) -1 )
                    if cpstart:
                        self.editor.setCaretPosition( para2.getEndOffset() -1 )
                        self.editor.moveCaretPosition( para.getStartOffset() )       
                    else:
                        self.editor.setCaretPosition( para.getStartOffset() )
                        self.editor.moveCaretPosition( para2.getEndOffset() -1 )      
                    return
                #@nonl
                #@-node:zorcanda!.20051102181315:<<move partial selection>>
                #@nl
                    
                if( self.areLinesInFold( above.getStartOffset(), above.getEndOffset() -1 ) ):
                    cp = self.editor.getCaretPosition()
                    cpstart = True
                    if cp == end:
                        cpstart = False
                    fold = self.getFold( above.getStartOffset(), above.getEndOffset() -1 )
                    self.removeFold( fold )
                    fstart = fold.pos1.getOffset()
                    fend = fold.pos2.getOffset()
                    txt = doc.getText( start, end - start )
                    txt2 = doc.getText( fstart, fend - fstart )
                    if txt2.endswith( "\n" ): txt2 = txt2[ : -1 ]
                    doc.remove( fstart, end - fstart )
                    nwtxt = "%s\n%s" %( txt, txt2 )
                    doc.insertString( fstart, nwtxt, None )
                    self.fold( fstart + len( txt ) +1 , end )
                    para = doc.getParagraphElement( fstart )
                    para2 = doc.getParagraphElement( fstart + len( txt ) )
                    if cpstart:
                        self.editor.setCaretPosition( para2.getEndOffset() -1 )
                        self.editor.moveCaretPosition( para.getStartOffset() )       
                    else:
                        self.editor.setCaretPosition( para.getStartOffset() )
                        self.editor.moveCaretPosition( para2.getEndOffset() -1 ) 
                    
                else:
                    cp = self.editor.getCaretPosition()
                    cpstart = True
                    if cp == end:
                        cpstart = False
                    txt = doc.getText( start, end  - start )
                    sstart = above.getStartOffset()
                    txt2 = doc.getText( sstart, above.getEndOffset() - sstart )
                    if txt2.endswith( "\n" ): txt2 = txt2[ : - 1 ]
                    doc.remove( sstart, end - sstart)
                    txt3 = "%s\n%s" % ( txt, txt2 )
                    doc.insertString( sstart, txt3, None )
                    para = doc.getParagraphElement( sstart )
                    para2 = doc.getParagraphElement( sstart + len( txt ) )
                    if cpstart:
                        self.editor.setCaretPosition( para2.getEndOffset() -1 )
                        self.editor.moveCaretPosition( para.getStartOffset() )       
                    else:
                        self.editor.setCaretPosition( para.getStartOffset() )
                        self.editor.moveCaretPosition( para2.getEndOffset() -1 ) 
            
            
            #@-node:zorcanda!.20051102145654:moveSelectionUp
            #@+node:zorcanda!.20051102181044:moveSelectionDown
            def moveSelectionDown( self ):
            
                start = self.editor.getSelectionStart() 
                end = self.editor.getSelectionEnd()
                if( self.areLinesSurroundingFold( start, end ) or self.doLinesIntersectFold( start, end ) ): return
                if start > end:
                    s1 = start
                    start = end
                    end = start 
                doc = self.editor.getDocument()
                p1 = doc.getParagraphElement( start )
                p2 = doc.getParagraphElement( end )
                below = doc.getParagraphElement( p2.getEndOffset() )
                #@    <<move partial selection>>
                #@+node:zorcanda!.20051102181315.1:<<move partial selection>>
                if p1.getStartOffset() != start or p2.getEndOffset() -1 != end:
                    cp = self.editor.getCaretPosition()
                    cpstart = True
                    if cp == end:
                        cpstart = False
                    txt = doc.getText( start, end - start )
                    if not txt.endswith( "\n" ): txt = txt + "\n"
                    self.editor.replaceSelection( "" )
                    pend = p2.getEndOffset()
                    doc.insertString( p2.getEndOffset() , txt, None )
                    para = doc.getParagraphElement( pend + 1 )
                    para2 = doc.getParagraphElement( pend + len( txt ) -1 )
                    if cpstart:
                        self.editor.setCaretPosition( para2.getEndOffset() -1 )
                        self.editor.moveCaretPosition( para.getStartOffset() )       
                    else:
                        self.editor.setCaretPosition( para.getStartOffset() )
                        self.editor.moveCaretPosition( para2.getEndOffset() -1 )
                        
                    return
                #@nonl
                #@-node:zorcanda!.20051102181315.1:<<move partial selection>>
                #@nl
                if( self.areLinesInFold( below.getStartOffset(), below.getEndOffset() ) ):
                    cp = self.editor.getCaretPosition()
                    cpstart = True
                    if cp == end:
                        cpstart = False
                    fold = self.getFold( below.getStartOffset(), below.getEndOffset() )
                    self.removeFold( fold )
                    fstart = fold.pos1.getOffset()
                    fend = fold.pos2.getOffset()
                    txt = doc.getText( start, end - start )
                    txt2 = doc.getText( fstart, fend - fstart )
                    if txt2.endswith( "\n" ): txt2 = txt2[ : -1 ]
                    doc.remove( start, (fold.pos2.getOffset() - start ) )
                    nwtxt = "%s\n%s" %( txt2, txt )
                    doc.insertString( start, nwtxt, None )
                    self.fold( start , start + len( txt2 ) )
                    para = doc.getParagraphElement( start + len( txt2 ) + 1 )
                    para2 = doc.getParagraphElement( start + len( txt2 ) + 1 + len( txt ) )
                    if cpstart:
                        self.editor.setCaretPosition( para2.getEndOffset() - 1 )
                        self.editor.moveCaretPosition( para.getStartOffset() )       
                    else:
                        self.editor.setCaretPosition( para.getStartOffset() )
                        self.editor.moveCaretPosition( para2.getEndOffset() -1 )            
                else:
                    cp = self.editor.getCaretPosition()
                    cpstart = True
                    if cp == end:
                        cpstart = False
                    txt = doc.getText( start, end  - start )
                    sstart = below.getStartOffset()
                    txt2 = doc.getText( sstart, below.getEndOffset() - sstart )
                    if txt2.endswith( "\n" ): txt2 = txt2[ : -1 ]
                    doc.remove( start, ( below.getEndOffset() - start )-1)
                    txt3 = "%s\n%s" % ( txt2, txt )
                    doc.insertString( start, txt3, None )
                    para = doc.getParagraphElement( start + len( txt2 ) + 1 )
                    para2 = doc.getParagraphElement( start + len( txt2 ) + 1 + len( txt ) )
                    if cpstart:
                        self.editor.setCaretPosition( para2.getEndOffset() -1 )
                        self.editor.moveCaretPosition( para.getStartOffset() )       
                    else:
                        self.editor.setCaretPosition( para.getStartOffset() )
                        self.editor.moveCaretPosition( para2.getEndOffset() -1 )
            #@nonl
            #@-node:zorcanda!.20051102181044:moveSelectionDown
            #@+node:zorcanda!.20051030100043:class Fold
            class Fold:
                def __init__( self, pos1, pos2 ):
                    self.pos1 = pos1
                    self.pos2 = pos2
                    self.text = None
                        
                def persist( self, doc ):
                    self.pos1 = self.pos1.getOffset()
                    self.pos2 = self.pos2.getOffset()
                    self.text = doc.getText( self.pos1, self.pos2 - self.pos1 )
                        
                def restore( self, doc ):
                    p1,p2 = self.pos1, self.pos2
                    if doc.getLength() < p2:
                        return False
                    self.pos1 = doc.createPosition( self.pos1 )
                    self.pos2 = doc.createPosition( self.pos2 )
                    pelement1 = doc.getParagraphElement( p1 )
                    pelement2 = doc.getParagraphElement( p2 )
                    if pelement1.getStartOffset() != p1 or pelement2.getEndOffset() -1 != p2:
                        return False
                    testtext = doc.getText( p1, p2 - p1 )
                    text = self.text; self.text = None
                    return text == testtext
                        
                def isInsertLegal( self, offset, doc ):
                    
                    e = doc.getParagraphElement( offset )
                    p1 = doc.getParagraphElement( self.pos1.getOffset() )
                    p2 = doc.getParagraphElement( self.pos2.getOffset() )
                    if p1 == e or p2 == e: return False
                    while p1 != p2:
                        if p1 == e: return False
                        p1 = doc.getParagraphElement( p1.getEndOffset()) 
                    else:
                        if p1 == e: return False
                    return True
                        
                def isRemoveLegal( self, offset, length, doc ):
                    
                    p1 = doc.getParagraphElement( self.pos1.getOffset() )
                    p2 = doc.getParagraphElement( self.pos2.getOffset() )       
                    start = doc.getParagraphElement( offset )
                    end = doc.getParagraphElement( offset + length )
                    if start == p1 or start == p2: return False
                    if end == p1 or end == p2: return False
                    while start != end:
                        if start == p1 or start == p2: return False
                        start = doc.getParagraphElement( start.getEndOffset() )
                    else:
                        if start == p1 or start == p2: return False
                                
                    return True
            #@-node:zorcanda!.20051030100043:class Fold
            #@+node:zorcanda!.20051030100043.1:class Defolder
            class Defolder( aevent.MouseAdapter ):
                def __init__( self, fp ):
                    aevent.MouseAdapter.__init__( self )
                    self.fp = fp
                        
                def mouseClicked( self, event ):
                        
                    x = event.getX()
                    y = event.getY()
                    if event.getButton() == event.BUTTON1:
                        if self.fp.isFolded( x, y ) and self.fp.isXInIconArea( x ):
                            self.fp.unfoldSpot( x, y )
            #@nonl
            #@-node:zorcanda!.20051030100043.1:class Defolder
            #@-others
                
                        
                    
                
                
                    
        #@nonl
        #@-node:zorcanda!.20051028173920:class FoldProtector
        #@+node:zorcanda!.20050417172937:CommanderCommander
        class CommanderCommander:
            
            def __init__( self, c , emacs, menu ):
                
                self.c = c
                self.emacs = weakref.proxy( emacs )
                f = c.frame 
                self.nodes = {}
                self.mode = 0
                self.tab_completer = None
                self.last_command = None
                self.name = "CommanderCommander"
                self.setupCommands( menu )
                self.addHelp()
                
            
            def getAltXCommands( self ):
                return self.commands.keys()
                
            def __call__( self, event ,command ):
                
                if self.mode == 1:
                    if command == 'Enter':
                        self.gotoNode2( event )
                        self.last_command = None
                        #self.emacs.keyboardQuit( event )
                        return True
                    elif command == 'Tab' and self.tab_completer:
                    
                        txt = self.emacs.minibuffer.getText()
                        if self.last_command == None or not txt.startswith( self.last_command ):
                            txt = self.emacs.minibuffer.getText()
                            fnd = self.tab_completer.lookFor( txt )
                            if fnd:
                                self.last_command = txt
                                self.emacs.minibuffer.setText( self.tab_completer.getNext() )
                        else :
                            self.emacs.minibuffer.setText( self.tab_completer.getNext() )
                        return True
                    else:
                        self.emacs.eventToMinibuffer( event )
                        return True
                    
                quit = self.commands[ command ]()
                if quit == None:
                    self.emacs.keyboardQuit( event )
                return True
                
            def getName( self ):
                return self.name
            
            #@    @+others
            #@+node:zorcanda!.20050417193853:setupCommands
            def setupCommands( self, menu ):
                
                c = self.c
                f = c.frame
                self.commands = menu.names_and_commands
                self.commands[ "goto node" ] = self.gotoNode1
                
            
            
            def addHelp( self ):
                
                addhelp =  [ 'Menu Commands:',
                             '-----------------',
                		         'You can execute any Menu command by entering its text',
                             'in the minibuffer.  For example:',
                             'Alt-x',
                             'Open Python Window',
                             '',
                             'will open a Python Window.  See Menus for complete list.',
                             '',
                             '',
                             'Additional Commands:',
                             '---------------------',
                             'These are Leo based commands.',
                             '',
                             'goto node --- will ask the user for which node to goto',
                             'and will take the user to it.' ] #we don't do triple strings because it doesn't format right because of Leo output
                addhelp = "\n".join( addhelp )
                self.emacs.addCommandHelp( addhelp )
            #@nonl
            #@-node:zorcanda!.20050417193853:setupCommands
            #@+node:zorcanda!.20050417193740:gotoNode1
            def gotoNode1( self ):
                    
                self.nodes = {}
                cp = self.c.currentPosition()
                for z in cp.allNodes_iter( copy = True ):
                    hs = z.headString()
                    if self.nodes.has_key( hs ):
                        self.nodes[ hs ].append( z )
                    else:
                        self.nodes[ hs ] = [ z, ]
                self.tab_completer = self.emacs.TabCompleter( self.nodes.keys() )
                       
                self.emacs.setCommandText( "Goto Which Node:" )
                self.emacs.minibuffer.setText( "" )
                self.emacs._stateManager.setState( self )
                self.mode = 1
                return True
            #@nonl
            #@-node:zorcanda!.20050417193740:gotoNode1
            #@+node:zorcanda!.20050417193740.1:gotoNode2
            def gotoNode2( self , event ):
                    
                self.mode = 0
                self.tab_completer = None
                node = self.emacs.minibuffer.getText()
                self.emacs.keyboardQuit( event )
                if self.nodes.has_key( node ):
                    c = self.c
                    c.beginUpdate()
                    nlist = self.nodes[ node ]
                    if len( nlist ) > 1:
                        jf = swing.JDialog()
                        jf.setLayout( awt.BorderLayout() )
                        jf.setModal( True )
                        jf.title = "Choose a Node"
                        table = swing.JTable()
                        table.setSelectionMode( swing.ListSelectionModel.SINGLE_SELECTION )
                        table.setAutoResizeMode( table.AUTO_RESIZE_OFF )
                        class kl( aevent.KeyAdapter ):
                            def keyPressed( self, event ):
                                if event.getKeyCode() == event.VK_ENTER:
                                    jf.dispose()
                        
                        table.addKeyListener( kl() )
                        jsp = swing.JScrollPane( table )
                        jf.add( jsp, awt.BorderLayout.CENTER )
                        dtm = table.getModel()
                        dtm.addColumn( "Node" )
                        dtm.addColumn( "Level" )
                        dtm.addColumn( "Parents" )
                        longest_parents = "Parents"
                        for z in nlist:
                            row = []
                            row.append( z.headString() )
                            row.append( z.level() )
                            ps = ""
                            p = z.getParent()
                            while p:
                                ps = "%s -->%s" %( p.headString(), ps )
                                p = p.getParent()
                            row.append( ps )
                            if len( ps ) > len( longest_parents) : longest_parents = ps
                            dtm.addRow( row )
                        
                        table.setColumnSelectionAllowed( False )
                        table.setRowSelectionInterval( 0, 0 )
                        cm = table.getColumn( "Node" )
                        fm = table.getFontMetrics( table.getFont() )
                        w = fm.stringWidth( z.headString() )
                        cm.setPreferredWidth( w )
                        
                        cm = table.getColumn( "Level" )
                        w = fm.stringWidth( "Level" )
                        cm.setPreferredWidth( w )
                        
                        cm = table.getColumn( "Parents" )
                        w = fm.stringWidth( longest_parents )
                        cm.setPreferredWidth( w )
                        
                        
                        height = table.getRowHeight()
                        size = jsp.getPreferredSize()
                        size.height = height * 6
                        jsp.setPreferredSize( size )    
                        cb = swing.JButton( "Select" )
                        cb.actionPerformed = lambda event: jf.dispose()
                        p = swing.JPanel()
                        p.add( cb )
                        jf.add( p , awt.BorderLayout.SOUTH )
                        jf.pack()
                        g.app.gui.center_dialog( jf )
                        jf.show()
                        sr = table.getSelectedRow()
                        if sr != -1:
                            c.selectPosition( nlist[ sr ] )
                        
                        
                    else:
                        c.selectPosition( nlist[ 0 ] )
                    c.endUpdate()
                else:
                    self.emacs.setCommandText( "%s does not exits" % node )      
                self.nodes = {}     
            #@nonl
            #@-node:zorcanda!.20050417193740.1:gotoNode2
            #@-others
            
        #@-node:zorcanda!.20050417172937:CommanderCommander
        #@+node:zorcanda!.20050225092920:BracketHighlighter
        class BracketHighlighter( sevent.ChangeListener, sevent.DocumentListener ):
            
            #@    @+others
            #@+node:zorcanda!.20050225104055:__init__
            def __init__( self, editor, c ): #, color ):
            
                self._jtc = editor
                self.c = c
                self._jtc.getDocument().addDocumentListener( self )
                self.highlight_painter = None #stext.DefaultHighlighter.DefaultHighlightPainter( color )
                self.highlighting = False
                self.tag = None
                self.iFind = False
                self.matchers = { '{' : ( '{', '}' ),
                                      '}' : ( '{', '}' ),
                                      '(' : ( '(', ')' ),
                                      ')' : ( '(', ')' ),
                                      '[' : ( '[', ']' ),
                                      ']' : ( '[', ']' ),
                                      '<' : ( '<', '>' ),
                                      '>' : ( '<', '>' ),
                                      }
                                      
                self._nomatch = ( None, None )
                self.match_bracket = 0
                self.setBracketMatch()
                manager = g.app.config.manager
                wm1 = WeakMethod( self, "setBracketMatch" )
                manager.addNotificationDef( "highlight_brackets", wm1 )
                manager.addNotificationDef( "highlight_brackets_color", wm1 )
                
            
            #@-node:zorcanda!.20050225104055:__init__
            #@+node:zorcanda!.20050225104234:DocumentListener interface
            def changedUpdate( self, event ):
                pass
                    
            def insertUpdate( self, event ):
                    
                doc = event.getDocument()
                len = event.getLength()
                where = event.getOffset()
                self.findBracket( where, doc, doc.getLength() )
                self.iFind = True
                    
            def removeUpdate( self, event ):
                pass  
            #@nonl
            #@-node:zorcanda!.20050225104234:DocumentListener interface
            #@+node:zorcanda!.20050225104234.1:ChangeListener interface
            def stateChanged( self, event ):
                    
                jtc = self._jtc
                dot = jtc.getCaretPosition()
                doc = jtc.getDocument()
                dlen = doc.getLength()
                self.findBracket( dot, doc, dlen )
            #@nonl
            #@-node:zorcanda!.20050225104234.1:ChangeListener interface
            #@+node:zorcanda!.20050225104055.1:findBracket
            def findBracket( self, dot, doc, dlen ):
                
                if not self.match_bracket: return
                jtc = self._jtc
                highlighter = jtc.getHighlighter()
                if self.iFind:
                    self.iFind = False
                    return
                if self.highlighting:
                    highlighter.removeHighlight( self.tag )
                    self.highlighting = False
                        
                if dot >= dlen:
                    return
                else:
                    c = doc.getText( dot, 1 )
                    first, last = self.matchers.get( c, self._nomatch )
                    if not first: return
                    if c == first:
                        txt = jtc.getText()
                        i = self.forwardFind( txt[ dot: ], first, last ) #we must include the first bracket for the find functions
                        if i != -1:
                            self.tag = highlighter.addHighlight( dot + i, dot + i + 1, self.highlight_painter )
                            self.highlighting = True
                    elif c == last:
                            
                        txt = jtc.getText( 0, dot + 1 )#we must include the first bracket for the find functions
                        i = self.backwardFind( txt, first, last  )
                        if i != -1:
                            self.tag = highlighter.addHighlight( i, i +1, self.highlight_painter )
                            self.highlighting = True
            #@-node:zorcanda!.20050225104055.1:findBracket
            #@+node:zorcanda!.20050225104437:forwardFind
            def forwardFind( self, txt, first, last ):
                    
                fbc = 0
                for z in xrange( len( txt ) ):
                    c = txt[ z ]
                    if c == first:
                        fbc += 1
                        continue
                    elif c == last:
                        if fbc:
                            fbc -=1
                        if not fbc:
                            return z
                                
                return -1
            #@nonl
            #@-node:zorcanda!.20050225104437:forwardFind
            #@+node:zorcanda!.20050225104437.1:backwardFind
            def backwardFind( self, txt, first, last ):
                    
                fbc = 0
                tlen = len( txt )
                tnum = tlen - 1
                for z in xrange( tlen ):
                    c = txt[ tnum ]        
                    if c == last:
                        fbc +=1
                    elif c == first:
                        if fbc:
                            fbc -= 1
                        if not fbc:            
                            return tnum
                    tnum -= 1
                return -1    
            #@nonl
            #@-node:zorcanda!.20050225104437.1:backwardFind
            #@+node:zorcanda!.20050530191454:setBracketMatch
            def setBracketMatch( self, notification=None, handback = None ):
            
                c = self.c
                if g.app.config.getBool( c, "highlight_brackets" ):
                    col = g.app.config.getColor( c, "highlight_brackets_color" )
                    color = getColorInstance( col , awt.Color.GREEN )
                    self.highlight_painter = stext.DefaultHighlighter.DefaultHighlightPainter( color )
                    self.match_bracket = 1
                else:
                    self.match_bracket = 0
                
            #@nonl
            #@-node:zorcanda!.20050530191454:setBracketMatch
            #@-others
            
                
        
        #@-node:zorcanda!.20050225092920:BracketHighlighter
        #@-others
        #@nonl
        #@-node:orkman.20050210114856.1:helper classes
        #@+node:orkman.20050213132705:component classes
        #@+node:orkman.20050208161218:autolistener --does autocompleter work
        class autolistener( sevent.DocumentListener, aevent.KeyAdapter ):
            
            watchwords = {}
            
            def __init__( self, editor ):
                self.watchwords = leoSwingBody.Editor.autolistener.watchwords
                self.watchitems = ( '.',')' )
                self.txt_template = '%s%s%s'
                okchars ={}
                for z in string.ascii_letters:
                    okchars[z] = z 
                okchars['_'] = '_'
                self.okchars = okchars
                self.editor = editor
                self.jeditor = editor.editor
                self.popup = None
                #self.layeredpane = editor.layeredpane
                self.haveseen = {}
                #self.autobox = None
                self.constructAutobox()
                self.on = 0
                wm1 = WeakMethod( self, "initialScan" )
                leoPlugins.registerHandler(('start2','open2'), wm1 )         
            
            
            #@    @+others
            #@+node:orkman.20050213123146:helper classes
            #@+others
            #@+node:orkman.20050213123146.1:hider and boxListener
            class inserter( aevent.MouseAdapter ):
                
                def __init__( self, autolistener ):
                    self.autolistener = autolistener
                    
                def mouseReleased( self, event ):
                    self.autolistener.insertFromAutoBox()
                    
                    
            class hider( aevent.MouseWheelListener ):
                
                def __init__( self, autolistener ):
                    self.autolistener = autolistener
                    
                def mouseWheelMoved( self, event ):
                    if self.autolistener.autobase.isShowing():
                        self.autolistener.hideAutoBox()
            
            
            #@-node:orkman.20050213123146.1:hider and boxListener
            #@-others
            #@nonl
            #@-node:orkman.20050213123146:helper classes
            #@+node:orkman.20050213122648:constructAutobox
            def constructAutobox( self ):
                
                #import AutoPanel
                jp = swing.JPanel()
                #jp = AutoPanel()
                gbl = awt.GridBagLayout()
                gbc = awt.GridBagConstraints()
                gbc.fill = 1
                jp.setLayout( gbl )
                jlist = swing.JList( swing.DefaultListModel() )
                jlist.setName( "Autolist" )
                jlist.setFont( self.editor.editor.getFont() )
                self.jsp = jsp = swing.JScrollPane( jlist )
                gbl.setConstraints( jsp, gbc )
                jp.add( jsp )
                self.autobox = jlist 
                self.autobase = jp   
                self.autobox.addMouseListener( self.inserter( self ) )
                self.jeditor.addMouseWheelListener( self.hider( self ) )
            
            #@-node:orkman.20050213122648:constructAutobox
            #@+node:orkman.20050208172240:processKeyStroke/keyPressed
            def keyPressed( self, event ): #aka key process keyStroke
                '''c in this def is not a commander but a Tk Canvas.  This def determine what action to take dependent upon
                   the state of the canvas and what information is in the Event'''
                #if not c.on:return None #nothing on, might as well return
                
                if not self.on: return
                if not self.autobase.isShowing(): return #isVisible just determines if the thing should be visible, not if it is.  isShowing does.
                
                
                modifiers = event.getModifiers()
                mtxt = event.getKeyModifiersText( modifiers )
                ktxt = event.getKeyText( event.getKeyCode() )
                keysym = '%s %s' %( mtxt, ktxt )
                keysym = keysym.strip()
                if keysym == "shift" :
                    return
                    
                elif keysym == "Backspace":
                    pos = self.jeditor.getCaretPosition()
                    doc = self.jeditor.getDocument()
                    if pos != 0:
                        c = doc.getText( pos - 1, 1 )
                        if c == '.':
                            return self.hideAutoBox()
            
            
                elif self.testForUnbind( keysym ): #all of the commented out code is being tested in the new testForUnbind def or moved above.
                    #unbind( context )
                    self.hideAutoBox()
                    return None
                #elif event.keysym in("Shift_L","Shift_R"):
                #    #so the user can use capital letters.
                #    return None 
                #elif not c.which and event.char in ripout:
                #    unbind( c )
                #elif context.which==1:
                #    #no need to add text if its calltip time.
                #    return None 
                #ind = body.index('insert-1c wordstart')
                #pat = body.get(ind,'insert')+event.char 
                #pat = pat.lstrip('.')
                doc = self.jeditor.getDocument()
                pos = self.jeditor.getCaretPosition()
                try:
                    txt = doc.getText( 0, pos )
                except:
                    return
                txt_lines = txt.splitlines()
                
                if len( txt_lines ) > 1:
                    txt_line = txt_lines[ -1 ]
                else:
                    txt_line = txt_lines[ 0 ]
                pat = txt_line.split( '.' )
                if len( pat ) > 1:
                    pat = pat[ -1 ]
                else:
                    pat = pat[ 0 ]
                
                #print keysym
                if keysym == 'Ctrl Ctrl':
                   return self.processAutoBox( event, pat )
                 
                if keysym in ( "Alt Up", "Alt Down" ):
                    event.consume()
                    return self.moveUpDown( keysym )
                
                kchar = event.getKeyChar()
                if kchar == event.CHAR_UNDEFINED: return
                else:
                    pat = pat + kchar
                autobox = self.autobox
                lm = autobox.getModel()
                ww = []
                index = None
                for z in xrange( lm.getSize() ):
                    item = lm.getElementAt( z )
                    if item.startswith( pat ):
                            index = z
                            break
                    #ww.append( lm.getElementAt( z ) )
            
                #autobox = context.autobox
                #ww = list( autobox.get( 0, 'end' ) )
                #lis = self.reducer(ww,pat)
                #if len(lis)==0:return None #in this section we are selecting which item to select based on what the user has typed.
                #i = ww.index(lis[0])
            
                #lm.clear()
                #autobox.setListData( lis )
                if index != None:
                    autobox.clearSelection()
                    autobox.setSelectedIndex( index )
                    autobox.ensureIndexIsVisible( index )
                    
                #autobox.select_clear( 0, 'end' ) #This section sets the current selection to match what the user has typed
                #autobox.select_set( i )
                #autobox.see( i )
                #return 'break'
            
            #@-node:orkman.20050208172240:processKeyStroke/keyPressed
            #@+node:orkman.20050208175258:processAutoBox
            def processAutoBox(self, event, pat ):
                '''This method processes the selection from the autobox.'''
                #if event.keysym in("Alt_L","Alt_R"):
                #    return None 
            
                #a = context.autobox.getvalue()
                a = self.autobox.getSelectedValue()
                #if len(a)==0:return None 
                if not a: self.hideAutoBox()
                try:
                    #a = a[0]
                    #ind = body.index('insert-1c wordstart')
                    #pat = body.get(ind,'insert')
                    #pat = pat.lstrip('.')
            
                    if a.startswith(pat): a = a[len(pat):]
                    doc = self.jeditor.getDocument()
                    doc.insertString( self.jeditor.getCaretPosition(), a , None )
                    self.hideAutoBox()
                    #self.editor.insert 
                    #body.insert('insert',a)
                    #body.event_generate("<Key>")
                    #body.update_idletasks()
                except java.lang.Exception, x:
                    x.printStackTrace()
                    #self.editor.hideAutoBox()
                    #unbind( context )
            #@-node:orkman.20050208175258:processAutoBox
            #@+node:orkman.20050208185646:moveUpDown
            def moveUpDown( self, code ):
                
                autobox = self.autobox
                i = autobox.getSelectedIndex()
                if code == 'Alt Up':
                    i2 = i -1
                else:
                    i2 = i + 1
                
                lm = autobox.getModel()
                if i2 < 0 or i2 + 1 > lm.getSize():
                    return
                else:
                    autobox.setSelectedIndex( i2 )
                    autobox.ensureIndexIsVisible( i2 )
            #@nonl
            #@-node:orkman.20050208185646:moveUpDown
            #@+node:orkman.20050208171040:testForUnbind
            def testForUnbind( self, keysym  ):
                '''c in this case is a Tkinter Canvas.
                  This def checks if the autobox or calltip label needs to be turned off'''
                  
                if keysym in ('parenright','parenleft', 'Escape', 'Space', 'Enter', 'Tab', 'Up', 'Down' ) or keysym.isspace():
                    return True
                #elif not context.which and event.char in ripout:
                #    return True
                return False
            #@-node:orkman.20050208171040:testForUnbind
            #@+node:orkman.20050213133132:DocumentListener implementation
            #@+others
            #@+node:orkman.20050208161218.1:changedUpdate
            def changedUpdate( self, event ):
                pass
                    
            #@-node:orkman.20050208161218.1:changedUpdate
            #@+node:orkman.20050208161218.2:insertUpdate
            def insertUpdate( self, event ):
                
                if not self.on: return
                doc = event.getDocument()
                change = doc.getText( event.getOffset(), event.getLength() )
                if change=='.':
                    self.watcher( event )
                    
                    
            
            #@-node:orkman.20050208161218.2:insertUpdate
            #@+node:orkman.20050208161218.3:removeUpdate
            def removeUpdate( self, event ):
                '''originally I wanted to do a remove of the autobox on a backspace of '.' but this couldnt be detected adequately
                and had to be put in the Key handling code of the autocompleter.'''
                pass
                    
            #@-node:orkman.20050208161218.3:removeUpdate
            #@-others
            #@nonl
            #@-node:orkman.20050213133132:DocumentListener implementation
            #@+node:orkman.20050208161859:watcher
            watchitems = ( '.',')' )
            txt_template = '%s%s%s'
            def watcher ( self, event):
                '''A function that tracks what chars are typed in the Text Editor.  Certain chars activate the text scanning
                   code.'''
                #global lang 
                doc = event.getDocument()
                txt = doc.getText( event.getOffset(), event.getLength() )
                if txt.isspace() or txt in self.watchitems:
                    #bCtrl = event.widget
                    #This if statement ensures that attributes set in another node
                    #are put in the database.  Of course the user has to type a whitespace
                    # to make sure it happens.  We try to be selective so that we dont burn
                    # through the scanText def for every whitespace char entered.  This will
                    # help when the nodes become big.
                    #if event.char.isspace():
                    #    if bCtrl.get( 'insert -1c' ).isspace(): return #We dont want to do anything if the previous char was a whitespace
                    #    if bCtrl.get( 'insert -1c wordstart -1c') != '.': return
                        
                    #c = bCtrl.commander
                    #lang = c.frame.body.getColorizer().language 
                    #txt = txt_template %( bCtrl.get( "1.0", 'insert' ), 
                    #                     event.char, 
                    #                     bCtrl.get( 'insert', "end" ) ) #We have to add the newest char, its not in the bCtrl yet
                    txt =  doc.getText( 0, doc.getLength() ) 
                    self.scanText(txt)
                    self.determineToShow( event )
                
            #@-node:orkman.20050208161859:watcher
            #@+node:orkman.20050208161922:scanText
            def scanText ( self, txt):
                '''This function guides what gets scanned.'''
            
                #if useauto:
                self.scanForAutoCompleter(txt)
                #if usecall:
                #    scanForCallTip(txt)
            #@-node:orkman.20050208161922:scanText
            #@+node:orkman.20050208161952:scanForAutoCompleter
            def scanForAutoCompleter ( self, txt):
                '''This function scans text for the autocompleter database.'''
                t1 = txt.split('.')
                g =[]
                reduce(lambda a,b: self.makeAutocompletionList(a,b,g),t1)
                if g:
                    for a, b in g:
                        if self.watchwords.has_key(a):
                            self.watchwords[a][ b ] = None
                        else:
                            self.watchwords[ a ] = { b: None }
                            #watchwords[a] = sets.Set([b])
                            #watchwords[ a ] = util.Hash
                        #watchwords[ a ].add( b ) # we are using the experimental DictSet class here, usage removed the above statements
                        #notice we have cut it down to one line of code here!
            #@nonl
            #@-node:orkman.20050208161952:scanForAutoCompleter
            #@+node:orkman.20050208162011:makeAutocompletionList
            def makeAutocompletionList ( self, a,b,glist):
                '''A helper function for autocompletion'''
                a1 = self._reverseFindWhitespace(a)
                if a1:
                    b2 = self._getCleanString(b)
                    if b2!='':
                        glist.append((a1,b2))
                return b 
            #@-node:orkman.20050208162011:makeAutocompletionList
            #@+node:orkman.20050208162022:_getCleanString
            def _getCleanString ( self, s ):
                '''a helper for autocompletion scanning'''
                if s.isalpha():return s 
            
                #for n, l in enumerate(s):
                for n in xrange( len( s ) ):
                    l = s[ n ]
                    if l in self.okchars:pass 
                    else:return s[:n]
                return s 
            #@-node:orkman.20050208162022:_getCleanString
            #@+node:orkman.20050208162112:_reverseFindWhitespace
            def _reverseFindWhitespace ( self, s):
                '''A helper for autocompletion scan'''
                #for n, l in enumerate(s):
                for n in xrange( len( s ) ):
                    l = s[ n ]
                    n =(n+1)*-1
                    if s[n].isspace()or s[n]=='.':return s[n+1:]
                return s 
            #@-node:orkman.20050208162112:_reverseFindWhitespace
            #@+node:orkman.20050208170610:reducer
            def reducer ( self, lis,pat):
                '''This def cuts a list down to only those items that start with the parameter pat, pure utility.'''
                return[x for x in lis if x.startswith(pat)]
            #@-node:orkman.20050208170610:reducer
            #@+node:orkman.20050208164920:determineToShow
            def determineToShow( self, event ):
                
                doc = event.getDocument()
                txt = doc.getText( 0, event.getOffset() )
                txt_list = txt.splitlines()
                if not txt_list: return
                txt_line = txt_list[ - 1 ]
                txt_splitdots = txt_line.split( '.' )[ -1 ]
                txt_final = txt_splitdots.split()
                if txt_final:
                    txt_final = txt_final[ -1 ]
                if txt_final and self.watchwords.has_key( txt_final ):
                    completers = self.watchwords[ txt_final ].keys()
                    completers.sort()
                    self.getAutoBox( completers )
                
            #@-node:orkman.20050208164920:determineToShow
            #@+node:orkman.20050213133238:startup time scanning
            #@+others
            #@+node:orkman.20050208184530:initialScan
            def initialScan ( self, tag,keywords):
                '''This method walks the node structure to build the in memory database.'''
                c = keywords.get("c")or keywords.get("new_c")
                haveseen = self.haveseen 
                if haveseen.has_key(c):
                    return 
            
                haveseen[c] = None 
                
                #This part used to be in its own thread until problems were encountered on Windows 98 and XP with g.es
                #pth = os.path.split(g.app.loadDir)  
                #aini = pth[0]+r"%splugins%sautocompleter.ini" % ( os.sep, os.sep )    
                #if not os.path.exists(aini):
                #    createConfigFile( aini )
                #try:
                #    if not hasReadConfig():
                #        if os.path.exists(aini):
                #            readConfigFile(aini) 
                #
                #        bankpath = pth[0]+r"%splugins%sautocompleter%s" % ( os.sep, os.sep, os.sep )
                #        readLanguageFiles(bankpath)#This could be too expensive to do here if the user has many and large language files.
                #finally:
                #    setReadConfig()
                
                # Use a thread to do the initial scan so as not to interfere with the user.
                #_self = self
                #class scanner( java.lang.Thread ):          
                #def run( self ):
                #    _self.readOutline( c )
                #    #g.es( "This is for testing if g.es blocks in a thread", color = 'pink' )
                #    #readOutline( c )
                
                dc = DefCallable( lambda : self.readOutline( c ) )
                g.app.gui.addStartupTask( dc )
                
            
            
            #@-node:orkman.20050208184530:initialScan
            #@+node:orkman.20050208184621:readOutline
            def readOutline ( self, c):
                '''This method walks the Outline(s) and builds the database from which
                autocompleter draws its autocompletion options
                c is a commander in this case'''
                #global lang
                #if 'Chapters'in g.app.loadedPlugins: #Chapters or chapters needs work for this function properly again.
                #    import chapters 
                #    it = chapters.walkChapters()
                #     for x in it:
                #        lang = None 
                #        setLanguage(x)
                #        scanText(x.bodyString())
                #else:
                for z in c.rootPosition().allNodes_iter( copy = True):
                    #self.scanText( z.bodyString() )
                    rvalues = LeoUtilities.scanForAutoCompleter( z.v.t._bodyString )
                    if rvalues:
                        for z in rvalues:
                            a,b = z
                            if self.watchwords.has_key(a):
                                self.watchwords[a][ b ] = None
                            else:
                                self.watchwords[ a ] = { b: None }
            
                    
                    
                g.es( "Autocompleter ready" )
            #@-node:orkman.20050208184621:readOutline
            #@-others
            #@nonl
            #@-node:orkman.20050213133238:startup time scanning
            #@+node:orkman.20050213133206:get, hide and insert AutoBox
            #@+others
            #@+node:orkman.20050213114844:getAutoBox
            def getAutoBox( self, completers ):
                    
                jlist = self.autobox
                jp = self.autobase
                if len( completers ) < 5:
                    jlist.setVisibleRowCount( len( completers ) )
                else:
                    jlist.setVisibleRowCount( 5 )
                
                model = jlist.getModel()
                model.removeAllElements() #by working with the model we dont burn a new object each time.
                for z in completers:
                    model.addElement( z )
                jlist.setSelectedIndex( 0 )
                jlist.ensureIndexIsVisible( 0 )
                jlist.setValueIsAdjusting( True )
            
                
                cur = self.jeditor.getCaretPosition()
                pos = self.jeditor.modelToView( cur )    
                size = self.editor.view.getViewport().getViewRect()
                pos = swing.SwingUtilities.convertRectangle( self.jeditor, pos, self.editor.epane )
                size.x = 0; size.y = 0;
            
            
                jlist.setSize( jlist.getPreferredSize() )#the discrepency between the two was causing weird drawing bugs.  This appears to have rectified it.
                #Its very important that the setSize call happens before the self.jsp.getPreferredSize call, or it may not calculate right.
                jsps = self.jsp.getPreferredSize()
                jp.setSize( jsps )  
                rx = ry = 0
                if pos.x > (size.x + size.height)/2:
                    rx = pos.x - jsps.width
                else: rx = pos.x
                
                if pos.y > ( size.y + size.height )/2:
                    ry = pos.y - jsps.height
                else: ry = pos.y + pos.height
                
                point = awt.Point( rx, ry )
                swing.SwingUtilities.convertPointToScreen( point, self.editor.view.getViewport() )
                popupfactory = swing.PopupFactory().getSharedInstance()
                self.popup = popup = popupfactory.getPopup( self.editor.editor, jp, point.x, point.y )
                popup.show()
            
            
            
            
            
            
            #@-node:orkman.20050213114844:getAutoBox
            #@+node:orkman.20050213115020:hideAutoBox
            def hideAutoBox( self ):
            
                if self.popup:
                    self.popup.hide();self.popup = None
            
            
            #@-node:orkman.20050213115020:hideAutoBox
            #@+node:orkman.20050213123146.2:insertFromAutobox
            def insertFromAutoBox( self ):
                        
                autobox = self.autobox
                value = autobox.getSelectedValue()
                pos = self.jeditor.getCaretPosition()
                self.jeditor.getDocument().insertString( pos, value, None )
                self.hideAutoBox()
            #@nonl
            #@-node:orkman.20050213123146.2:insertFromAutobox
            #@-others
            #@nonl
            #@-node:orkman.20050213133206:get, hide and insert AutoBox
            #@-others
                
        #@-node:orkman.20050208161218:autolistener --does autocompleter work
        #@+node:zorcanda!.20050224092411:Carets
        #@+node:zorcanda!.20050224092411.1:UnderlinerCaret
        class UnderlinerCaret( stext.DefaultCaret ):
            '''This Caret creates a see through colored box over the current character.'''
            def __init__( self, color ):
                stext.DefaultCaret.__init__( self )
                #ti = java.lang.Integer.decode( "#FFFFC6" );
                #c = awt.Color( ti );
                #self._bg = awt.Color.RED
                self._bg = color
                #self._bg = awt.Color( c.getRed(), c.getGreen(), c.getBlue(), 50 ); 
                self.setBlinkRate( 0 ) #no blinking please
        
                
            def paint( self, g ):
        
                com = self.super__getComponent()
                dot = self.getDot()
                pos = com.getCaretPosition()
                view = com.modelToView( pos )
        
                if( self.x != view.x or self.y != view.y ): 
                    self.super__repaint()
                    self.x = view.x
                    self.y = view.y 
                    self.width = self.calculateCharacterWidth( g ) + 1 #Its important to be a little wider
                    self.height = view.height + 1                      #And a little taller than the box, or redraws will leave traces
                    
        
                if self.isVisible():
                    g.setColor( self._bg )
                    #g.fillRect( self.x, self.y, self.width - 1, view.height )
                    g.drawLine( self.x  , self.y + self.height - 1, self.x + self.width - 1, self.y + self.height - 1 )
                self.setMagicCaretPosition( awt.Point( self.x, self.y ) )
                
            def calculateCharacterWidth( self, g ):
                '''This method allows the see-through box to have the same width as the character'''
        
                com = self.super__getComponent()
                fm = g.getFontMetrics()
                
                pos = com.getCaretPosition()
                len = com.getDocument().getLength()
                if pos >= len:
                    c = ' '
                else:
                    c = com.getText( pos, 1 )
                if java.lang.Character.isWhitespace( c ): c = ' '
                
                return swing.SwingUtilities.computeStringWidth( fm, c )
                
        
                
                
                
            def damage( self, r ):
                
                if r == None: return
                
                self.x = r.x
                self.y = r.y
                com = self.super__getComponent()
                pos = com.getCaretPosition()
                view = com.modelToView( pos )
                graphics = com.getGraphics()
                self.width = self.calculateCharacterWidth( graphics ) + 1
                graphics.dispose()
                self.height = view.height + 1;
                self.super__repaint()
                self.setMagicCaretPosition( awt.Point( self.x, self.y ) )
        #@nonl
        #@-node:zorcanda!.20050224092411.1:UnderlinerCaret
        #@+node:orkman.20050218102048:SeeThroughBoxCaret
        class SeeThroughBoxCaret( stext.DefaultCaret ):
            '''This Caret creates a see through colored box over the current character.'''
            def __init__( self, color ):
                stext.DefaultCaret.__init__( self )
                #ti = java.lang.Integer.decode( "#FFFFC6" );
                #c = awt.Color( ti );
                #c = awt.Color.RED
                self._bg = awt.Color( color.getRed(), color.getGreen(), color.getBlue(), 50 ); 
                self.setBlinkRate( 0 ) #no blinking please
        
                
            def paint( self, g ):
                
                com = self.super__getComponent()
                dot = self.getDot()
                pos = com.getCaretPosition()
                view = com.modelToView( pos )
                if( self.x != view.x or self.y != view.y ): 
                    self.super__repaint()
                    self.x = view.x
                    self.y = view.y 
                    self.width = self.calculateCharacterWidth( g ) + 1 #Its important to be a little wider
                    self.height = view.height + 1                      #And a little taller than the box, or redraws will leave traces
                    
        
                if self.isVisible():
                    g.setColor( self._bg )
                    g.fillRect( self.x, self.y, self.width - 1, view.height)
        
                self.setMagicCaretPosition( awt.Point( self.x, self.y ) )
                
            def calculateCharacterWidth( self, g ):
                '''This method allows the see-through box to have the same width as the character'''
        
                if not g: return 0
                com = self.super__getComponent()
                doc = com.getDocument()
                pos = com.getCaretPosition()
                len = doc.getLength()
                if pos >= len:
                    c = ' '
                else:
                    c = com.getText( pos, 1 )
                
                e = doc.getCharacterElement( pos ) 
                atts = e.getAttributes()
                f = doc.getFont( atts )
                if f:
                    g.setFont( f )
                fm = g.getFontMetrics()
                
                if java.lang.Character.isWhitespace( c ): c = ' '
                
                return swing.SwingUtilities.computeStringWidth( fm, c )
                
        
                
                
                
            def damage( self, r ):
                
                if r == None: return
                
                self.x = r.x
                self.y = r.y
                com = self.super__getComponent()
                pos = com.getCaretPosition()
                view = com.modelToView( pos )
                graphics = com.getGraphics()
                self.width = self.calculateCharacterWidth( graphics ) + 1
                if graphics:
                    graphics.dispose()
                self.height = view.height + 1;
                self.super__repaint()
                self.setMagicCaretPosition( awt.Point( self.x, self.y ) )
                
        #@-node:orkman.20050218102048:SeeThroughBoxCaret
        #@+node:zorcanda!.20050224101513:GhostlyLeoCaret
        import java.awt.image as aim
        class GhostlyLeoCaret( stext.DefaultCaret ):
            '''This Caret creates a see through colored box over the current character.'''
            def __init__( self ):
                stext.DefaultCaret.__init__( self )
                
                self.setBlinkRate( 0 ) #no blinking please
                self._image = leoSwingBody.Editor.icon.getImage()
                self._im_height = self._image.getHeight() + 1
                self._im_width = self._image.getWidth() + 1
                self._ac = awt.AlphaComposite.getInstance( awt.AlphaComposite.SRC_OVER, .2 )
                self._bgc = None
            
                
            def paint( self, g ):
        
                com = self.super__getComponent()
                if self._bgc == None:
                    self._bgc == g.getColor()
                dot = self.getDot()
                pos = com.getCaretPosition()
                view = com.modelToView( pos )
        
                if( self.x != view.x or self.y != view.y ): 
                    self.super__repaint()
                    self.x = view.x
                    self.y = view.y      
                    self.width = self._im_width
                    self.height = self._im_height               
                    
        
                if self.isVisible():
        
                    if not self.isWhiteSpace( g ):
                        g.setComposite( self._ac )
                    g.drawImage( self._image, self.x, self.y, self._bgc, None )
                self.setMagicCaretPosition( awt.Point(  self.x, self.y ) )
                
            def isWhiteSpace( self, g ):
                '''This method allows the see-through box to have the same width as the character'''
        
                com = self.super__getComponent()
                v1 = com.viewToModel( awt.Point( self.x, self.y ) )
                v2 = com.viewToModel( awt.Point( self.x + self.width, self.y ) )
                vlen = v2 - v1
                len = com.getDocument().getLength()
                if v1 >= len:
                    c = ' '
                else:
                    c = com.getText( v1, vlen )
                if c.isspace() or c =='' : c = ' '
                return c == ' '
                
        
                
                
                
            def damage( self, r ):
                
                if r == None: return
                
                self.x = r.x
                self.y = r.y
                self.height = self._im_height
                self.width = self._im_width
                self.super__repaint()
                self.setMagicCaretPosition( awt.Point(self.x, self.y) )
        #@-node:zorcanda!.20050224101513:GhostlyLeoCaret
        #@+node:zorcanda!.20050307092917:ImageCaret
        class ImageCaret( GhostlyLeoCaret ):
            
            def __init__( self, image ):
                leoSwingBody.Editor.GhostlyLeoCaret.__init__( self )
                self._image = image
                self._im_height = self._image.getHeight() + 1
                self._im_width = self._image.getWidth() + 1
                
            
        #@-node:zorcanda!.20050307092917:ImageCaret
        #@-node:zorcanda!.20050224092411:Carets
        #@+node:orkman.20050221152400:leoJTextPane
        class leoJTextPane( swing.JTextPane):
                
            def __init__( self, c ):
                swing.JTextPane.__init__( self )
                self.c = c
                self.last_rec = None
                self._bg = None
                
            def setLineColor( self, notification = None, handback = None ):
                
                c = self.c
                if g.app.config.getBool( c, "highlight_current_line" ):
                    hc = g.app.config.getColor( c, "current_line_highlight_color" )
                    color = getColorInstance( hc, awt.Color.ORANGE )
                    self._bg = awt.Color( color.getRed(), color.getGreen(), color.getBlue(), 50 )
                else:
                    self._bg = None 
                    self._last_rec = None
                self.repaint()
            
        #@+at        
        #     def paintComponent( self , graphics ):
        #         if 0:
        #             paint = graphics.getPaint()
        #             color = self.getBackground()
        #             c1 = awt.Color.RED
        #             c2 = awt.Color.GREEN
        #             vrect = self.getVisibleRect()
        #             gp = awt.GradientPaint( vrect.x, vrect.y, c1, vrect.x + 
        # vrect.width, vrect.y + vrect.height, c2 )
        #             graphics.setPaint( gp )
        #             graphics.fillRect( vrect.x, vrect.y, vrect.width, 
        # vrect.height )
        #             graphics.setPaint( paint )
        #@-at
        #@@c
        
            def paintComponent( self , graphics ):
                            
                self.super__paintComponent( graphics )
                if self._bg:
                    cpos = self.getCaretPosition()#from here
                    try:
                        rec = self.modelToView( cpos )
                    except java.lang.Exception, x:
                        x.printStackTrace()
                        return
                    sz = self.getVisibleRect()
                    rec = awt.Rectangle( sz.x, rec.y, sz.width, rec.height )#to here: these calculate the colored background. 
                    if self.last_rec and not self.last_rec.equals( rec ): #its not the same spot we must repaint!
                        if self.last_rec.width < rec.width:
                            self.last_rec.width = rec.width
                        self.repaint( self.last_rec )
            
                
                    c = graphics.getClip()
                    rintersect = rec.intersects( c )
                    if not rec.equals( self.last_rec ) or rintersect:
                        if self.last_rec:
                            if rec.y != self.last_rec.y or rec.height != self.last_rec.height:
                                rintersect = 0
                        if rintersect:
                            graphics.setColor( self._bg ) #if we intersect we only repaint a small portion. This reduces flicker.
                            graphics.fill( rec )
                        else:
                            g2 = self.getGraphics()
                            g2.setColor( self._bg ) #if we dont we repaint all of it.
                            g2.fill( rec )
                            g2.dispose()
                
                
                    self.last_rec = rec
        
                
        #@-node:orkman.20050221152400:leoJTextPane
        #@+node:zorcanda!.20051105174008:leoImageJPanel
        class leoImageJPanel( swing.JPanel ):
            
            def __init__( self, layoutmanager):
                swing.JPanel.__init__( self, layoutmanager )
                self.image = None
                self.backedWidget = None
                self.last_image = None
                self.alpha = awt.AlphaComposite.getInstance( awt.AlphaComposite.SRC_OVER, 1.0 ) 
                self.lastDimensions = awt.Rectangle( 0, 0, 0, 0 )
                
            def setBackedWidget( self, widget ):
                self.backedWidget = widget
                
            def setImage( self, image ):
                self.image = image
                
            def setAlpha( self, alpha ):
                self.alpha = awt.AlphaComposite.getInstance( awt.AlphaComposite.SRC_OVER, alpha ) 
                
            def paintComponent( self, graphics ):
                
                self.super__paintComponent( graphics )
                if self.backedWidget and self.image:
                    vrec = self.backedWidget.getVisibleRect()
                    rec2 = swing.SwingUtilities.convertRectangle( self.backedWidget, vrec, self )
                    if not self.lastDimensions.equals( vrec ):
                        self.lastDimensions = vrec
                        self.last_image = self.image.getScaledInstance( rec2.width, rec2.height, awt.Image.SCALE_REPLICATE )
                    composite = graphics.getComposite()
                    graphics.setComposite( self.alpha )
                    graphics.drawImage( self.last_image, rec2.x, rec2.y, awt.Color.WHITE, None )
                    graphics.setComposite( composite )
                
        #@nonl
        #@-node:zorcanda!.20051105174008:leoImageJPanel
        #@+node:zorcanda!.20051106145426:leoLayoutManager
        class leoLayoutManager( awt.LayoutManager ):
            
            
            def __init__( self ):
                self.jscrollpane = None
                self.minibuffer = None
                self.media = None
                
                
                
            def addLayoutComponent( self, name, component ):
                pass
                
            
            def layoutContainer( self, container ):
        
                size = container.getSize()
                if self.minibuffer:
                    mbpsize = self.minibuffer.getPreferredSize()
                else:
                    mbpsize = awt.Rectangle( 0, 0, 0, 0 )
                
                if self.jscrollpane:
                    self.jscrollpane.setBounds( 0, 0, size.width, size.height - mbpsize.height )
                    if self.minibuffer:
                        self.minibuffer.setBounds( 0, size.height - mbpsize.height, size.width, mbpsize.height )
                    
                if self.media and self.jscrollpane:
                    vp = self.jscrollpane.getViewport()
                    vr = vp.getBounds()
                    self.media.setBounds( vr )
                    
            def layoutMedia( self ):
                if self.media and self.jscrollpane:
                    vp = self.jscrollpane.getViewport()
                    vr = vp.getBounds()
                    self.media.setBounds( vr )        
            
            def minimumLayoutSize( self, container ):       
                return container.getMinimumSize()
                
            
            def preferredLayoutSize( self, container ):
                return container.getPreferredSize()
                
                
            def removeLayoutComponent( self, container ):
                pass        
                    
        #@nonl
        #@-node:zorcanda!.20051106145426:leoLayoutManager
        #@-node:orkman.20050213132705:component classes
        #@-others
        #@nonl
        #@-node:orkman.20050212183628:helper methods and classes
        #@-others
                        
    
            
            
    
    #@-node:orkman.20050202102136:class Editor -- contains the code that makes and controls editors
    #@+node:orkman.20050202110639:UtilityRightClick--for adding new Editors and to cut,copy and paste
    class UtilityRightClick( aevent.MouseAdapter ):
        
        
        def __init__( self, c, detach_retach = False, editor = None ):
            aevent.MouseAdapter.__init__( self )
            self.c = c
            self.editor = weakref.proxy( editor )
            self._detach_retach = detach_retach
        
        
        #@    @+others
        #@+node:zorcanda!.20050307213649:mousePressed
        def mousePressed( self, mE ):
                        
            if mE.getClickCount() == 1:
                if mE.getButton() == mE.BUTTON3:
                    x = mE.getX()
                    y = mE.getY()
                    
                    
                    popup = swing.JPopupMenu()
        
        
                    UtilityAction = leoSwingBody.UtilityAction
                    AddEditor = leoSwingBody.AddEditor
                    InsertNode = leoSwingBody.InsertNode            
                    frame = self.c.frame
                    for z in ( ( "Cut", self.editor.editor.cut ), ( "Copy", self.editor.editor.copy ), 
                                ( "Paste", self.editor.editor.paste ), # frame.OnPaste ), 
                                ( "Delete", self.c.delete  ),
                                ):
                        popup.add( UtilityAction( z[ 0 ], z[ 1 ] ) )
                    
                    
                    popup.addSeparator()
                    popup.add( UtilityAction( "Turn Selection Into Node", self.editor.turnSelectionIntoNode ))
                    inmenu = swing.JMenu( "Insert Node Into Body" )
                    inmenu.addMenuListener( InsertNode( inmenu, self.c, UtilityAction ) )
                    popup.add( inmenu )
                    
                    popup.add( UtilityAction( "Split Node", frame.body.editor.splitNode ) )
                      
                    if( mE.getComponent() == self.editor ):
                        popup.add( UtilityAction( "Select All", self.editor.selectAll ) )
                        
                    popup.addSeparator()  
                    body = frame.body
                    popup.add( AddEditor( body , x, y ) )
                    popup.addSeparator()               
                    if self._detach_retach:
                        if self.editor._attached:
                            s = "Detach Editor"
                            act = self.editor.detach
                        else:
                            s = "Retach Editor"
                            act = self.editor.retach 
                        ji = swing.JMenuItem( s )
                        ji.actionPerformed =  act
                        popup.add( ji )
                    
                    
                    folded = self.editor.foldprotection.isFolded( x, y )
                    if self.editor.editor.getSelectionStart() != self.editor.editor.getSelectionEnd() or folded:
                        popup.addSeparator()
                        if not folded:
                            jmi = swing.JMenuItem( "Fold Selection" )
                            jmi.actionPerformed = lambda event, fp = self.editor.foldprotection: fp.foldSelection()
                        else:
                            jmi = swing.JMenuItem( "Unfold Fold" )
                            jmi.actionPerformed = lambda event, fp = self.editor.foldprotection, x = x, y= y: fp.unfoldSpot( x, y )
                        
                        popup.add( jmi )
                        
                        
                    source = mE.getSource()    
                    popup.show( source, x, y )
        #@nonl
        #@-node:zorcanda!.20050307213649:mousePressed
        #@-others
                            
                            
    #@-node:orkman.20050202110639:UtilityRightClick--for adding new Editors and to cut,copy and paste
    #@+node:zorcanda!.20050924192354:SimplifiedUtilityRightClick -- for adding an Editor
    class SimplifiedUtilityRightClick( aevent.MouseAdapter ):
        
        
        def __init__( self, body ):
            aevent.MouseAdapter.__init__( self )
            self.body = body
    
        
        
        #@    @+others
        #@+node:zorcanda!.20050924192354.1:mousePressed
        def mousePressed( self, mE ):
                        
            if mE.getClickCount() == 1:
                if mE.getButton() == mE.BUTTON3:
                    x = mE.getX()
                    y = mE.getY()
                               
                    popup = swing.JPopupMenu()
                    AddEditor = leoSwingBody.AddEditor
                    popup.add( AddEditor( self.body , x, y ) )                
                    source = mE.getSource()                
                    popup.show( source, x, y )
        #@nonl
        #@-node:zorcanda!.20050924192354.1:mousePressed
        #@-others
                            
                            
    #@-node:zorcanda!.20050924192354:SimplifiedUtilityRightClick -- for adding an Editor
    #@+node:zorcanda!.20050307213649.1:class AddEditor
    class AddEditor( swing.AbstractAction ):
                        
        def __init__( self, body, x,y ):
            swing.AbstractAction.__init__( self, "Add Editor" )
            self.body = body
            self.x = x
            self.y = y
                            
        def actionPerformed( self, event ):
            leoSwingBody.Editor( self.body.jdp , self.body.c, self.body , x = self.x, y = self.y )
    #@nonl
    #@-node:zorcanda!.20050307213649.1:class AddEditor
    #@+node:zorcanda!.20050307213812:class UtilityAction
    class UtilityAction( swing.AbstractAction ):
        def __init__( self, name, command ):
            swing.AbstractAction.__init__( self, name )
            self.command = command
                            
        def actionPerformed( self, event ):
            self.command()
    #@nonl
    #@-node:zorcanda!.20050307213812:class UtilityAction
    #@+node:zorcanda!.20050516144113:class InsertNode
    class InsertNode( sevent.MenuListener ):
    
        def __init__( self, menu, c, utilityaction ):
            self.menu = menu
            self.c = c
            self.UtilityAction = utilityaction
            #self.insert = insert
                    
        def menuCanceled( self, event ):
            pass
                    
        def menuDeselected( self, event ):
            pass
                    
        def menuSelected( self, event ):
            
            menu = self.menu       
            menu.removeAll()
            cp = self.c.currentPosition()
            for z in cp.children_iter( copy = True ):
                action = lambda node = z: self.insertNode( node )
                ua = self.UtilityAction( z.headString(), action )
                menu.add( ua )
    
        def insertNode( self, node ):
            
            c = self.c
            at = c.atFileCommands
            at.write(node.copy(),nosentinels=True,toString=True,scriptWrite=True)
            data = at.stringOutput
            c.frame.body.editor.insertTextIntoBody( data )
            c.beginUpdate()
            cpos = c.currentPosition()
            node.doDelete( cpos )
            c.endUpdate()
                   
    
    
    
    #@-node:zorcanda!.20050516144113:class InsertNode
    #@-others
    #@nonl
    #@-node:orkman.20050212184341:classes: Editor and a multitude of helpers
    #@+node:orkman.20050128131048:DocumentListener --syncing nodes and editor/document
    #@+at
    # These methods, implementing DocumentListener, keeps the document and 
    # position data in sync.
    # And also adds to the undoer.
    #@-at
    #@@c
    
    def insertUpdate( self, event):
        
        #doc = event.getDocument()
        #txt = doc.getText( event.getOffset(), event.getLength() )       
        self._syncText( event )
    
        
        
    def removeUpdate( self, event):
        self._syncText( event, which = 0 )
        
    def changedUpdate( self, event ):
        pass #this does Attribute changes
        
    
    
    def _syncText( self, event, which = 1 ):
        
        if self.ignore_insert: return
        c = self.c 
        doc = event.getDocument()
        #From here to
        oldText = self.oldText
        oldSel = self.oldSel 
        oldYview = self.oldYview 
        ch = self.ch
        #Here, these are set in the KeyAdapter node
        
        newSel = c.frame.body.getTextSelection()
        #length = doc.getLength()
        #newText = doc.getText( 0 , length )
        p = c.currentPosition().copy()
    
        undoType='Typing'
        if g.doHook("bodykey1",c=c,p=p,v=p,ch=ch,oldSel=oldSel,undoType=undoType):
            event.consume()
            return
            
        pos = c.currentPosition()
        #pos.setTnodeText( newText )
        t = pos.v.t
        offset = event.getOffset()
        length = event.getLength()
        if which:
            txt = doc.getText( offset, length )
            t._bodyString.insert( offset, txt )
            dec_edit = leoSwingUndo.UndoableDocumentEvent( c , event, txt )
            #c.undoer.addUndo( dec_edit )
            if self.editor._node_undoer:
                self.editor._node_undoer.addUndo( dec_edit )
            else:
                c.undoer.addUndo( dec_edit )
                dec_edit.p = pos.copy()
        else:
            #offset = offset - length
            txt = t.bodyString[ offset: offset + length ]
            t._bodyString.delete( offset, offset + length )
            dec_edit = leoSwingUndo.UndoableDocumentEvent( c, event, txt )
            #c.undoer.addUndo( dec_edit )
            #c.frame.body.editor._node_undoer.addUndo( dec_edit )
            if self.editor._node_undoer:
                self.editor._node_undoer.addUndo( dec_edit )
            else:
                c.undoer.addUndo( dec_edit )
                dec_edit.p = pos.copy()
            
        if not pos.isDirty():
            pos.setDirty()
            c.setChanged( True )  
        
        #for z in self.editor.synchers:
        #    z.sync()
            
        #c.undoer.setUndoTypingParams(p,undoType,oldText,newText,oldSel,newSel,oldYview=oldYview)   
        g.doHook("bodykey2",c=c,p=p,v=p,ch=ch,oldSel=oldSel,undoType=undoType) 
        
    
    
    
    
    
    
    
    #@-node:orkman.20050128131048:DocumentListener --syncing nodes and editor/document
    #@+node:zorcanda!.20050609201329:UndoableEditListener
    def undoableEditHappened( self, event ):
        
        if self.ignore_insert: return
        c = self.c
        cp = c.currentPosition().copy()
        edit = event.getEdit()
        #dec_edit = leoSwingUndo.UndoableEditDecorator( c, cp, edit )
        #c.undoer.addUndo( dec_edit )
        
        #undoType = "undo_edit_class"
        #c.undoer.setUndoTypingParams(p,undoType,oldText,newText,oldSel,newSel,oldYview=oldYview)
    #@-node:zorcanda!.20050609201329:UndoableEditListener
    #@+node:zorcanda!.20050314101604:KeyAdapter -- for preparing undoer
    def keyPressed( self, event ):
        
        editor = self.editor.editor
        self.oldText = editor.getText()
        self.oldSel = editor.getSelectedText()
        self.ch = event.getKeyChar()
        cpos = editor.getCaretPosition()
        rec = editor.modelToView( cpos )
        self.oldYview = rec.y 
    #@-node:zorcanda!.20050314101604:KeyAdapter -- for preparing undoer
    #@+node:mork.20050127125058.35:oops
    def oops (self):
        
        g.trace("leoBody oops:", g.callerName(2), "should be overridden in subclass")
    #@nonl
    #@-node:mork.20050127125058.35:oops
    #@+node:mork.20050127125058.36:leoBody.setFontFromConfig
    def setFontFromConfig (self):
        
        self.oops()
    #@nonl
    #@-node:mork.20050127125058.36:leoBody.setFontFromConfig
    #@+node:mork.20050127125058.37:Must be overriden in subclasses
    def createBindings (self,frame):
        self.oops()
    
    def createControl (self,frame,parentFrame):
        self.oops()
        
    def initialRatios (self):
        self.oops()
        
    def onBodyChanged (self,v,undoType,oldSel=None,oldYview=None,newSel=None,oldText=None):
        pass
        
    def setBodyFontFromConfig (self):
        self.oops()
        
    #@+node:mork.20050127125058.38:Bounding box (Tk spelling)
    def bbox(self,index):
    
        self.oops()
    #@nonl
    #@-node:mork.20050127125058.38:Bounding box (Tk spelling)
    #@+node:mork.20050127125058.39:Color tags (Tk spelling)
    def tag_add (self,tagName,index1,index2):
    
        self.oops()
    
    def tag_bind (self,tagName,event,callback):
    
        self.oops()
    
    def tag_configure (self,colorName,**keys):
    
        self.oops()
    
    def tag_delete(self,tagName):
    
        self.oops()
    
    def tag_remove (self,tagName,index1,index2):
        self.oops()
    #@nonl
    #@-node:mork.20050127125058.39:Color tags (Tk spelling)
    #@+node:mork.20050127125058.40:Configuration (Tk spelling)
    def cget(self,*args,**keys):
        
        self.oops()
        
    def configure (self,*args,**keys):
        
        self.oops()
    #@nonl
    #@-node:mork.20050127125058.40:Configuration (Tk spelling)
    #@+node:mork.20050127125058.41:Focus
    def hasFocus (self):
        
        return self.editor.editor.hasFocus()
        
    def setFocus (self):
        
        df = DefCallable( self.editor.editor.requestFocusInWindow )
        ft = java.util.concurrent.FutureTask( df )
        java.awt.EventQueue.invokeLater( ft )
        
    def focus_get( self ):
        
        return self
    #@nonl
    #@-node:mork.20050127125058.41:Focus
    #@+node:mork.20050127125058.42:Height & width
    def getBodyPaneHeight (self):
        
        return self.editor.editor.getSize().height
    
    def getBodyPaneWidth (self):
        
        return self.editor.editor.getSize().width 
    #@nonl
    #@-node:mork.20050127125058.42:Height & width
    #@+node:mork.20050127125058.43:Idle time...
    def scheduleIdleTimeRoutine (self,function,*args,**keys):
    
        self.oops()
    #@nonl
    #@-node:mork.20050127125058.43:Idle time...
    #@+node:mork.20050127125058.44:Indices
    def adjustIndex (self,index,offset):
        
        return index + offset
        
    def compareIndices(self,i,rel,j):
    
        if j == 'end' or j == '1.0':
            if j == 'end':
                j = self.editor.editor.getDocument().getLength()
            elif j == '1.0':
                j = 0
                     
        if rel == '<=':
            return i <= j
        
    def convertRowColumnToIndex (self,row,column):
        
        self.oops()
        
    def convertIndexToRowColumn (self,index):
        
        self.oops()
        
    def getImageIndex (self,image):
        
        self.oops()
    #@nonl
    #@-node:mork.20050127125058.44:Indices
    #@+node:mork.20050127125058.45:Insert point
    def getBeforeInsertionPoint (self):
        
        editor = self.editor.editor
        pos = editor.getCaretPosition()
        if pos == 0:
            return 0
        else:
            return pos - 1
    
    def getInsertionPoint (self):
    
        return self.editor.editor.getCaretPosition()
        
    def getCharAtInsertPoint (self):
        
        editor = self.editor.editor
        pos = editor.getCaretPosition()
        doc = editor.getDocument()
        dlen = doc.getLength()
        if dlen == pos:
            return " "
        else:
            return doc.getText( pos, 1 )
    
    def getCharBeforeInsertPoint (self):
        editor = self.editor.editor
        pos = editor.getCaretPosition()
        doc = editor.getDocument()
        dlen = doc.getLength()
        if pos == 0:
            return " "
        else:
            return doc.getText( pos - 1, 1 )
        
    def makeInsertPointVisible (self):
        pass #this doesn't seem to be a relevant method at this point
        
    def setInsertionPoint (self,index):
        
        self.editor.editor.setCaretPosition( index )
    
    def setInsertionPointToEnd (self):
        
        editor = self.editor.editor
        doc = editor.getDocument()
        editor.setCaretPosition( doc.getLength() )
        
    def setInsertPointToStartOfLine (self,lineNumber): # zero-based line number
        
        txt = self.editor.editor.getText()
        lines = txt.splitlines( True )
        n = 0
        for z in xrange( lineNumber ):
            n += len( lines[ z ] )
           
        self.editor.editor.setCaretPosition( n )
        
    #@nonl
    #@-node:mork.20050127125058.45:Insert point
    #@+node:mork.20050127125058.46:Menus
    def bind (self,*args,**keys):
        
        #self.oops()
        pass
    #@-node:mork.20050127125058.46:Menus
    #@+node:mork.20050127125058.47:Selection
    def deleteTextSelection (self):
    
        editor = self.editor.editor
        editor.replaceSelection( "" )
        
    def getSelectedText (self):
    
        editor = self.editor.editor
        return editor.getSelectedText()
        
    def getTextSelection (self):
        
        editor = self.editor.editor
        start = editor.getSelectionStart()
        end = editor.getSelectionEnd()
        return start, end
        
    def hasTextSelection (self):
        
        editor = self.editor.editor
        start = editor.getSelectionStart()
        end = editor.getSelectionEnd()
        if start != end: return True
        else: return False
        
    def selectAllText (self):
    
        editor = self.editor.editor
        doc = editor.getDocument()
        editor.setSelectionStart( 0 )
        editor.setSelectionEnd( doc.getLength() )
        
    def setTextSelection (self,i,j=None):
        
        if i is None:
            i, j = 0, 0
        elif i != None and j != None:
            pass
        else:
            i,j = i
        editor = self.editor.editor
        g.app.gui.setTextSelection( editor, i, j )
    #@nonl
    #@-node:mork.20050127125058.47:Selection
    #@+node:mork.20050127125058.48:Text
    #@+node:mork.20050127125058.49:delete...
    def deleteAllText(self):
        
        editor = self.editor.editor
        doc = editor.getDocument()
        doc.replace( 0, doc.getLength(), "", None )
    
    def deleteCharacter (self,index):
        editor = self.editor.editor
        doc = editor.getDocument()
        doc.replace( index, 1, "", None )
        
        
    def deleteLastChar (self):
        editor = self.editor.editor
        sdoc = editor.getStyledDocument()
        sdoc.replace( sdoc.getLength() - 1, 1, "", None )
        
        
    def deleteLine (self,lineNumber): # zero based line number.
    
        
        editor = self.editor.editor
        txt = editor.getText()
        lines = txt.splitlines( True )
        start = lines[ : lineNumber ]
        end = lines[ lineNumber + 1 : ]
        start.extend( end )
        ntxt = ''.join( start )
        sdoc = editor.getStyledDocument()
        sdoc.replace( 0, sdoc.getLength(), "", None )
        sdoc.insertString( 0, ntxt, None )
        
    def deleteLines (self,line1,numberOfLines): # zero based line numbers.
        #self.oops()
        editor = self.editor.editor
        txt = editor.getText()
        txtlines = txt.splitlines( True )
        start = txtlines[ : line1 ]
        middle = [ '\n', ]
        end = txtlines[ line1 + numberOfLines : ]
        start.extend( middle )
        start.extend( end )
        
        ntxt = ''.join( start )
        sdoc = editor.getStyledDocument()
        try:
            sdoc.replace( 0, sdoc.getLength(), ntxt , None )
            
        except java.lang.Exception, x:
            x.printStackTrace()
            
        
        
        
    def deleteRange (self,index1,index2):
    
        editor = self.editor.editor
        sdoc = editor.getStyledDocument()
        sdoc.remove( index1, index2 -index1 )
        
    #@-node:mork.20050127125058.49:delete...
    #@+node:mork.20050127125058.50:get...
    def getAllText (self):
        
        editor = self.editor.editor
        doc = editor.getDocument()
        return doc.getText()
        
    def getCharAtIndex (self,index):
        
        editor = self.editor.editor
        sdoc = editor.getStyledDocument()
        return sdoc.getText( index, 1 )
        
    def getInsertLines (self):
        self.oops()
        return None,None,None
        
    def getSelectionAreas (self):
        self.oops()
        return None,None,None
        
    def getSelectionLines (self):
        #self.oops()
        editor = self.editor.editor
        start = editor.getSelectionStart()
        end = editor.getSelectionEnd()
        if start == end:
            start = stext.Utilities.getRowStart( editor, start )
            end = stext.Utilities.getRowEnd( editor, start )
            if start == -1: start = 0
            if end == -1: end = 0
        
        before = editor.getText( 0, start )
        sel = editor.getText( start, end - start )
        after = editor.getText( end, len( editor.getText() ) - end )
        return before, sel, after
        
        
        
    def getTextRange (self,index1,index2):
    
        editor = self.editor.editor
        sdoc = editor.getStyledDocument()
        return sdoc.getText( index1, index2 -index1 )
        
    #@-node:mork.20050127125058.50:get...
    #@+node:mork.20050127125058.51:Insert...
    def insertAtInsertPoint (self,s):
        
        editor = self.editor.editor
        sdoc = editor.getStyledDocument()
        pos = editor.getCaretPosition()
        sdoc.insertString( pos, s, None )
        editor.setCaretPosition( pos + len( s ) )
        
    def insertAtEnd (self,s):
        
        editor = self.editor.editor
        sdoc = editor.getStyledDocument()
        length = sdoc.getLength()
        sdoc.insertString( length - 1, s, None )
        editor.setCaretPosition( length -1 + len( s ))
        
    def insertAtStartOfLine (self,lineNumber,s):
        
        editor = self.editor.editor
        txt = editor.getText()
        txtlines = txt.splitlines( True )
        lines = txtlines[ : lineNumber ]
        where = ''.join( lines )
        spot = len( where )
        sdoc = editor.getStyledDocument()
        sdoc.insertString( spot, s, None )
        editor.setCaretPosition( spot + len( s ) )
        
    #@-node:mork.20050127125058.51:Insert...
    #@+node:mork.20050127125058.52:setSelectionAreas
    def setSelectionAreas (self,before,sel,after):
    
        
        editor = self.editor.editor
        doc = editor.getDocument()
        doc.remove( 0, doc.getLength() )
        if before:
            doc.insertString( 0, before, None )
        sel_start = doc.getLength()
        
        if sel:
            doc.insertString( doc.getLength(), sel, None )
        sel_end = doc.getLength()
        
        if after:
            if after[ -1 ] == '\n':
                after = after[ : -1 ]
            doc.insertString( doc.getLength(), after, None )
            
        g.app.gui.setTextSelection( self.editor.editor, sel_start, sel_end )
        
        return sel_start, sel_end
    #@-node:mork.20050127125058.52:setSelectionAreas
    #@-node:mork.20050127125058.48:Text
    #@+node:mork.20050127125058.53:Visibility & scrolling
    def makeIndexVisible (self,index):
        pass
        
    def setFirstVisibleIndex (self,index):
        pass
        
    def getYScrollPosition (self):
        
        editor = self.editor.editor
        try:
            cpos = editor.getCaretPosition()
            rec = editor.modelToView( cpos )
            return rec.y 
        except:
            return 0
        
    def setYScrollPosition (self,scrollPosition):
        #self.oops()
        #print "Y Scroll is %s" % scrollPosition
        pass   
    
    def scrollUp (self):
        self.oops()
        
    def scrollDown (self):
        self.oops()
    #@nonl
    #@-node:mork.20050127125058.53:Visibility & scrolling
    #@-node:mork.20050127125058.37:Must be overriden in subclasses
    #@+node:orkman.20050222162639:getAllText --had to be added
    def getAllText( self ):
        
        return self.editor.editor.getText()
    #@nonl
    #@-node:orkman.20050222162639:getAllText --had to be added
    #@+node:mork.20050127125058.54:Coloring
    # It's weird to have the tree class be responsible for coloring the body pane!
    
    def getColorizer(self):
        
        return self.colorizer
    
    def recolor_now(self,p,incremental=False):
        
        self.editor.editor.repaint()
        #self.colorizer.colorize(p.copy(),incremental)
    
    def recolor_range(self,p,leading,trailing):
        
        pass 
        #self.colorizer.recolor_range(p.copy(),leading,trailing)
    
    def recolor(self,p,incremental=False):
        
        pass
        #if 0: # Do immediately
        #    self.colorizer.colorize(p.copy(),incremental)
        #else: # Do at idle time
        #    self.colorizer.schedule(p.copy(),incremental)
        
    def updateSyntaxColorer(self,p):
        pass
        #return self.colorizer.updateSyntaxColorer(p.copy())
    #@nonl
    #@-node:mork.20050127125058.54:Coloring
    #@-others
#@nonl
#@-node:mork.20050127125058.33:class leoSwingBody
#@+node:mork.20050127125058.55:class leoSwingFrame
class leoSwingFrame( leoFrame.leoFrame ):     
    
    """The base class for all Leo windows."""
    
    instances = 0
    
    #@    @+others
    #@+node:mork.20050127125058.56:  leoSwingFrame.__init__
    def __init__ (self, gui ):
        
        leoFrame.leoFrame.__init__( self, gui )
        self.gui = gui
        #import RepaintManager2
        #rpm2 = RepaintManager2()
        #swing.RepaintManager.setCurrentManager( rpm2 )
        # Objects attached to this frame.
        self.menu = None
        self.keys = None
        self.colorPanel = None 
        self.fontPanel = None 
        self.prefsPanel = None
        self.comparePanel = None 
        self.title = ""
        self._menu_init_callbacks = []
        self.receiver = None
        self.canresize = True
        
        #import Chapters
        #self.chapters = Chapters.Chapters( self.c )
        #if g.app.config.getBool( self.c, "lock_open_files" ):
        #    receiver = self.Receiver( self, self.c )
        #    thread = java.lang.Thread( receiver )
        #    thread.setDaemon( True )
        #    thread.start()
            
        #self.c = None # Must be created by subclasses.
        #self.title = None # Must be created by subclasses.
        
        # Objects attached to this frame.
        #self.menu = None
        #self.keys = None
        #self.colorPanel = None 
        #self.fontPanel = None 
        #self.prefsPanel = None
        #self.comparePanel = None
    
        # Gui-independent data
        #self.es_newlines = 0 # newline count for this log stream
        #self.openDirectory = ""
        #self.saved=False # True if ever saved
        #self.splitVerticalFlag,self.ratio, self.secondary_ratio = self.initialRatios()
        #self.startupWindow=False # True if initially opened window
        #self.stylesheet = None # The contents of <?xml-stylesheet...?> line.
    
        # Colors of log pane.
        #self.statusColorTags = [] # list of color names used as tags in status window.
    
        # Previous row and column shown in the status area.
        #self.lastStatusRow = self.lastStatusCol = 0
        #self.tab_width = 0 # The tab width in effect in this pane.
    #@nonl
    #@-node:mork.20050127125058.56:  leoSwingFrame.__init__
    #@+node:mork.20050127125058.57: Must be defined in subclasses
    #@+node:mork.20050127125058.58: gui-dependent commands
    # In the Edit menu...
    def OnCopy  (self,event=None): self.OnCopyFromMenu()
    def OnCut   (self,event=None): self.OnCutFromMenu()
    def OnPaste (self,event=None): self.OnPasteFromMenu()
    
    def OnCutFromMenu  (self):
        self.OnCopyFromMenu()
        self.body.editor.editor.replaceSelection( "" ) 
        
    def OnCopyFromMenu (self):
        
        gui = g.app.gui
        editor = self.body.editor.editor
        txt = editor.getSelectedText()
        gui.replaceClipboardWith( txt )
        
    def OnPasteFromMenu (self):
        
        txt = g.app.gui.getTextFromClipboard()
        editor = self.body.editor.editor
        document = self.body.editor.editor.getStyledDocument()
        if txt:
            pos = editor.getCaretPosition()
            document.insertString( pos, txt, None )
        
    
    def abortEditLabelCommand (self):
        
        self.c.frame.tree.jtree.cancelEditing()
        
    def endEditLabelCommand (self):   
        self.c.frame.tree.endEditLabel()
        
    def insertHeadlineTime (self):    
        time = self.c.getTime( body = False )
        cp = self.c.currentPosition()
        hs = cp.headString()
        nhs = '%s %s' %( time, hs )
        cp.setHeadString( nhs )
        
        
    # In the Window menu...
    def cascade(self):              self.oops()
    def equalSizedPanes(self):
        self.jsp2.setDividerLocation( .5 )
        
    def hideLogWindow (self):       self.oops()
    def minimizeAll(self):
        
        self.top.setState( self.top.ICONIFIED )   
        
    def resizeToScreen(self):
        
        tk = self.top.getToolkit()
        ss = tk.getScreenSize()
        self.top.setBounds( 0, 0, ss.width, ss.height )
        
    def toggleActivePane(self):     self.oops()
    
    
    def toggleSplitDirection(self):
        
        self._toggle( self.jsp1 )
        self._toggle( self.jsp2 )
        self.jsp2.setDividerLocation( .50 )
        self.jsp1.setDividerLocation( .75 )
        
    def _toggle( self, jsp ):
        
        orient = jsp.getOrientation()
        if orient == jsp.HORIZONTAL_SPLIT:
            jsp.setOrientation( jsp.VERTICAL_SPLIT )
        else:
            jsp.setOrientation( jsp.HORIZONTAL_SPLIT )
            
         
            
    
    # In help menu...
    def leoHelp (self): self.oops()
    
    #@-node:mork.20050127125058.58: gui-dependent commands
    #@+node:mork.20050127125058.59:bringToFront, deiconify, lift & update
    def bringToFront (self):
        
        self.top.toFront()
    
    def deiconify (self):
        
        self.top.setVisible( True )
        
    def lift (self):
        
        self.top.toFront()
        
    def update (self):
        
        self.top.repaint()
        
    #@-node:mork.20050127125058.59:bringToFront, deiconify, lift & update
    #@+node:mork.20050127125058.60:config stuff...
    #@+node:mork.20050127125058.61:resizePanesToRatio
    def resizePanesToRatio (self,ratio,secondary_ratio):
            
        def resize():
            self.jsp1.setDividerLocation( ratio )
            self.jsp2.setDividerLocation( secondary_ratio ) 
        
        dc = DefCallable( resize )
        java.awt.EventQueue.invokeLater( java.util.concurrent.FutureTask( dc ) )
        
    #@nonl
    #@-node:mork.20050127125058.61:resizePanesToRatio
    #@+node:mork.20050127125058.62:setInitialWindowGeometry
    def setInitialWindowGeometry (self):
        """Set the position and size of the frame to config params."""
        #config = g.app.config
        c = self.c 
        h = c.config.getInt("initial_window_height")
        w = c.config.getInt("initial_window_width")
        x = c.config.getInt("initial_window_left")
        y = c.config.getInt("initial_window_top")
        
        if h and w and x and y:
            self.setTopGeometry(w,h,x,y)
    
        #was:
        #h = config.getIntWindowPref("initial_window_height")
        #w = config.getIntWindowPref("initial_window_width")
        #x = config.getIntWindowPref("initial_window_left")
        #y = config.getIntWindowPref("initial_window_top")
        #if h and w and x and y:
        #    self.setTopGeometry(w,h,x,y)
    #@nonl
    #@-node:mork.20050127125058.62:setInitialWindowGeometry
    #@+node:mork.20050127125058.63:setTopGeometry
    def setTopGeometry (self,w,h,x,y,adjustSize=True):
       
        if self.canresize: 
            self.top.setBounds( x, y, w, h )    
        
        
    def disableResizing( self ):
        
        self.canresize = False
        
    def enableResizing( self ):
        
        self.canresize = True
    #@nonl
    #@-node:mork.20050127125058.63:setTopGeometry
    #@+node:orkman.20050128212311:get_window_info
    def get_window_info( self ):
        
        bounds = self.top.getBounds()
        return ( bounds.width, bounds.height, bounds.x, bounds.y )
    #@-node:orkman.20050128212311:get_window_info
    #@-node:mork.20050127125058.60:config stuff...
    #@-node:mork.20050127125058.57: Must be defined in subclasses
    #@+node:mork.20050127130815:finishCreate
    def finishCreate(self,c):
    
        self.c = c
        self.setSkin()
        #swing.plaf.metal.MetalLookAndFeel.setCurrentTheme( self.LeoMetalTheme( self.c ) )
        wm1 = WeakMethod( self, "setSkin" )
        g.app.config.manager.addNotificationDef( "type_of_skin", wm1 )
        self.top = swing.JFrame() #Must add close question
        self.gp2 = self.GlassPane2()
        self.top.setGlassPane( self.gp2 )
        self.top.addWindowListener( self.WindowClosingWatcher( self ) )
            
        self.ftp = self.leoFocusTraversalPolicy( c )
        self.top.setFocusTraversalPolicy( self.ftp )
        #if g.app.config.getBool( self.c, "lock_open_files" ) and self.c.mFileName != "":
        #    self.startReceiver()
    
        g.app.gui.addLAFListener( self.top )
        #self.setSkin()
        #g.app.config.manager.addNotificationDef( "type_of_skin", self.setSkin )
    
               
        ic = g.os_path_join( g.app.loadDir ,"..","Icons","Leoapp.GIF")
        ifile = io.File( ic )
        if ifile.exists():
            try:
                icimage = imageio.ImageIO.read( ifile )
                self.top.setIconImage( icimage )
            except java.lang.Exception, x:
                pass
        self.top.setDefaultCloseOperation( swing.JFrame.DO_NOTHING_ON_CLOSE )
        self.setTitle( c.mFileName )
        pf = self.top.getContentPane()
    
        self.jcp = self.top.getContentPane()
        self.toolbar = swing.JPanel( java.awt.BorderLayout() ) #swing.JToolBar()
        #self.toolbar.setFloatable( False )
        nodebar = swing.JToolBar()
        self.NodeBar( c, nodebar )
        nodebar.setFloatable( True )
        self.toolbar.add( nodebar, java.awt.BorderLayout.NORTH )
        self.toolbar2 = swing.JToolBar()
        #g.doHook( "toolbar2-in-place", c = self.c , toolbar = self.toolbar2 )
        self.toolbar.add( self.toolbar2, java.awt.BorderLayout.SOUTH )
        
        self.jsp1 = swing.JSplitPane()
        self.jsp1.continuousLayout = True
        
        #pf.add( self.jif3 )
        self.jsp2 = swing.JSplitPane( swing.JSplitPane.VERTICAL_SPLIT, True )
        self.jsp2.topComponent = self.jsp1
        #self.jtab = swing.JTabbedPane()
        #self.tree_tabs = TabManager()
        #self.jsp1.leftComponent = self.tree_tabs.base #self.jtab
        self.jcp.add( self.jsp2 , awt.BorderLayout.CENTER )
        self.top.add( self.toolbar, awt.BorderLayout.NORTH )
        #self.jif.getContentPane().add( self.jtab )
        #import Chapters
        #self.chapters = Chapters.Chapters( self.c )
        self.jsp1.leftComponent = self.c.chapters.getWidget()
        #self.tree = leoSwingTree(frame=self)
        self.tree = self.c.chapters.addChapter( "New Chapter", p = c.rootPosition() )
        #self.jsp1.leftComponent = self.tree.getWidget()
        self.menu = leoSwingMenu.leoSwingMenu(frame=self)
        #self.menu.createMenuBar( self )
        self.body = leoSwingBody(frame=self,parentFrame=self.jsp2 )
        self.log  = leoSwingLog (frame=self,parentFrame=self.jsp1 )
        import leoSwingFind
        self.findPanel = leoSwingFind.leoSwingFind( c )
        g.app.log = self.log 
        self.bodyCtrl = self.body.editor.editor
        
        tk = self.top.getToolkit()
        size = tk.getScreenSize()
        self.top.bounds = ( 0, 0, size.width , size.height )
        #self.jsp1.setDividerLocation( .75 )
        #self.jsp2.setDividerLocation( .5 )
        self.jsp1.setOneTouchExpandable( True )
        self.jsp2.setOneTouchExpandable( True )
        #@    << create the first tree node >>
        #@+node:mork.20050127175441:<< create the first tree node >>
        import leoNodes
        t = leoNodes.tnode()
        v = leoNodes.vnode(c,t)
        p = leoNodes.position(v,[])
        v.initHeadString("NewHeadline")
        c.beginUpdate()
        p.moveToRoot()
        #c.beginUpdate()
        #c.selectVnode(p)
        c.selectPosition( p )
        #c.redraw()
        #c.frame.getFocus()
        c.editPosition(p)
        c.endUpdate(False)
        
        
        #@-node:mork.20050127175441:<< create the first tree node >>
        #@nl
        #self.menu = leoSwingMenu.leoSwingMenu(frame=self)
        self.menu.createMenuBar( self )
        #self.top.visible = True
        #self.jsp1.setDividerLocation( .75 )
        #self.jsp2.setDividerLocation( .5 )
        
        g.app.windowList.append( self )
        c.initVersion()
        c.signOnWithVersion()
        self.menuInitialized()
        placement = g.app.config.getString( c, 'tree_editor_placement' )
        if placement == "Top/Bottom":
            pass
        else:
            self.toggleSplitDirection()
    
    
    
    #@-node:mork.20050127130815:finishCreate
    #@+node:zorcanda!.20050303120146:finishCreateForSettings
    def finishCreateForSettings(self,c, controller ):
    
        self.c = c
        self.top = swing.JFrame()
        self.ftp = self.leoFocusTraversalPolicy( c )
        self.top.setFocusTraversalPolicy( self.ftp )
        self.top.setTitle( "Leo Settings" )
        
        ic = g.os_path_join( g.app.loadDir ,"..","Icons","Leoapp.GIF")
        ifile = java.io.File( ic )
        if ifile.exists():
            iimage = imageio.ImageIO.read( ifile )
            self.top.setIconImage( iimage )
        self.top.setDefaultCloseOperation( swing.JFrame.EXIT_ON_CLOSE )
        self.setTitle( c.mFileName )
        pf = self.top.getContentPane()
        gbl = awt.GridBagLayout()
        pf.setLayout( gbl )
        gbc = awt.GridBagConstraints()
        gbc.weightx = 1
        gbc.weighty = 1
        gbc.fill = 1
        
    
        self.jcp = self.top.getContentPane()    
        self.jsp1 = swing.JSplitPane( swing.JSplitPane.VERTICAL_SPLIT )
        gbl.setConstraints( self.jsp1, gbc )
        self.jsp1.continuousLayout = True
        pf.add( self.jsp1 )
        self.jtab = self.c.chapters.getWidget()
        c.chapters.disablePopup()
        self.jsp1.leftComponent = self.jtab
        self.jsp1.rightComponent = swing.JPanel()
        self.tree = c.chapters.addChapterForSettingsTree( "Settings", p = c.rootPosition(), controller = controller )
        self.tree.jtree.setEditable( False )
        class fkBody:
            
            class ed:
                def __init__( self ):
                    self.editor = swing.JTextPane()
                    
                def sync( self, *args ):
                    pass
            
            def __init__( self ):
                self.editor =  self.ed()
            
            def setFocus( self ):
                pass
                
            def setSelectionAreas( self, *args):
                pass
                
            def setTextSelection( self, *args ):
                pass
                
            def recolor( self, *args ):
                pass
                
            def setColorFromConfig( self, *args ):
                pass
                
        self.body = fkBody()
        self.jsp1.setOneTouchExpandable( True )
        #@    << create the first tree node >>
        #@+node:zorcanda!.20050303121054:<< create the first tree node >>
        import leoNodes
        t = leoNodes.tnode()
        v = leoNodes.vnode(c,t)
        p = leoNodes.position(v,[])
        v.initHeadString("NewHeadline")
        c.beginUpdate()
        p.moveToRoot()
        #c.beginUpdate()
        #c.selectVnode(p)
        c.selectPosition( p )
        #c.redraw()
        #c.frame.getFocus()
        c.editPosition(p)
        c.endUpdate(False)
        
        
        #@-node:zorcanda!.20050303121054:<< create the first tree node >>
        #@nl
        self.jsp1.setDividerLocation( .5 )
        g.app.windowList.append( self )
        c.initVersion()
        c.signOnWithVersion()
        self.tree.jtree.setDragEnabled( False )
    
            
    #@-node:zorcanda!.20050303120146:finishCreateForSettings
    #@+node:zorcanda!.20050529210315:configuration methods
    #@+others
    #@+node:zorcanda!.20050529210315.1:setSkin
    def setSkin( self, notification = None, handback = None ):
        
        c = self.c 
        toskin = g.app.config.getString( c, 'type_of_skin' )
        if toskin == 'native':
            
            nlafname = swing.UIManager.getSystemLookAndFeelClassName()
            if nlafname:
                import java.lang.Class
                nlaf = java.lang.Class.forName( nlafname ).newInstance()
                swing.UIManager.setLookAndFeel( nlaf )
        elif toskin == 'synth':
            try:
                slaf = synth.SynthLookAndFeel()
                sname = g.app.config.getString( c, 'custom_skin' )
                ldir1 = io.File( g.app.loadDir )
                ldir2 = ldir1.getParent()
                ldir3 = io.File( ldir2, "skins" )
                ldir4 = io.File( ldir2, "skinimages" )
                synthfile = io.File( ldir3, sname )
                fis = io.FileInputStream( synthfile )
                import JyLeoResourceClassLoader as jlrc
                cloader = jlrc( ldir4, ldir1 )
                clazz = cloader.getFakeClass()
                slaf.load( fis, clazz )
                swing.UIManager.setLookAndFeel( slaf )
            except java.lang.Exception, x:
                x.printStackTrace()
                g.es( "Could not load custom skin" )
        else:
            swing.UIManager.setLookAndFeel( "javax.swing.plaf.metal.MetalLookAndFeel" )
            
        
                    
    
    #@-node:zorcanda!.20050529210315.1:setSkin
    #@-others
    #@-node:zorcanda!.20050529210315:configuration methods
    #@+node:mork.20050127125058.64:setTabWidth
    def setTabWidth (self,w):
        
        # Subclasses may override this to affect drawing.
        self.tab_width = w
    #@nonl
    #@-node:mork.20050127125058.64:setTabWidth
    #@+node:mork.20050127125058.65:getTitle & setTitle
    def getTitle (self):
        return self.title
        
    def setTitle (self,title):
        self.top.title = title
    #@nonl
    #@-node:mork.20050127125058.65:getTitle & setTitle
    #@+node:mork.20050127125058.66:initialRatios
    def initialRatios (self):
    
        config = g.app.config
    
        s = config.getWindowPref("initial_splitter_orientation")
        verticalFlag = s == None or (s != "h" and s != "horizontal")
    
        if verticalFlag:
            r = config.getFloatWindowPref("initial_vertical_ratio")
            if r == None or r < 0.0 or r > 1.0: r = 0.5
            r2 = config.getFloatWindowPref("initial_vertical_secondary_ratio")
            if r2 == None or r2 < 0.0 or r2 > 1.0: r2 = 0.8
        else:
            r = config.getFloatWindowPref("initial_horizontal_ratio")
            if r == None or r < 0.0 or r > 1.0: r = 0.3
            r2 = config.getFloatWindowPref("initial_horizontal_secondary_ratio")
            if r2 == None or r2 < 0.0 or r2 > 1.0: r2 = 0.8
    
        # print r,r2
        return verticalFlag,r,r2
    #@nonl
    #@-node:mork.20050127125058.66:initialRatios
    #@+node:mork.20050127125058.67:longFileName & shortFileName
    def longFileName (self):
    
        return self.c.mFileName
        
    def shortFileName (self):
    
        return g.shortFileName(self.c.mFileName)
    #@nonl
    #@-node:mork.20050127125058.67:longFileName & shortFileName
    #@+node:mork.20050127125058.68:oops
    def oops(self):
        
        print "leoFrame oops:", g.callerName(2), "should be overridden in subclass"
    #@-node:mork.20050127125058.68:oops
    #@+node:mork.20050127125058.69:promptForSave
    def promptForSave (self):
        
        """Prompt the user to save changes.
        
        Return True if the user vetos the quit or save operation."""
        
        c = self.c
        name = g.choose(c.mFileName,c.mFileName,self.title)
        type = g.choose(g.app.quitting, "quitting?", "closing?")
        answer = g.app.gui.runAskYesNoCancelDialog(
            "Confirm",
            'Save changes to %s before %s' % (name,type))    
        # print answer	
        if answer == "cancel":
            return True # Veto.
        elif answer == "no":
            return False # Don't save and don't veto.
        else:
            if not c.mFileName:
                #@            << Put up a file save dialog to set mFileName >>
                #@+node:mork.20050127125058.70:<< Put up a file save dialog to set mFileName >>
                # Make sure we never pass None to the ctor.
                if not c.mFileName:
                    c.mFileName = ""
                
                c.mFileName = g.app.gui.runSaveFileDialog(
                    initialfile = c.mFileName,
                    title="Save",
                    filetypes=[("Leo files", "*.leo")],
                    defaultextension=".leo")
                #@nonl
                #@-node:mork.20050127125058.70:<< Put up a file save dialog to set mFileName >>
                #@nl
            if c.mFileName:
                ok = c.fileCommands.save(c.mFileName)
                return not ok # New in 4.2: Veto if the save did not succeed.
            else:
                return True # Veto.
    #@nonl
    #@-node:mork.20050127125058.69:promptForSave
    #@+node:mork.20050127125058.71:scanForTabWidth
    # Similar to code in scanAllDirectives.
    
    def scanForTabWidth (self,p):
    
        c = self.c ; w = c.tab_width
    
        for p in p.self_and_parents_iter():
            s = p.v.t.bodyString
            dict = g.get_directives_dict(s)
            #@        << set w and break on @tabwidth >>
            #@+node:mork.20050127125058.72:<< set w and break on @tabwidth >>
            if dict.has_key("tabwidth"):
                
                val = g.scanAtTabwidthDirective(s,dict,issue_error_flag=False)
                if val and val != 0:
                    w = val
                    break
            #@nonl
            #@-node:mork.20050127125058.72:<< set w and break on @tabwidth >>
            #@nl
    
        c.frame.setTabWidth(w)
    #@nonl
    #@-node:mork.20050127125058.71:scanForTabWidth
    #@+node:orkman.20050128235427:destroySelf --had to be added
    def destroySelf( self ):
        
        self.top.setVisible( False )
        self.top.dispose()
        self.top = None
        
    #@-node:orkman.20050128235427:destroySelf --had to be added
    #@+node:orkman.20050130103121:clearStatusLine -- had to be added
    def clearStatusLine( self ):
        pass
        
    def putStatusLine( self, s, **kwords ):
        pass
    #@nonl
    #@-node:orkman.20050130103121:clearStatusLine -- had to be added
    #@+node:zorcanda!.20050919131437:addIconButton -- had to be added
    def addIconButton( self, *args, **kwords ):
        
        toolbar = self.toolbar2
        text = kwords[ 'text' ]
        button = swing.JButton( text )
        toolbar.add( button )
        return button
    #@-node:zorcanda!.20050919131437:addIconButton -- had to be added
    #@+node:zorcanda!.20050415145153:toggleActivePane
    def toggleActivePane( self ):
        
        kfm = awt.KeyboardFocusManager.getCurrentKeyboardFocusManager()
        kfm.focusNextComponent()
        
        
        
    #@-node:zorcanda!.20050415145153:toggleActivePane
    #@+node:zorcanda!.20050418115008:isMenuInitialized
    def isMenuInitialized( self, callback ):
         
        if self.menu != None:
            callback( self.menu )
        else:
            self._menu_init_callbacks.append( callback )
            
            
    def menuInitialized( self ):
        
        for z in self._menu_init_callbacks:
            z( self.menu )
        
        self._menu_init_callbacks=[]
    #@nonl
    #@-node:zorcanda!.20050418115008:isMenuInitialized
    #@+node:zorcanda!.20050419114330:startReceiver
    def startReceiver( self ):
        
        import java
        self.receiver = receiver = self.Receiver( self, self.c )
        thread = java.lang.Thread( receiver )
        thread.setDaemon( True )
        thread.start()     
    
    def hasReceiver( self ):
        
        if self.receiver:
            return True
        else:
            return False
    #@nonl
    #@-node:zorcanda!.20050419114330:startReceiver
    #@+node:zorcanda!.20051206140225:helper classes
    #@+others
    #@+node:zorcanda!.20050415150410:class leoFocusTraversalPolicy
    class leoFocusTraversalPolicy( awt.FocusTraversalPolicy ):
        """This class implements the Traversale Policy for a Leo instance,
        Ctrl-T moves from widget to widget.  The Policy moves the Widgets like so:
        Editor --> Tree --> Log --> (Back to Editor)"""
        
        def __init__( self, c ):
            awt.FocusTraversalPolicy.__init__( self )
            self.c = c
            
        #@    @+others
        #@+node:zorcanda!.20050415150410.1:getComponentAfter
        def getComponentAfter( self, aContainer, aComponent):
        
            try:
                c = self.c
                if str( c.frame.tree.__class__ ) == "leoConfig.settingsTree":
                    return c.frame.tree.jtree
                    
                editor = c.frame.body.editor.editor
                logCtrl = c.frame.log.getCurrentTab()
                tree = c.frame.tree.jtree
                tree_editor = c.frame.tree.tcEdi.editor._jta
             
                if aComponent == editor:
                    return tree
                elif aComponent == tree:
                
                    return logCtrl
                
                elif aComponent == tree_editor:
                    return logCtrl
                
                else:
                    return editor
            except java.lang.Exception, x:
                x.printStackTrace()
                return editor  
            
        #@-node:zorcanda!.20050415150410.1:getComponentAfter
        #@+node:zorcanda!.20050415150410.2:getComponentBefore
        def getComponentBefore( self, aContainer, aComponent):
        
            logCtrl = self.c.frame.log.getCurrentTab()
            editor = self.c.frame.body.editor.editor
            tree = self.c.frame.tree.jtree
            tree_editor = self.c.frame.tree.tcEdi.editor._jta
            
            if aComponent == editor:
                return logCtrl
            elif aComponent == tree:
                return editor
                
            elif aComponent == tree_editor:
                return editor
            else:
                return tree
                
        #@-node:zorcanda!.20050415150410.2:getComponentBefore
        #@+node:zorcanda!.20050415150410.3:getDefaultComponent
        def getDefaultComponent( self, container ):
            
            return self.c.frame.body.editor.editor
            
        #@-node:zorcanda!.20050415150410.3:getDefaultComponent
        #@+node:zorcanda!.20050415150410.4:getFirstComponent
        def getFirstComponent( self, aContainer):
            
            return self.c.frame.body.editor.editor
        #@nonl
        #@-node:zorcanda!.20050415150410.4:getFirstComponent
        #@+node:zorcanda!.20050415150410.5:getInitialComponent
        def getInitialComponent( self, window):
            
            return self.c.frame.body.editor.editor
            
             
        
        #@-node:zorcanda!.20050415150410.5:getInitialComponent
        #@+node:zorcanda!.20050415150410.6:getLastComponent
        def getLastComponent( self, aContainer):
        
            return self.c.frame.log.getCurrentTab()
            
        #@-node:zorcanda!.20050415150410.6:getLastComponent
        #@-others
        
    #@-node:zorcanda!.20050415150410:class leoFocusTraversalPolicy
    #@+node:zorcanda!.20050419095522:class Receiver
    class Receiver( java.lang.Runnable ):
        '''A Class that receives UDP packets, and will bring the frame
           parameter to the front if the packet contains the open file name
           of the Commander instance passed in'''
        
        def __init__( self, frame, c ):
            self.frame = frame
            self.c = c
            
            
        def run( self ):
            
            s = java.lang.String( self.c.mFileName )
            random = java.util.Random( s.hashCode() )
            i = 0
            while i <= 2000:
                i = random.nextInt( 65535 + 1 )
            
            ia = java.net.InetAddress.getByName( "127.0.0.1" )
            mcs = java.net.DatagramSocket( i , ia )
            
            import jarray
            s = java.lang.String( self.c.mFileName )
            bytes = s.getBytes()
            
            while 1:
                
                try:
                    array = jarray.zeros( len( bytes ), 'b' )
                    dgp = java.net.DatagramPacket( array, len( bytes ))
                    dgp.setPort(i)
                    dgp.setAddress( ia )
                    mcs.receive( dgp )
                    nexts = java.lang.String( dgp.getData() )
                    
                    if nexts.equals( s ):
                        self.frame.top.setVisible( True )
                        self.frame.top.setState( self.frame.top.NORMAL )
                        self.frame.top.toFront()
                        self.frame.body.editor.editor.requestFocusInWindow()
                        
                        
                        
                except java.lang.Exception, x:
                    x.printStackTrace()
                
    #@nonl
    #@-node:zorcanda!.20050419095522:class Receiver
    #@+node:zorcanda!.20051127195123:class GlassPane2
    class GlassPane2( swing.JPanel ):
        
        def __init__( self ):
            swing.JPanel.__init__( self )
            self.setOpaque( False )
            self.alpha = awt.AlphaComposite.getInstance( awt.AlphaComposite.SRC_OVER, float(0.5) )
            self.image = None
            self.setLayout( None )
            
            
        def setImage( self, image ):
            self.image = image
            if image:
                self.setVisible( True )
            else: self.setVisible( False )
            
        
        def phaseIn( self, widget ):
            
            psize = widget.getPreferredSize()
            self.add( widget )
            bi = awt.image.BufferedImage( psize.width, psize.height, awt.image.BufferedImage.TYPE_INT_RGB )
            g = bi.createGraphics()
            widget.paint( g )
            self.remove( widget )
            g.dispose()
            self.setVisible( True )
            self.Phaser( widget, bi, self )
            
        class Phaser( aevent.ActionListener ):
            def __init__( self, widget, image, parent ):
                self.widget = widget
                self.parent = parent
                self.image = image
                self.increments = 20
                self.waitperiod = 1000/self.increments
                self.timer = swing.Timer( self.waitperiod, self )
                self.timer.start()
                
            def actionPerformed( self, event ):
    
                alpha = 1.0/self.increments
                g = self.parent.getGraphics()
                spot = self.widget.getLocation()
                ac = awt.AlphaComposite.getInstance( awt.AlphaComposite.SRC_OVER, alpha )
                g.setComposite( ac )
                g.drawImage( self.image, spot.x, spot.y, None )
                g.dispose()
                self.increments -= 1
                if self.increments == 0:
                    self.timer.stop()
                    self.parent.add( self.widget )
                    self.parent.revalidate()
           
        def paintComponent2( self, g ):
            
            if not self.image: return
            
            composite = g.getComposite()
            mpi = awt.MouseInfo.getPointerInfo()
            location = mpi.getLocation()
            swing.SwingUtilities.convertPointFromScreen( location, self )
            g.setComposite( self.alpha )
            g.drawImage( self.image, location.x, location.y, None )
            g.setComposite( composite )
            
    
    
    #@-node:zorcanda!.20051127195123:class GlassPane2
    #@+node:orkman.20050213143403:class NodeBar
    import java.awt.datatransfer as dtfr
    class NodeBar( dtfr.FlavorListener, java.lang.Runnable ):
        '''This class creates a toolbar that offers the user the ability to manipulate nodes
            with a button press.'''
        
        #@    @+others
        #@+node:orkman.20050213143424:images
        #@+at
        # nodeup = 
        # r'''R0lGODlhEAAQAIABAENMzf///yH+FUNyZWF0ZWQgd2l0aCBUaGUgR0lNUAAsAAAAABAAEAAAAhqM
        # j6nL7QDcgVBS2u5dWqfeTWA4lqYnpeqqFgA7'''
        # nodedown = 
        # r'''R0lGODlhEAAQAIABAENMzf///yH+FUNyZWF0ZWQgd2l0aCBUaGUgR0lNUAAsAAAAABAAEAAAAhuM
        # j6nL7Q2inLTaGW49Wqa+XBD1YE8GnOrKBgUAOw=='''
        # nodeleft = 
        # r'''R0lGODlhEAAQAIABAENMzf///yH+FUNyZWF0ZWQgd2l0aCBUaGUgR0lNUAAsAAAAABAAEAAAAiOM
        # jwDIqd3Ug0dOam/MC3JdfR0jjuRHBWjKpUbmvlIsm65WAAA7'''
        # noderight = 
        # r'''R0lGODlhEAAQAIABAENMzf///yH+FUNyZWF0ZWQgd2l0aCBUaGUgR0lNUAAsAAAAABAAEAAAAiGM
        # A3DLltrag/FMWi+WuiK9WWD4gdGYdenklUnrwqX8tQUAOw=='''
        # clone = 
        # r'''R0lGODlhEAAQAIABAP8AAP///yH+FUNyZWF0ZWQgd2l0aCBUaGUgR0lNUAAsAAAAABAAEAAAAhaM
        # j6nL7Q8jBDRWG8DThjvqSeJIlkgBADs='''
        # copy = 
        # r'''R0lGODlhEAAQAMIEAAAAAI9pLOcxcaCclf///////////////ywAAAAAEAAQAAADLEi63P5vSLiC
        # vYHiq6+wXSB8mQKcJ2GNLAssr0fCaOyB0IY/ekn9wKBwSEgAADs='''
        # cut = 
        # r'''R0lGODlhEAAQAKECAAAAAKCclf///////yH+FUNyZWF0ZWQgd2l0aCBUaGUgR0lNUAAsAAAAABAA
        # EAAAAiaUDad7yS8cnDNYi4A0t7vNaCLTXR/ZZSBFrZMLbaIWzhLczCxTAAA7'''
        # paste = 
        # r'''R0lGODlhEAAQAKECAAAAAB89vP///////yH+FUNyZWF0ZWQgd2l0aCBUaGUgR0lNUAAsAAAAABAA
        # EAAAAiOUH3nLktHYm9HMV92FWfPugQcgjqVBnmm5dsD7gmsbwfEZFQA7'''
        # insert = 
        # r'''R0lGODlhEAAQAKECAAAAAB89vP///////ywAAAAAEAAQAAACKJRhqSvIDGJ8yjWa5MQ5BX4JwXdo
        # 3RiYRyeSjRqKmGZRVv3Q4M73VAEAOw=='''
        # demote = 
        # r'''R0lGODlhEAAQAKECACMj3ucxcf///////yH+FUNyZWF0ZWQgd2l0aCBUaGUgR0lNUAAsAAAAABAA
        # EAAAAiiUj2nBrNniW+G4eSmulqssgAgoduYWeZ+kANPkCsBM1/abxLih70gBADs='''
        # promote = 
        # r'''R0lGODlhEAAQAKECACMj3ucxcf///////yH+FUNyZWF0ZWQgd2l0aCBUaGUgR0lNUAAsAAAAABAA
        # EAAAAiWUj6kX7cvcgy1CUU1ecvJ+YUGIbKSJAAlqqGQLxPI8t29650YBADs='''
        # pasteclone = 
        # r'''R0lGODlhEAAQAKEDACMj3v8AAP/9/f///ywAAAAAEAAQAAACOJSPaTPgoxBzgEVDM4yZbtU91/R8
        # ClkJzGqp7MK21rcG9tYedSCb7sDjwRLAGs7HsPF8khjzcigAADs='''
        # hoist = 
        # r'''R0lGODlhEAAQAKECAAAAAENMzf/9/f/9/SwAAAAAEAAQAAACI5SPaRCtypp7S9rw4sVwzwQYW4ZY
        # JAWhqYqE7OG+QvzSrI0WADs='''
        # dehoist = 
        # r'''R0lGODlhEAAQAKECAAAAACMj3v/9/f/9/SH+FUNyZWF0ZWQgd2l0aCBUaGUgR0lNUAAsAAAAABAA
        # EAAAAiOUj6lrwOteivLQKi4LXCcOegJIBmIZLminklbLISIzQ9hbAAA7'''
        # question = 
        # r'''R0lGODlhEAAQAIABAB89vP///yH+FUNyZWF0ZWQgd2l0aCBUaGUgR0lNUAAsAAAAABAAEAAAAiCM
        # DwnHrNrcgzFQGuGrMnGEfdtnjKRJpt2SsuxZqqgaFQA7'''
        # sortchildren = 
        # r'''R0lGODlhEAAQAKECAAAAAB89vP/9/f/9/SwAAAAAEAAQAAACJJSPKcGt2NwzbKpqYcg68oN9ITde
        # UQCkKgCeCvutsDXPk/wlBQA7'''
        # sortsiblings = 
        # r'''R0lGODlhEAAQAKECAAAAAB89vP/9/f/9/SH+FUNyZWF0ZWQgd2l0aCBUaGUgR0lNUAAsAAAAABAA
        # EAAAAiWUFalxbatcS7IiZh3NE2L+fOAGXpknal4JlAIAw2Br0Fksu1YBADs='''
        # delete = 
        # r'''R0lGODlhEAAQAMIEAAAAAB89vKCclbq3sv///////////////yH+FUNyZWF0ZWQgd2l0aCBUaGUg
        # R0lNUAAsAAAAABAAEAAAAzJIutwKELoGVp02Xmy5294zDSSlBAupMleAEhoYuahaOq4yCPswvYQe
        # LyT0eYpEW8iRAAA7'''
        # moveup = 
        # r'''R0lGODlhEAAQAIABAENMzf///yH+FUNyZWF0ZWQgd2l0aCBUaGUgR0lNUAAsAAAAABAAEAAAAh6M
        # j6nL7QDcgVDWcFfGUW3zfVPHPZHoUeq6Su4LwwUAOw=='''
        # movedown = 
        # r'''R0lGODlhEAAQAIABAENMzf///yH+FUNyZWF0ZWQgd2l0aCBUaGUgR0lNUAAsAAAAABAAEAAAAh+M
        # j6nL7Q2inFS+EDFw2XT1eVsSHmGJdChpXesFx00BADs='''
        # moveleft = 
        # r'''R0lGODlhEAAQAIABAENMzf///yH+FUNyZWF0ZWQgd2l0aCBUaGUgR0lNUAAsAAAAABAAEAAAAiWM
        # jwDIqd3egueFSe2lF2+oGV41fkwoZmNJJlxXvbDJSbKI1l4BADs='''
        # moveright = 
        # r'''R0lGODlhEAAQAIABAENMzf///yH+FUNyZWF0ZWQgd2l0aCBUaGUgR0lNUAAsAAAAABAAEAAAAiWM
        # A3DLltqaSpFBWt3BFTovWeAyIiUinSNnkaf2Zagpo2x343IBADs='''
        #@-at
        #@@c
        
        
        
        #@-node:orkman.20050213143424:images
        #@+node:orkman.20050213144830:def __init__
        def __init__( self, c, toolbar ):
            
            self.c = c
            bcommands = ( 
                          ( c.moveOutlineUp, "nodeup.gif", 'Move Node Up', c.canMoveOutlineUp ),
                          ( c.moveOutlineDown, "nodedown.gif" , 'Move Node Down', c.canMoveOutlineDown ),
                          ( c.moveOutlineLeft, "nodeleft.gif" , 'Move Node Left' , c.canMoveOutlineLeft),
                          ( c.moveOutlineRight, "noderight.gif", 'Move Node Right', c.canMoveOutlineRight ),
                          ( c.clone, "clone.gif" , 'Clone Node', c.canClone ),
                          ( c.copyOutline, "copy.gif", 'Copy Node', 0 ),
                          ( c.cutOutline, "cut.gif", 'Cut Node', c.canCutOutline ),
                          ( c.deleteOutline, "delete.gif", 'Delete Node', c.canDeleteHeadline ),
                          ( c.pasteOutline, "paste.gif" , 'Paste Node', c.canPasteOutline ),
                          ( c.pasteOutlineRetainingClones, "pasteclone.gif", 'Paste Retaining Clones', c.canPasteOutline ),
                          ( c.insertHeadline, "insert.gif", 'Insert Node', 0 ),
                          ( c.demote, "demote.gif", 'Demote', c.canDemote ),
                          ( c.promote, "promote.gif" , 'Promote', c.canPromote ) ,
                          ( c.hoist, "hoist.gif", 'Hoist', c.canHoist),
                          ( c.dehoist, "dehoist.gif", 'De-Hoist', c.canDehoist ),
                          ( c.sortChildren, "sortchildren.gif", 'Sort Children', c.canSortChildren ),
                          ( c.sortSiblings, "sortsiblings.gif", 'Sort Siblings', c.canSortSiblings ),
                          ( c.goToPrevSibling, "moveup.gif", 'Goto Previous Sibling', self.canGotoPreviousSibling ),
                          ( c.goToNextSibling, "movedown.gif", 'Goto Next Sibling', self.canGotoNextSibling ),
                          ( c.goToParent, "moveleft.gif", 'Goto Parent', self.canGotoParent ),
                          ( self.goToChild, "moveright.gif", 'Goto Child', self.canGotoChild ),
                          )
            
            self.buttons_enabled = {}             
            for z in bcommands:
                button = self.createButton( z[ 1 ] )
                button.setToolTipText( z[ 2 ] )
                button.actionPerformed = self.getCallback( z[ 0 ] )
                if z[ 3 ]: self.buttons_enabled[ button ] = z[ 3 ]
                toolbar.add( button )
            
            wm1 = WeakMethod( self, "endUpdate" )
            leoPlugins.registerHandler( "select1", wm1 )  
            leoPlugins.registerHandler( "chapter-changed", wm1 )
            leoPlugins.registerHandler( "chapter-removed", wm1 )      
            leoPlugins.registerHandler( "hoist-executed", wm1 )
            leoPlugins.registerHandler( "dehoist-executed", wm1 )
            #--> disable for now, this seems to flaky behavorialy, but the idea is good
            #tk = java.awt.Toolkit.getDefaultToolkit()
            #clipboard = tk.getSystemClipboard()
            #clipboard.addFlavorListener( self )
            self.runs = 0
            
        def getCallback( self, command ):
            
            def callback(self,event =None, c= self.c):
                command()
        
                
            return callback
        
        #@-node:orkman.20050213144830:def __init__
        #@+node:zorcanda!.20050928130443:flavorsChanged
        def flavorsChanged( self, event ):
            
            #print event
            #print event.getSource()
            cb = event.getSource()
            #print cb.getName()
            #import java.awt.datatransfer as dtfr
            #print cb.getData( dtfr.DataFlavor.stringFlavor )
            #print cb.getAvailableDataFlavors()
            self.endUpdate( "flavor-change", { 'c' : self.c } )
        #@nonl
        #@-node:zorcanda!.20050928130443:flavorsChanged
        #@+node:zorcanda!.20050928111249:goto enablers
        def canGotoParent( self ):
            
            cp = self.c.currentPosition()
            if not cp: return False
            parent = cp.getParent()
            if parent:
                return True
            return False
            
            
        def canGotoChild( self ):
            
            cp = self.c.currentPosition()
            if not cp: return False
            nc = cp.numberOfChildren()
            if nc != 0: return True
            return False
            
        def canGotoPreviousSibling( self ):
            
            cp = self.c.currentPosition()
            if not cp: return False
            psibling = cp.moveToBack()
            if psibling:
                return True
            return False
            
        def canGotoNextSibling( self ):
            
            cp = self.c.currentPosition()
            if not cp: return False
            nsibling = cp.moveToNext()
            if nsibling:
                return True
            return False
        #@nonl
        #@-node:zorcanda!.20050928111249:goto enablers
        #@+node:orkman.20050213145256.1:def createButton
        def createButton( self, name ):
            
            #bytes = java.lang.String( base64.decodestring( data ) ).getBytes()
            
            path = g.os_path_join( g.app.loadDir,"..","Icons/nodebar",name)
            ii = swing.ImageIcon( path )
            jb = swing.JButton( ii )
            #size = awt.Dimension( ii.getIconWidth(), ii.getIconHeight() )
            return jb
            
        #@-node:orkman.20050213145256.1:def createButton
        #@+node:orkman.20050213150926:def gotoChild
        def goToChild( self ):
                
            pos = self.c.currentPosition()
            if pos.hasChildren():
                self.c.beginUpdate()
                self.c.selectPosition( pos.nthChild( 0 ) )
                self.c.endUpdate()
        #@nonl
        #@-node:orkman.20050213150926:def gotoChild
        #@+node:zorcanda!.20050928105321:endUpdate
        def endUpdate( self, tag, *args, **kwords ):
            
            c = args[ 0 ][ 'c' ]
            #print tag
            if c == self.c:
                swing.SwingUtilities.invokeLater( self )
            else:
                print "C %s not == to %s" % ( c, self.c )
        
        
        def run( self ):
            
            try:
                #print "RUN NUMBER %s" % self.runs
                self.runs += 1
                for z in self.buttons_enabled:
                    button = z
                    callback = self.buttons_enabled[ z ]
                    #print callback
                    if callback():
                        button.setEnabled( 1 )
                    else:
                        button.setEnabled( 0 )
            except:
                print "BOOM!!"
                    
        #@-node:zorcanda!.20050928105321:endUpdate
        #@-others
        
    #@-node:orkman.20050213143403:class NodeBar
    #@+node:zorcanda!.20051215090906:class WindowClosingWatcher
    class WindowClosingWatcher( aevent.WindowAdapter ):
        
        def __init__( self, frame ):
            aevent.WindowAdapter.__init__( self )
            self.frame = frame
            
        def windowClosing( self, event ):
            
    	    g.app.closeLeoWindow( self.frame )
            if len( g.app.windowList ) == 0:
                java.lang.System.exit( 0 )
    #@nonl
    #@-node:zorcanda!.20051215090906:class WindowClosingWatcher
    #@+node:zorcanda!.20051218230218:class LeoMetalTheme
    class LeoMetalTheme( swing.plaf.metal.DefaultMetalTheme ):
        
        def __init__( self, c ):
            
            swing.plaf.metal.DefaultMetalTheme.__init__( self )
            self.c = c
            self.p1 = swing.plaf.ColorUIResource( awt.Color.YELLOW )
            self.p3 = swing.plaf.ColorUIResource( awt.Color.YELLOW )
            self.p2 = swing.plaf.ColorUIResource( awt.Color.YELLOW )
            self.s1 = swing.plaf.ColorUIResource( awt.Color.YELLOW )
            self.s2 = swing.plaf.ColorUIResource( awt.Color.YELLOW )
            self.s3 = swing.plaf.ColorUIResource( awt.Color.YELLOW )
            
            print self.p1, self.p2, self.p3, self.s1, self.s2, self.s3
            
        def getName( self ):
            return "LeoMetalTheme"
            
        def getControlTextFont2( self ):
            pass
        
        def getMenuTextFont2( self ):
            pass
            
        def getPrimary1( self ):
            print 'p1'
            return self.p1
            
        def getPrimary2( self ):
            print 'p2'
            return self.p2
            
        def getPrimary3( self ):
            print 'p3'
            return self.p3
            
        def getSecondary1( self ):
            print "s1"
            return self.s1
            
        def getSecondary2( self ):
            print "s2"
            return self.s2
            
        def getSecondary3( self ):
            print "s3"
            return self.s3
        
        def getBlack2( self ):
            print "BLACK"
            return swing.plaf.ColorUIResource( awt.Color.YELLOW )
            
        def getMenuBackground( self ):
            print "GMB"
            return self.getWhite()
        
        def getMenuForeground( self ):
            print "MFG"
            return self.getBlack()
            
        def getMenuSelectedForeground( self ):
            print "MSFG!"
            return swing.plaf.ColorUIResource( awt.Color.YELLOW )
            
        def getMenuSelectedBackground( self ):
            print "MSBG"
            return swing.plaf.ColorUIResource( awt.Color.YELLOW )
        
        def getPrimaryControl( self ):
            print "PCONTROL"
            return swing.plaf.ColorUIResource( awt.Color.YELLOW )
        
        def getControl( self ):
            print "CONTROL"
            return swing.plaf.ColorUIResource( awt.Color.YELLOW )
            
        def getControlHighlight( self ):
            return swing.plaf.ColorUIResource( awt.Color.YELLOW )
            
        def getPrimaryControlHighlight( self ):
            return swing.plaf.ColorUIResource( awt.Color.YELLOW )
            
        def getSystemTextColor( self ):
            return swing.plaf.ColorUIResource( awt.Color.WHITE )
           
        def getSubTextFont2( self ):
            pass
            
        def getSystemTextFont2( self ):
            pass
            
        def getUserTextFont2( self ):
            pass
            
        def getWindowTitleFont2( self ):
            pass
        
            
            
    #@nonl
    #@-node:zorcanda!.20051218230218:class LeoMetalTheme
    #@-others
    #@-node:zorcanda!.20051206140225:helper classes
    #@-others
#@nonl
#@-node:mork.20050127125058.55:class leoSwingFrame
#@+node:mork.20050127125058.73:class leoSwingLog
class leoSwingLog:
    
    """The base class for the log pane in Leo windows."""
    
    #@    @+others
    #@+node:mork.20050127125058.74:leoLog.__init__
    def __init__ (self,frame,parentFrame):
        
        self._font = None
        self.jta = None
        #leoFrame.leoLog.__init__( self, frame, parentFrame )
        self.frame = frame
        self.c = frame.c
        self.enabled = True
        self.newlines = 0
    
        # Note: self.logCtrl is None for nullLog's.
        self.logCtrl = self.createControl(parentFrame)
        self.setFontFromConfig()
        self.setColorFromConfig()
        
        #self.c = frame.c
        self._font = None
        
        manager = g.app.config.manager
        for z in ( "log_pane_background_color", "log_text_foreground_color", "log_text_background_color" ):
            manager.addNotificationDef( z, self.setColorFromConfig )
        for z in ( "log_text_font_family", "log_text_font_size" ,  "log_text_font_weight" ):
            manager.addNotificationDef( z, self.setFontFromConfig )
    
    
    #@-node:mork.20050127125058.74:leoLog.__init__
    #@+node:mork.20050127125058.75:leoLog.configure
    def configure (self,*args,**keys):
        
        self.oops()
    #@nonl
    #@-node:mork.20050127125058.75:leoLog.configure
    #@+node:mork.20050127125058.76:leoLog.configureBorder
    def configureBorder(self,border):
        
        self.oops()
    #@-node:mork.20050127125058.76:leoLog.configureBorder
    #@+node:mork.20050127125058.77:leoLog.createControl
    def createControl (self,parentFrame):
        
        self.tab_manager = TabManager( switch_on_add = 0 )
        self.tab_manager.tabsToBottom()
        self._jtp = jtp = self.tab_manager.base
                
        self.logCtrl = logCtrl = self.jta = self.LogControl()
        self.logCtrl.setFocusable( True );
        logCtrl.setName( "Log" )
        import utilities.CutCopyPaste as CCP
        CCP.CutCopyPaste( logCtrl )
        self.setColorFromConfig()
        
        if self._font:
            logCtrl.setFont( self._font )
        self.jsp = swing.JScrollPane( logCtrl )
    
        self.tab_manager.add( "Log", self.jsp )
        logCtrl.addFocusListener( leoJSPFocusListener( self.jsp, self.c ) )
        parentFrame.rightComponent = jtp
        self.setBackgroundImage()
        g.doHook( "leoswinglogcreated", c = self.c, log = self )
        
    
    
    
    #@-node:mork.20050127125058.77:leoLog.createControl
    #@+node:zorcanda!.20051105192816:class LogControl
    class LogControl( swing.JTextPane ):
        
        def __init__( self, *args ):
            swing.JTextPane.__init__( self, *args )
            self.alpha = awt.AlphaComposite.getInstance( awt.AlphaComposite.SRC_OVER, 1.0 )
            self.lastDimensions = awt.Rectangle( 0,0,0,0 )
            self.image = None
            self.last_image= None
            
            
        def setAlpha( self, alpha ):
            self.alpha = awt.AlphaComposite.getInstance( awt.AlphaComposite.SRC_OVER, alpha )
            
        
        def setImage( self, image ):
            self.image = image
            
            
        def paintComponent( self, graphics ):
            
            #self.super__paintComponent( graphics )
            if self.image:
                vrec = self.getVisibleRect()
                if not self.lastDimensions.equals( vrec ):
                    self.lastDimensions = vrec
                    self.last_image = self.image.getScaledInstance( vrec.width, vrec.height, awt.Image.SCALE_REPLICATE )
                composite = graphics.getComposite()
                graphics.setComposite( self.alpha )
                graphics.drawImage( self.last_image, vrec.x, vrec.y, awt.Color.WHITE, None )
                graphics.setComposite( composite )       
            self.super__paintComponent( graphics )
            
            
    #@nonl
    #@-node:zorcanda!.20051105192816:class LogControl
    #@+node:zorcanda!.20050805120914:setBackgroundImage
    def setBackgroundImage( self, notification = None, handback = None ):
        
        c = self.c
        
    
        use_background = g.app.config.getBool( c, "log_use_background_image" )    
        if not use_background:
            return
            
        alpha = g.app.config.getFloat( c, "log_background_alpha" )
        if alpha == None: alpha = 1.0
        image_path = g.app.config.getString( c, "log_image_location@as-filedialog" )
        if image_path:
            imfile = java.io.File( image_path ) 
            if imfile.exists():
                bimage = imageio.ImageIO.read( imfile )
                #if not hasattr( self, 'background' ): 
                #self.background = EditorBackground( bimage, bimage.getWidth(), bimage.getHeight(), alpha )
                #self.layeredpane.add( self.background, self.layeredpane.DEFAULT_LAYER )
                #self.logBackPane.add( self.background )
                #self.jsp.getViewport().addChangeListener( self.resizer( self.jsp, self.logBackPane ) )
                #self._vport.addChangeListener( self._resizer )
                #self.editor.setOpaque( False )
                #self.jtree.setOpaque( False )
                #self.jpanel.setOpaque( False )
                #self.jspane.setOpaque( False )
                #self.jspane.getViewport().setOpaque( False )
                #self.logCtrl.setOpaque( False )
                #self.jsp.getViewport().setOpaque( False )
                #self.jsp.setOpaque( False )
                self.logCtrl.setOpaque( False )
                self.logCtrl.setImage( bimage )
                self.logCtrl.setAlpha( alpha )
                g.app.config.manager.addNotificationDef( "log_background_alpha", self.setBackgroundImage )
                g.app.config.manager.addNotificationDef( "log_image_location@as-filedialog", self.setBackgroundImage )
                      
                #else:
                #    self.background.setBackground( bimage, bimage.getWidth(), bimage.getHeight(), alpha )
                #    self.background.repaint()
    
    
    
    #@-node:zorcanda!.20050805120914:setBackgroundImage
    #@+node:mork.20050127125058.78:leoLog.enable & disable
    def enable (self,enabled=True):
        
        self.enabled = enabled
        
    def disable (self):
        
        self.enabled = False
    #@-node:mork.20050127125058.78:leoLog.enable & disable
    #@+node:mork.20050127125058.79:leoLog.oops
    def oops (self):
        
        print "leoLog oops:", g.callerName(2), "should be overridden in subclass"
    #@nonl
    #@-node:mork.20050127125058.79:leoLog.oops
    #@+node:zorcanda!.20050308093929:leoLog setColorFromConfig
    def setColorFromConfig( self, notification = None, handback = None ):
        
        logCtrl = self.jta
        if logCtrl:
            color = g.app.config.getColor( self.c , "log_pane_background_color" )
            logCtrl.setBackground( getColorInstance( color, awt.Color.WHITE ) )
            color = g.app.config.getColor( self.c, "log_text_foreground_color" )
            logCtrl.setForeground( getColorInstance( color, awt.Color.GRAY ) ) 
            color = g.app.config.getColor( self.c, "log_text_background_color" )
            logCtrl.setSelectionColor( getColorInstance( color, awt.Color.GREEN ) )
    
    #@-node:zorcanda!.20050308093929:leoLog setColorFromConfig
    #@+node:mork.20050127125058.80:leoLog.setFontFromConfig
    def setFontFromConfig (self, notification = None, handback = None):
        
        logCtrl = self.jta ; config = g.app.config
    
        font = config.getFontFromParams( self.c,
            "log_text_font_family", "log_text_font_size",
            "log_text_font_slant",  "log_text_font_weight",
            config.defaultLogFontSize)
        
        if font:
            #awt_font = awt.Font.decode( font )
            self._font = font
            if logCtrl:
                logCtrl.setFont( font )
    
              
    
            
    
    #@-node:mork.20050127125058.80:leoLog.setFontFromConfig
    #@+node:mork.20050127125058.81:leoLog.onActivateLog
    def onActivateLog (self,event=None):
    
        try:
            g.app.setLog(self,"OnActivateLog")
        except:
            g.es_event_exception("activate log")
    #@nonl
    #@-node:mork.20050127125058.81:leoLog.onActivateLog
    #@+node:mork.20050127125058.82:leoLog.put & putnl
    # All output to the log stream eventually comes here.
    
    def put (self,s,color=None):
        
        if self.jta:
            pos = self.jta.getCaretPosition()
            document = self.jta.getStyledDocument()
            attrset = None
    
            if color:
                if hasattr( awt.Color, color ):
                    attrcolor = getattr( awt.Color, color )
                    attrset = stext.SimpleAttributeSet()
                    stext.StyleConstants.setForeground( attrset, attrcolor  )
            
            document.insertString( document.getLength(), s, attrset )
            npos = document.getLength() - len( s )
            self.jta.setCaretPosition( npos )
        else:
            g.app.logWaiting.append( ( s , color ) )
        
        if leoSwingGui.splash.isVisible():
            leoSwingGui.splash.setText( s )
    
    
    def putnl (self):
    
        if self.jta:
            doc = self.jta.getStyledDocument()
            doc.insertString( doc.getLength(), "\n", None )
        else:
            g.app.logWaiting.append( '\n' )
    
        
    
        
        
    #@nonl
    #@-node:mork.20050127125058.82:leoLog.put & putnl
    #@+node:zorcanda!.20050907144441:addTab
    def addTab( self, name, component ):
        
        self.tab_manager.add( name, component )
        
    
    def selectTab( self, component ):
        self.tab_manager.select( component )
       
    def removeTab( self, component ):
        
        self.tab_manager.remove( component )
        
    
    def getCurrentTab( self ):
        
        ctab = self.tab_manager.getCurrentTab()
        if ctab is None:
            return self.jta
        else:
            size = ctab.getSize()
            x = size.width/2
            y = size.height/2
            component = swing.SwingUtilities.getDeepestComponentAt( ctab, x, y )
            return component
    #@-node:zorcanda!.20050907144441:addTab
    #@-others
#@nonl
#@-node:mork.20050127125058.73:class leoSwingLog
#@+node:mork.20050127125058.83:class leoSwingTree
# This would be useful if we removed all the tree redirection routines.
# However, those routines are pretty ingrained into Leo...

class leoSwingTree( sevent.TreeSelectionListener, java.lang.Runnable, aevent.FocusListener ):   
    
    """The base class for the outline pane in Leo windows."""
    
    
    positions = java.util.WeakHashMap() #For storing where a node has last been edited
    icons = jarray.zeros( 16, swing.ImageIcon )
    for z in xrange( 16 ):
        num = '%s' % z
        if z < 10: num = '%s%s' %( 0, num )
        ipath = g.os_path_join( g.app.loadDir,"..","Icons","box%s.GIF" % num )
        icons[ z ] = swing.ImageIcon( ipath )
        
    commenticon = swing.ImageIcon( g.os_path_join( g.app.loadDir, "..", "Icons", "Cloud24.gif" ) )
#@+at
# for( int i = 0; i < _icons.length; i++ ){
#             String num = String.valueOf( i );
#             if( i < 10 ) num = "0" + num;
# _icons[ i ] = new ImageIcon( String.format( "../Icons/box%s.GIF" , num ) );
#     }
#@-at
#@@c

    #@    @+others
    #@+node:mork.20050127125058.84:  tree.__init__ (base class)
    def __init__ (self,frame, model = None, chapter = None ):
        
        #leoFrame.leoTree.__init__( self, frame )
        self.frame = frame
        self.c = c = frame.c
    
        
        # "public" ivars: correspond to setters & getters.
        self._editPosition = None
    
        # Controlling redraws
        self.updateCount = 0 # self.redraw does nothing unless this is zero.
        self.chapter = chapter
        self.loaded = False
        self._op = None
        self.skip_reload = 0
        self.view_controls = self.ViewControls()
        self.center = center = self.view_controls.addControl( "Outline", lambda : 1, None, checkmark = 1 )
    
    
        
        if model:
            self.posTM = model
        else:
            self.posTM = self.posTreeModel( self.c )
        self.jtree = jtree = self.JTree2( self.posTM )
        jtree.setFocusable( True )
        jtree.setRowHeight( -1 )#ensures that the renderer component's size is used
        self.setBackgroundColor()
        #self.setFontFromConfig()
        g.app.config.manager.addNotificationDef( "outline_pane_background_color", self.setBackgroundColor )
        config = g.app.config
        color = g.app.config.getColor( self.c, "headline_text_unselected_foreground_color" )
        tfg = getColorInstance( color, awt.Color.BLACK )
        color = g.app.config.getColor( self.c, "headline_text_unselected_background_color" )
        tbg = getColorInstance( color, awt.Color.WHITE )
        do_brackets = config.getBool( self.c, "headline_do_bracket_color" )
        color = config.getColor( self.c, "headline_bracket_color" )
        bracket_color = getColorInstance( color, awt.Color.BLUE )
        do_directives = config.getBool( self.c, "headline_do_directive_color" )
        color = config.getColor( self.c, "headline_directive_color" )
        directive_color = getColorInstance( color, awt.Color.GREEN )
        
        import leoNodes
        tnode = leoNodes.tnode()
        v = leoNodes.vnode( self.c, tnode )
        def getValue( names, self = v ):
            return names
        olFindAtFileName = v.findAtFileName
        v.findAtFileName = getValue
        names = v.anyAtFileNodeName()
        v.findAtFileName = olFindAtFileName
        names = list( names )
        hmap = java.util.HashMap()
        for z in names: hmap.put( z, None )
       
        self.renderer = leoIconTreeRenderer( self.posTM._root, self.icons,
                                             tfg, tbg,
                                             do_brackets, bracket_color,
                                             do_directives, directive_color,
                                             hmap
                                             )
                                             
        self.renderer.setCommentIcon( self.commenticon )
        xxx = lambda : self.jtree.setCellRenderer( self.renderer )
        dc = DefCallable( xxx )
        ft = dc.wrappedAsFutureTask()
        swing.SwingUtilities.invokeLater( ft )
        self.setFontFromConfig()
        self.renderer.setFont( self.jtree.getFont() )
        
        color = g.app.config.getColor( self.c, "headline_text_editing_foreground_color" )
        tefg = getColorInstance( color, awt.Color.BLACK )
        color = g.app.config.getColor( self.c, "headline_text_editing_background_color" )
        tebg = getColorInstance( color, awt.Color.WHITE )
        self.headlineEditor = leoHeadlineTreeCellEditor( self.c, tefg, tebg, leoSwingBody.Editor.icon )
        self.headlineEditor.setFont( self.jtree.getFont() )
        self.tcEdi = tcllEditor = self.tcellEditor( jtree, self.renderer, 
                                                    self.headlineEditor,
                                                    self.c )
        tcllEditor.addCellEditorListener( self.cellEditorListener( self.c ) )
        jtree.setCellEditor( tcllEditor )
        jtree.setRootVisible( False )
        jtree.setShowsRootHandles( True )
        jtree.getSelectionModel().setSelectionMode( stree.DefaultTreeSelectionModel.SINGLE_TREE_SELECTION )
        jtree.setScrollsOnExpand( True )
    
        self.jtree = jtree
        jtree.setTransferHandler( self.TreeTransferHandler( self.c, jtree ) )
        jtree.setDragEnabled( True ) 
        jtree.addTreeSelectionListener( self )
        jtree.editable = True
        self.jspane = swing.JScrollPane()
        #self.jspane.setViewport( JViewPort2() )
        
        #self.jspane = self.ZoomJSP()#swing.JScrollPane()
        #self.jspane.setViewport( self.ZoomView() )
        self.jspane.setViewportView( self.jtree )
        #self.jspane.getViewport().setOpaque( False )
        #self.jspane.setBackground( self.jtree.getBackground() )
        center.add( self.jspane )
        jtree.addFocusListener( leoJSPFocusListener( self.jspane, self.c ) )
        self.main_widget = parentpanel = swing.JRootPane()# swing.JPanel( awt.BorderLayout() )
        base = self.view_controls.getBase()
        parentpanel.getContentPane().add( base )
        parentpanel.getGlassPane().setLayout( None )
        
    
    #@+at
    #     zoom = swing.JMenu( "Zoom" )
    #     def setScale( scale, jtree = jtree ): #zoomer = zoomer, jtree = 
    # jtree ):
    #         double = java.lang.Double( scale )
    #         sval = double.doubleValue()/100
    #         #zoomer.setScale( sval )
    #         jtree.setScale( sval )
    #     buttongroup = swing.ButtonGroup()
    #     for z in ( 25, 50, 75, 100, 150, 200, 300, 400 ):
    #         jmi = swing.JCheckBoxMenuItem( str( z ) + "%" )
    #         zoom.add( jmi )
    #         buttongroup.add( jmi )
    #         if z == 100: jmi.setState( True )
    #         jmi.actionPerformed = lambda event, scale = z: setScale( scale )
    #     jmb.add( zoom )
    #@-at
    #@@c
        
        self.current = self.jspane
        cpane = frame.jsp1
    
        self._dragging = False
        self._editPosition = None
    
    
        self.reloading = False
        self.paths = False
        self.settingPosition = False
        self.lastHoistStackLength = 0
        self.configureMedia()
        g.doHook("swingtreecreated", tree = self, view_controls = self.view_controls, c = self.c) 
        
    
    
    
    #@-node:mork.20050127125058.84:  tree.__init__ (base class)
    #@+node:zorcanda!.20051206134057:createAuxilaryWidgets
    def createAuxilaryWidgets( self ):
        
        parentpanel = self.main_widget
        jtree = self.jtree
        c = self.c
        jmb = swing.JMenuBar()
        self.view_controls.setMenuBar( jmb )
        parentpanel.add( jmb, java.awt.BorderLayout.NORTH )    
        pue = self.PopupEnabler( c )
        jtree.addMouseListener( pue )
        self._EditLabelEnabler = self.EditLabelEnabler( self.jtree , self.headlineEditor)
        jtree.addFocusListener( self )
    #@-node:zorcanda!.20051206134057:createAuxilaryWidgets
    #@+node:zorcanda!.20050924210317:getWidget
    def getWidget( self ):
        
        return self.main_widget
        
    #@-node:zorcanda!.20050924210317:getWidget
    #@+node:zorcanda!.20051206140337:Tree Widget..
    #@+others
    #@+node:zorcanda!.20050929204655:class JTree2
    class JTree2( swing.JTree ):
        
        def __init__( self, model ):
            self.posTM = model
            swing.JTree.__init__( self, model )
            self.lastDimensions = awt.Rectangle( 0, 0,0,0 )
            self.last_image = None
            self.image = None
            self.alpha = awt.AlphaComposite.getInstance( awt.AlphaComposite.SRC_OVER, 1.0 ) 
            #self.setOpaque( False )
            self.canPaint = True
            
    
        def setImage( self, image ):
            self.image = image
            
        def setAlpha( self, alpha ):
            self.alpha = awt.AlphaComposite.getInstance( awt.AlphaComposite.SRC_OVER, alpha )
            
    
            
        def paintComponent( self, graphics ):
            
            if self.image:
                vrec = self.getVisibleRect()
                if not self.lastDimensions.equals( vrec ):
                    self.lastDimensions = vrec
                    self.last_image = self.image.getScaledInstance( vrec.width, vrec.height, awt.Image.SCALE_REPLICATE )
                composite = graphics.getComposite()
                graphics.setComposite( self.alpha )
    
                graphics.drawImage( self.last_image, vrec.x, vrec.y, awt.Color.WHITE, None )
                graphics.setComposite( composite ) 
    #@+at
    #         else:
    #             #clip = graphics.getClip();
    #             #bounds = clip.getBounds()
    #             paint = graphics.getPaint()
    #             color = self.getBackground()
    #             c1 = color.brighter()
    #             c2 = color.darker()
    #             vrect = self.getVisibleRect()
    #             gp = awt.GradientPaint( vrect.x, vrect.y, c1, vrect.x + 
    # vrect.width, vrect.y + vrect.height, c2, True )
    #             graphics.setPaint( gp )
    #             graphics.fillRect( vrect.x, vrect.y, vrect.width, 
    # vrect.height )
    #             graphics.setPaint( paint )
    #@-at
    #@@c       
            self.super__paintComponent( graphics )#comes last, or no tree!!!
    
         
            
        def isExpanded( self, path ):
            
            if path.__class__ != stree.TreePath:
                path = self.getPathForRow( path )
                
            lc = path.getLastPathComponent()
            if lc == self.posTM._root:
                return True
            else:
                return lc.isExpanded()
        
        def setExpandedState( self, path, boolean ):
            
            if boolean:
                lc = path.getLastPathComponent()
                try:
                    self.fireTreeWillExpand( path )
                except:
                    return
                lc.expand()
                self.fireTreeExpanded( path )
            else:
                lc = path.getLastPathComponent()
                try:
                    self.fireTreeWillCollapse( path )
                except:
                    return
                lc.contract()
                self.fireTreeCollapsed( path )
            
        
        def getExpandedDescendants( self, path ):
            
    
            lc = path.getLastPathComponent()
            paths = java.util.Vector()
            expanders = []
            
            if lc == self.posTM._root:
                p = self.posTM.chapter.getRootPosition()
                cp = self.posTM.chapter.getCurrentPosition()
            else:
                p = lc.copy()
            rp = self.posTM.chapter.getRootPosition()
            stop_p = p.copy()
            
            while p:                
                expanded = p.isExpanded()
                #if p == stop_p and p != rp: expanded = True
                #elif stop_p == rp and not self.posTM.drunning: expanded = True
                #elif self.posTM.drunning and p == rp:
                #    expanded = True
                
                if expanded:
                    expanders.append( p.copy() )
                            
                if expanded:
                    if p.v.t._firstChild:
                        p.moveToFirstChild()
                    elif p and p.v._next:
                        p.moveToNext()
                    else:
                        while p:
                            p.moveToParent()
                            if p == stop_p and not p.isRoot(): 
                                p = None
                                break
                            if p and p.v._next:
                                p.moveToNext()
                                break
                            elif not p: break
                else:
                    if p.v._next:
                        p.moveToNext()
                    else:
                        while p:
                            p.moveToParent()
                            if p == stop_p and not p.isRoot(): 
                                p = None
                                break
                            if p and p.v._next:
                                p.moveToNext()
                                break
                            elif not p: break
            
            expanders.sort( self.sortNodes )
            while expanders:
                z = expanders.pop()
                path = self.posTM.getPathToRoot( z.copy(), masterlist = expanders )
                paths.add( path )
            return paths.elements()
        
    
        def sortNodes( self, node1, node2 ):
            
            l1 = node2.level()
            l2 = node2.level()
            if l1 > l2: return 1
            elif l1 < l2: return -1
            else: return 0
    
    
    #@-node:zorcanda!.20050929204655:class JTree2
    #@+node:zorcanda!.20051113133134:class ZoomJTree2
    #@+at
    # #experimental code....
    # #import PositionJTree
    # class JTree2( PositionJTree ):
    #     def __init__( self, model ):
    #         self.posTM = model
    #         print dir( self )
    #         PositionJTree.__init__( self, model )
    #     def getRootPosition( self ):
    #         return self.posTM.chapter.getRootPosition()
    #     def getPathToRoot( self, node ):
    #         return self.posTM.getPathToRoot( node )
    # 
    # 
    # class ZoomJSP( swing.JScrollPane ):
    #     def __init__( self ):
    #         swing.JScrollPane.__init__( self )
    #     def processEvent( self, event ):
    #         print event
    #         self.super__processEvent( event )
    # 
    # 
    # class ZoomView( swing.JViewport ):
    #     def __init__( self ):
    #         swing.JViewport.__init__( self )
    #     def processMouseEvent( self, me ):
    #         print me
    #         self.super__processMouseEvent( me )
    #     def processEvent( self, event ):
    #         print event
    #         self.super__processEvent( event )
    #     def getGraphics( self ):
    #         g = self.super__getGraphics()
    #         g.scale( 2.0, 2.0 )
    #         return g
    #     def paintComponent( self, g ):
    #         transform = g.getTransform()
    #         if transform.getScaleX() != 2.0:
    #             #print "ZOOMSCALE!!!!"
    #             g.scale( 2.0, 2.0 )
    #         self.super__paintComponent( g )
    #     def getViewPosition( self ):
    #         vp = self.super__getViewPosition()
    #         #print vp
    #         #vp.x = int( vp.x * 2.0 )
    #         #vp.y = int( vp.y * 2.0 )
    #         return vp
    #     def repaint2( self, *args ):
    #         print "REPAINT!"
    #         print args
    #         self.super__repaint( *args )
    #     def setViewSize2( self, d ):
    #         print d
    #         d.width= int(d.width * 2.0)
    #         d.height = int( d.height * 2.0 )
    #         print d
    #         self.super__setViewSize( d )
    #     def toViewCoordinates2( self, x ):
    #         print "x %s" % x
    #         x.width = int(x.width/2.0)
    #         x.height = int(x.height/2.0 )
    #         return self.super__toViewCoordinates( x )
    # 
    # class ZoomJTree2( swing.JTree ):
    #     def __init__( self, model ):
    #         self.posTM = model
    #         self.scale = 1.0
    #         self.pif = False
    #         #self.zilc = 0
    #         swing.JTree.__init__( self, model )
    #         #print "DOUBLE BUFFERED ? %s" % self.isDoubleBuffered()
    #         #self.setDoubleBuffered( True )
    #         self.lastDimensions = awt.Rectangle( 0, 0,0,0 )
    #         self.last_image = None
    #         self.image = None
    #         self.alpha = awt.AlphaComposite.getInstance( 
    # awt.AlphaComposite.SRC_OVER, 1.0 )
    #         #self.setOpaque( False )
    #         #tml2 = self.createTreeModelListener2()
    #         #model.addTreeModelListener( tml2 )
    #         #self.posTM = model
    #         #print "FIXED? %s" % self.isFixedRowHeight()
    #     def getPreferredSize( self ):
    #         psize = self.super__getPreferredSize()
    #         #if self.scale > 1.0:
    #         psize.width = int( psize.width * self.scale )
    #         psize.height = int( psize.height * self.scale )
    #         return psize
    #     def getPreferredScrollableViewportSize( self ):
    #         #print "GPSVS"
    #         dimension = self.super__getPreferredScrollableViewportSize()
    #         vrect = self.getVisibleRect()
    #         if vrect.width > dimension.width: dimension.width = vrect.width
    #         if vrect.height > dimension.height: dimension.height = 
    # vrect.height
    #         #print dimension
    #         return dimension
    #     def getScrollableBlockIncrement( self, vRect, orientation, direction 
    # ):
    #         rv = self.super__getScrollableBlockIncrement( vRect, 
    # orientation, direction )
    #         return int( rv * self.scale )
    #     def getScrollableUnitIncrement( self, vRect, orientation, direction 
    # ):
    #         rv = self.super__getScrollableUnitIncrement( vRect, orientation, 
    # direction )
    #         return int( rv * self.scale )
    #     def getGraphics( self ):
    #         g = self.super__getGraphics()
    #         if not self.pif:
    #             #vrect = self.getParent().getVisibleRect()
    #             #vrect2 = self.getVisibleRect()
    #             #print vrect, vrect2
    #             #g.setColor( self.getBackground() )
    #             #g.fillRect( vrect2.x, vrect2.y , vrect.width, vrect.height 
    # )
    #             #print "G PIF? %s %s" % ( self.pif, self.isEditing() )
    #             #if not self.pif:
    #             #if not self.isEditing():
    #             g.scale( self.scale, self.scale )
    #         return g
    #     def repaint2( self, *args ):
    #         print args
    #         if len( args ) == 1 and args[ 0 ].__class__ == awt.Rectangle:
    #             rect = args[ 0 ]
    #             rect.x = int( rect.x * self.scale )
    #             rect.y = int( rect.y * self.scale )
    #             if self.scale < 1.0:
    #                 rect.width = int( rect.width * self.scale )
    #                 rect.height = int( rect.height * self.scale )
    #             self.super__repaint( rect )
    #             return
    #         elif len( args ) == 5:
    #             arg1 = args[ 0 ]
    #             x = args[ 1 ]
    #             y = args[ 2 ]
    #             width = args[ 3 ]
    #             height = args[ 4 ]
    #             x = int( x * self.scale )
    #             y = int( y * self.scale )
    #             if self.scale < 1.0:
    #                 width = int( width * self.scale )
    #                 height = int( height * self.scale )
    #             self.super__repaint( arg1, x, y, width, height )
    #             return
    #         elif len( args ) == 4 :
    #             x = args[ 0 ]
    #             y = args[ 1 ]
    #             width = args[ 2 ]
    #             height = args[ 3 ]
    #             x = int( x * self.scale )
    #             y = int( y * self.scale )
    #             if self.scale < 1.0:
    #                 width = int( width * self.scale )
    #                 height = int( height * self.scale )
    #             self.super__repaint( x, y, width, height )
    #             return
    #         return self.super__repaint( *args )
    # 
    #     def scrollRectToVisible( self, rect ):
    #         rect.x = int( rect.x * self.scale )
    #         rect.y = int( rect.y * self.scale )
    #         rect.width = int( rect.width * self.scale )
    #         rect.height = int( rect.height * self.scale )
    #         self.super__scrollRectToVisible( rect )
    #     def setScale( self, scale ):
    #         self.scale = scale
    #         self.treeDidChange()
    #         self.repaint()
    #     def getScrollableTracksViewportHeight2( self ):
    #         parent = self.getParent()
    #         size1 = self.getPreferredSize()
    #         size2 = parent.getVisibleRect()
    #         return size1.height <= size2.height
    # 
    #     def getScrollableTracksViewportWidth2( self ):
    #         parent = self.getParent()
    #         size1 = self.getPreferredSize()
    #         size2 = parent.getVisibleRect()
    #         return size1.width <= size2.width
    # 
    #     def setImage( self, image ):
    #         self.image = image
    #     def setAlpha( self, alpha ):
    #         self.alpha = awt.AlphaComposite.getInstance( 
    # awt.AlphaComposite.SRC_OVER, alpha )
    # 
    #     def processMouseEvent( self, me ):
    #         #print me
    #         #me.consume()
    #         x = int(me.getX()/self.scale)
    #         y = int(me.getY()/self.scale)
    #         component = swing.SwingUtilities.getDeepestComponentAt( self, x, 
    # y )
    #         me.consume()
    #         if component and component != self and me.getClickCount() != 0:
    #             me.consume()
    #             point = swing.SwingUtilities.convertPoint( self, x, y, 
    # component )
    #             me2 = aevent.MouseEvent( component, me.getID(), 
    # me.getWhen(), me.getModifiers(), point.x, point.y, me.getClickCount(), 
    # me.isPopupTrigger() )
    #             eq = awt.Toolkit.getDefaultToolkit().getSystemEventQueue()
    #             eq.postEvent( me2 )
    #             return
    #         me2 = aevent.MouseEvent( self, me.getID(), me.getWhen(), 
    # me.getModifiers(), x, y, me.getClickCount(), me.isPopupTrigger())
    #         self.super__processMouseEvent( me2 )
    #     def paint( self, g  ):
    #         transform = g.getTransform()
    #         print "PAINT %s" % transform.getScaleX()
    #         if transform.getScaleX() != self.scale:
    #             #print g.getRenderingHints()
    #             g.scale( self.scale, self.scale )
    #         self.super__paint( g )
    #     def paintImmediately( self, *args ):
    #         self.pif = True
    #         self.super__paintImmediately( *args )
    #         self.pif = False
    # 
    #     def paintChildren( self, g ):
    #         transform = g.getTransform()
    #         print "PC %s" % transform.getScaleX()
    #         self.super__paintChildren( g )
    #     def paintComponent2( self ):
    #         g = self.super__getGraphics()
    #         visRect = self.getParent().getVisibleRect()
    #         g.setColor( self.getBackground() )
    #         g.fillRect( visRect.x, visRect.y, visRect.width, visRect.height 
    # )
    #         g.dispose()
    #     def paintComponent( self, graphics ):
    #         if self.image:
    #             vrec = self.getVisibleRect()
    #             if not self.lastDimensions.equals( vrec ):
    #                 self.lastDimensions = vrec
    #                 self.last_image = self.image.getScaledInstance( 
    # vrec.width, vrec.height, awt.Image.SCALE_REPLICATE )
    #             composite = graphics.getComposite()
    #             graphics.setComposite( self.alpha )
    #             graphics.drawImage( self.last_image, vrec.x, vrec.y, 
    # awt.Color.WHITE, None )
    #             graphics.setComposite( composite )
    #         if self.scale < 1.0 and not self.pif and not self.image:
    #             mult = 1.0/self.scale
    #             vrect = self.getVisibleRect()
    #             print vrect
    #             w = int(vrect.width * mult); h = int(vrect.height * mult)
    #             graphics.setColor( self.getBackground() )
    #             graphics.fillRect( vrect.x, vrect.y, w, h )
    #         ##    #transform = graphics.getTransform()
    #         #    #graphics.scale( 1.0, 1.0 )
    #         #    #self.paintComponent2()
    #         #graphics.scale( self.scale, self.scale )
    #         print "SCALE WILL BE %s" % graphics.getTransform().getScaleX()
    #         #print graphics.hashCode()
    #         transform = graphics.getTransform()
    #         if transform.getScaleX() != self.scale:
    #             g = graphics
    #             #print g.getRenderingHints()
    #             g.scale( self.scale, self.scale )
    #             #g.setRenderingHint( awt.RenderingHints.KEY_RENDERING, 
    # awt.RenderingHints.VALUE_RENDER_QUALITY )
    #             #java.lang.Thread.currentThread().dumpStack()
    #         #else:
    #         #    java.lang.Thread.currentThread().dumpStack()
    #         self.super__paintComponent( graphics )#comes last, or no tree!!!
    # 
    #     def isExpanded( self, path ):
    #         if path.__class__ != stree.TreePath:
    #             path = self.getPathForRow( path )
    #         lc = path.getLastPathComponent()
    #         if lc == self.posTM._root:
    #             return True
    #         else:
    #             return lc.isExpanded()
    #     def setExpandedState( self, path, boolean ):
    #         if boolean:
    #             lc = path.getLastPathComponent()
    #             lc.expand()
    #             try:
    #                 self.fireTreeWillExpand( path )
    #             except:
    #                 return
    #             self.fireTreeExpanded( path )
    #         else:
    #             lc = path.getLastPathComponent()
    #             lc.contract()
    #             try:
    #                 self.fireTreeWillCollapse( path )
    #             except:
    #                 return
    #             self.fireTreeCollapsed( path )
    #     def getExpandedDescendants( self, path ):
    # 
    #         lc = path.getLastPathComponent()
    #         paths = java.util.Vector()
    #         expanders = []
    #         if lc == self.posTM._root:
    #             p = self.posTM.chapter.getRootPosition()
    #             cp = self.posTM.chapter.getCurrentPosition()
    #         else:
    #             p = lc.copy()
    #         rp = self.posTM.chapter.getRootPosition()
    #         stop_p = p.copy()
    #         while p:
    #             expanded = p.isExpanded()
    #             #if p == stop_p and p != rp: expanded = True
    #             #elif stop_p == rp and not self.posTM.drunning: expanded = 
    # True
    #             #elif self.posTM.drunning and p == rp:
    #             #    expanded = True
    #             if expanded:
    #                 expanders.append( p.copy() )
    #             if expanded:
    #                 if p.v.t._firstChild:
    #                     p.moveToFirstChild()
    #                 elif p and p.v._next:
    #                     p.moveToNext()
    #                 else:
    #                     while p:
    #                         p.moveToParent()
    #                         if p == stop_p and not p.isRoot():
    #                             p = None
    #                             break
    #                         if p and p.v._next:
    #                             p.moveToNext()
    #                             break
    #                         elif not p: break
    #             else:
    #                 if p.v._next:
    #                     p.moveToNext()
    #                 else:
    #                     while p:
    #                         p.moveToParent()
    #                         if p == stop_p and not p.isRoot():
    #                             p = None
    #                             break
    #                         if p and p.v._next:
    #                             p.moveToNext()
    #                             break
    #                         elif not p: break
    #         expanders.sort( self.sortNodes )
    #         while expanders:
    #             z = expanders.pop()
    #             path = self.posTM.getPathToRoot( z.copy(), masterlist = 
    # expanders )
    #             paths.add( path )
    #         return paths.elements()
    # 
    #     def sortNodes( self, node1, node2 ):
    #         l1 = node2.level()
    #         l2 = node2.level()
    #         if l1 > l2: return 1
    #         elif l1 < l2: return -1
    #         else: return 0
    # 
    #@-at
    #@-node:zorcanda!.20051113133134:class ZoomJTree2
    #@-others
    #@-node:zorcanda!.20051206140337:Tree Widget..
    #@+node:zorcanda!.20050804220212:configureMedia
    def configureMedia( self ):
        
        c = self.c 
        use_background = g.app.config.getBool( c, "tree_use_background_image" )    
        if use_background:
            self.setBackgroundImage()
    #@-node:zorcanda!.20050804220212:configureMedia
    #@+node:zorcanda!.20050804220306:setBackgroundImage
    def setBackgroundImage( self, notification = None, handback = None ):
        
        c = self.c
        alpha = g.app.config.getFloat( c, "tree_background_alpha" )
        if alpha == None: alpha = 1.0
        image_path = g.app.config.getString( c, "tree_image_location@as-filedialog" )
        if image_path:
            imfile = java.io.File( image_path ) 
            if imfile.exists():
                bimage = imageio.ImageIO.read( imfile )
                self.jtree.setImage( bimage )
                self.jtree.setAlpha( alpha )
                self.jtree.setOpaque( False )
                g.app.config.manager.addNotificationDef( "tree_background_alpha", self.setBackgroundImage )
                g.app.config.manager.addNotificationDef( "tree_image_location@as-filedialog", self.setBackgroundImage )
    
    
    
    #@-node:zorcanda!.20050804220306:setBackgroundImage
    #@+node:zorcanda!.20050530212448:helper classes
    #@+others
    #@+node:mork.20050127171611:class posTreeModel
    class posTreeModel( stree.TreeModel, java.lang.Runnable ):
        
        def __init__( self, c ):
    
            self.c = c
            self.tmlisteners = java.util.ArrayList();
            self._root = self._rootN( c )
            self._rTreePath = stree.TreePath( self._root )       
    
    
        def getRoot( self ):
            return self._root
    
        def reload( self, full_reload = False ):
            
            
            if full_reload:
                t_r = self.c.frame.tree.tree_reloader
                for z in self.c.rootPosition().allNodes_iter( copy = True ):
                    if z.isExpanded():
                        t_r.expand( z )
            
            import jarray
            a = jarray.zeros( 1, stree.TreeNode )
            a[ 0 ] = self._root
            e = sevent.TreeModelEvent( self._root, a )
            for z in self.tmlisteners:
                z.treeStructureChanged( e )
                
    
        
        def addTreeModelListener( self, listener ):
            self.tmlisteners.add( listener )
            
        def removeTreeModelListener( self, listener ):
            self.tmlisteners.remove( listener )
        
        def getChild( self, parent, ind ):
            if parent is self._root:
                return parent.getChildAt( ind ).copy()
            return parent.getNthChild( ind ).copy()
            
        def getChildCount( self, parent ):
            
            if parent is self._root:
                return parent.getChildCount()
            if parent:
                return parent.numberOfChildren()
            else:
                return 0
            
        def getIndexOfChild( self, parent, child ):
            if parent is self._root:
                return self._root.getIndex( child )
            else:
                return child.childIndex()
    
    
        
        def valueForPathChanged( self, path, value ):
    
            pos = path.getLastPathComponent()
            pos.setHeadString( value )
            
        def isLeaf( self, node ):
            if node is self._root: return False
            if node:
                if node.numberOfChildren(): return False
                else: return True
            else:
                return True
                
        def getPathToRoot( self, node ):
            
            path = []
            #if not node:
            #    node = self.c.rootPosition()
                
            while node and node.level() != 0:
                path.append( node.copy() )
                node = node.getParent()
            else:
                path.append( node.copy() )
                path.append( self._root )
                
            path.reverse()
            tp = stree.TreePath( path )
            return tp
                
        class _rootN( stree.TreeNode ):
            
            def __init__( self, c ):
                self.c = c
            
            def getChildAt(self, childIndex):
                rp = self.c.rootPosition()
                if len( self.c.hoistStack ) != 0: #Hoist Code
                    rp = self.c.hoistStack[ -1 ].p.copy()
                    def getParent( root = self ): #This slight modification to a copy allows the Tree to keep its expanded state
                        return root
                    rp.getParent = getParent
                    return rp #End of Hoist Code
                if not rp: return None
                i = 0
                for z in rp.siblings_iter():
                    if i == childIndex:
                        return z
                    i = i + 1
                return None       
            
            def getChildCount( self ):
                rp = self.c.rootPosition()
                if len( self.c.hoistStack ) != 0:
                    return 1
                i = 0
                for z in rp.siblings_iter():
                    i = i + 1
                return i
            
            def getParent( self ):
                return None
                
            def getIndex( self, node):
                rp = self.c.rootPosition()
                if len( self.c.hoistStack ) != 0:
                    #rp = self.c.hoistStack[ -1 ][ 0 ].copy()
                    return 0
                i = 0
                for z in rp.siblings_iter():
                    if z == node: return i
                    i = i + 1
                return -1
                
            def getAllowsChildren( self ):
                return True
                
            def isLeaf( self ):
                return False
                
            def equal( self, x ):
                if self is x: return True
                else: return False
                
            def equals( self, x ):
                if self is x: return True
                else:
                    return False
                
            def copy( self ):
                return self
                
            def bodyString( self ):
                return ""
                
            def headString( self ):
                return ""
                
            def children( self ):
                
                class _enum( util.Enumeration ):
                    
                    def __init__( self, iter ):
                        self.iter = iter
                        try:
                            self.next = iter.next()
                        except:
                            self.next = None
                    
                    def hasMoreElements( self ):
                        if self.next: return True
                        else: return False
                        
                    def nextElement( self ):
                        
                        try:
                            rt = self.next
                            self.next = iter.next()
                        finally:
                            return rt
                return _enum( self.c.rootPosition.siblings_iter( copy = True ) )        
            
    
        
           
    
    
    
    
    
    #@-node:mork.20050127171611:class posTreeModel
    #@+node:orkman.20050130142517:class tcellEditor
    class tcellEditor( stree.DefaultTreeCellEditor ): #so the tree will start editing on 1 click!
        
        def __init__( self , jtree, renderer, editor, c ):
            stree.DefaultTreeCellEditor.__init__( self, jtree, renderer , editor )
            self.editor = editor
            self.editor.setFocusTraversalPolicy( c.frame.ftp )
            self.timer = None
            self.c = c
            self.tree = jtree
    
        def getTreeCellEditorComponent(self, tree, value, isSelected, expanded, leaf, row):
            return self.editor.getTreeCellEditorComponent( tree, value, isSelected, expanded, leaf, row )     
    
        def requestFocusInWindow( self ):
            self.editor.requestFocusInWindow()
    
        def shouldStartEditingTimer( self, event ):
        
            if event.getClickCount() >= 1 and self.inHitRegion( event.getX(), event.getY() ):
                #self.tree.stopEditing() 
                return True
            else:
                return False
                
        def canEditImmediately( self, event ):
            
            if event == None or event.getClickCount() == 2:
                return True
            else:
                return False
    
        def startEditingTimer( self ):
            
            #self.htext = None
            if self.timer == None:
                self.timer = swing.Timer( 10, self )
                self.timer.setRepeats( False )
            self.timer.start()
    
        #def cancelCellEditing( self ):
        #
        #    self.super__cancelCellEditing()
        #cp = self.c.currentPosition()
        #htext = self.tree.getCellEditor().getCellEditorValue()
        #cp.setHeadString(  )
        #self.htext = None
    
        #def prepareForEditing( self ):
        #    
        #    self.super__prepareForEditing()
        #cp = self.c.currentPosition()
        #self.htext = cp.headString()
    
    #@-node:orkman.20050130142517:class tcellEditor
    #@+node:orkman.20050130144235:class cellEditorListener
    class cellEditorListener( sevent.CellEditorListener, java.lang.Runnable ):
        
        def __init__( self, c ):
            self.c = c
            
        def editingCanceled( self, event ): 
            #Called when the headline edit has been aborted, do nothing... results in headline reverting.
            pass
            #self.sync( event )
            
        def editingStopped( self, event ):
            self.sync( event )
            
        def run( self ):
            
            self.c.frame.body.editor.editor.requestFocusInWindow()
            
            
        def sync( self , event ):
            
            source = event.getSource()
            value = source.getCellEditorValue()
            cp = self.c.currentPosition()
            cp.setHeadString( value )
            awt.EventQueue.invokeLater( self )
    #@-node:orkman.20050130144235:class cellEditorListener
    #@+node:zorcanda!.20050403180442:class EditLabelEnabler
    class EditLabelEnabler( java.lang.Runnable ):
        '''This class enables a label to be edited within the context of
           beginUpdate and endUpdate.  Doing the operation between these two
           calls resulted in NullPointer Exceptins to be thrown.  This does the work
           safely after those calls have been made, actually this is how it is used
           in endUpate, not with the EditLabelEnabler.  It is a policy on top of this
           classes mechanism'''
           
        def __init__( self, jtree, headlineEditor ):
            
            self._jtree = jtree
            self.headlineEditor = headlineEditor
            #We use an AtomicReference to ensure that the node is fresh.
            #We use 2 Semaphores so we can correctly time the execution of an insert
            #and the beginning of a label edit.  Without this we can move too quickly 
            #and produce  NullPointerExceptions, or something like that.
            self.edit_v = atomic.AtomicReference()
            self.semaphore = concurrent.Semaphore( 1 ) 
            self.add_to_queue = concurrent.Semaphore( 1 )
            
            
        def setNodeToEdit( self, node ):
            
            if node:
                self.semaphore.acquire()
                self.edit_v.set( node.copy() )
                self.semaphore.release()
            
        def addToEventQueue( self ):
            #java.lang.Thread.dumpStack()
            if self.edit_v.get() and self.add_to_queue.availablePermits():
                self.add_to_queue.acquire()
                awt.EventQueue.invokeLater( self )
                
        
        def run( self ):
            
            self.semaphore.acquire()
            posTM = self._jtree.getModel()
            ev = self.edit_v.getAndSet( None )
            self.semaphore.release()
            ptr = posTM.getPathToRoot( ev )
            #self.edit_v = None
            #self._jtree.requestFocusInWindow()
            self._jtree.startEditingAtPath( ptr )
            self.headlineEditor.requestFocusInWindow()
            self.add_to_queue.release()
            
            
    #@-node:zorcanda!.20050403180442:class EditLabelEnabler
    #@+node:zorcanda!.20050907113615:class ViewControls
    class ViewControls:
        
        def __init__( self ):
            self.menu = swing.JMenu( "Views" )
            self.bgroup = swing.ButtonGroup()
            self.layout = java.awt.CardLayout()
            self.base = swing.JPanel( self.layout )
            self.methods = {}
            self.detacher = None
            self.menu_bar = None
            self.count = 0
            
        def setMenuBar( self, bar ):
            self.menu_bar = bar
            if self.count > 1:
                self.menu_bar.add( self.menu, 0 )
        
        def getMenu( self ):
            return self.menu
            
        def getBase( self ):
            return self.base
            
        def addControl( self, name, attachmethod, detachmethod, checkmark = 0 ):
            
            jmi = swing.JCheckBoxMenuItem( name )
            if checkmark:
                jmi.setSelected( 1 )
            self.methods[ name ] = ( attachmethod, detachmethod )
            jmi.actionPerformed = lambda event: self.__action(  name  )
            self.bgroup.add( jmi )
            self.menu.add( jmi )
            nwbase = swing.JPanel()
            nwbase.setLayout( awt.GridLayout( 1,1 )) 
            self.base.add( nwbase, name )
            if self.menu_bar and ( self.count > 1 and self.menu.getParent() == None ):
                self.menu_bar.add( self.menu, 0 )
            self.count += 1
            return nwbase
        
        def __action( self, name ):
            
            if self.detacher: self.detacher()
            attach, detach = self.methods[ name ]
            self.layout.show( self.base, name )
            attach()
            self.detacher = detach
            
    
    #@-node:zorcanda!.20050907113615:class ViewControls
    #@+node:orkman.20050206162833:class PopupEnabler
    class PopupEnabler( aevent.MouseAdapter ):
        
        def __init__( self, c ):
            aevent.MouseAdapter.__init__( self )
            self.node = None
            self.c = c
            #self.cursor = None
            #self.imagesetter = leoSwingTree.ImageSetter( c.frame.gp2, c )
            
        def mouseDragged( self, event ):
            self.c.frame.gp2.repaint()
            
        def mouseMoved( self, event ):
            pass
        
        def mousePressed( self, mevent ):
            
            button = mevent.getButton()
    #@+at
    #         if button == mevent.BUTTON1:
    #             tree = mevent.getSource()
    #             path = tree.getPathForLocation( mevent.x, mevent.y )
    #             if path:
    #                 row = tree.getRowForLocation( mevent.x, mevent.y )
    #                 self.node = path.getLastPathComponent().copy()
    #                 bi2 = self.c.frame.tree.getRendererImageOfNode( 
    # self.node )
    #                 self.cursor = tree.getCursor()
    #                 ncursor = awt.Cursor.getPredefinedCursor( 
    # awt.Cursor.HAND_CURSOR )
    #                 #tk = awt.Toolkit.getDefaultToolkit()
    #                 #ccursor = tk.createCustomCursor( bi2, awt.Point(0,0 ), 
    # "ccursor" )
    #                 self.imagesetter.setTargets( bi2, ncursor, path )
    #                 swing.SwingUtilities.invokeLater( self.imagesetter )
    #@-at
    #@@c
            if button == mevent.BUTTON3:
                self.showMenu( mevent )
    #@+at        
    #     def mouseReleased2( self, mevent ):
    #         tree = mevent.getSource()
    #         path = tree.getPathForLocation( mevent.x, mevent.y )
    #         updatestarted = False
    #         self.imagesetter.reset()
    #         try:
    #             if path and self.node:
    #                 endpoint = path.getLastPathComponent().copy()
    #                 if self.node.v.t != endpoint.v.t and not 
    # self.node.isAncestorOf( endpoint ):
    #                     try:
    #                         self.c.beginUpdate()
    #                         updatestarted = True
    #                     except:
    #                         pass
    #                     if endpoint.numberOfChildren():
    #                         self.c.dragToNthChildOf(self.node,endpoint,0)
    #                     else:
    #                         self.c.dragAfter(self.node,endpoint)
    #         finally:
    #             self.node = None
    #             if self.cursor:
    #                 tree.setCursor( self.cursor )
    #                 self.cursor = None
    #             if updatestarted:
    #                 updatestarted = False
    #                 self.c.endUpdate()
    #@-at
    #@@c
             
        def showMenu( self, event ):
            
            popup = swing.JPopupMenu()
            class aa( swing.AbstractAction ):
                def __init__( self, name, command ):
                    swing.AbstractAction.__init__( self, name )
                    self.command = command
                    
                def actionPerformed( self, event ):
                    self.command()
            
            c = self.c
            commandlist = (  
                            ( "Read @file Nodes", c.readAtFileNodes, 0 ),
                            ( "Write @file Nodes", c.fileCommands.writeAtFileNodes, 0 ), 
                            (),
                            ( "Tangle", c.tangle, 0 ),
                            ( "Untangle", c.untangle, 0 ),
                            (),
                            ("Toggle Angle Brackets", c.toggleAngleBrackets, 0 ),
                            (),
                            ( "Cut Node", c.cutOutline, c.canCutOutline ),
                             (  "Copy Node", c.copyOutline, 0 ),
                             ( "Paste Node", c.pasteOutline, c.canPasteOutline ),
                             ( "Delete Node", c.deleteOutline, c.canDeleteHeadline ),
                             (),
                             ( "Insert Node", c.insertHeadline, 0 ),
                             ( "Clone Node", c.clone, 0 ),
                             ( "Sort Children", c.sortChildren, c.canSortChildren ),
                             ( "Sort Siblings", c.sortSiblings, c.canSortSiblings ),
                             (),
                             ( "Contract Parent", c.contractParent, c.canContractParent ),
                             )
                             
            for z in commandlist:
                if len(z) == 0:
                    popup.addSeparator()
                else:
                    if z[ 2 ]:
                        ok = z[ 2 ]()
                    else:
                        ok = True
                    if ok:
                        popup.add( aa( z[ 0 ], z[ 1 ] ) )
                             
                             
                             
            
            x = event.getX()
            y = event.getY()
            popup.show( event.getSource(), x, y )
    
    #@-node:orkman.20050206162833:class PopupEnabler
    #@+node:zorcanda!.20051128120143:class ImageSetter
    class ImageSetter( java.lang.Runnable, aevent.MouseMotionListener  ):
        def __init__( self , gp2, c, jtree):
            self.image = None
            self.gp2 = gp2
            self.c = c
            self.path = None
            jtree.addMouseMotionListener( self )
            
        def mouseDragged( self, event ):
            if self.image:
                self.gp2.repaint()
                
        def mouseMoved( self, event ):
            pass
                
        def setImage( self, image ):
            self.image = image
            
                
        def setPath( self, path ):
            self.path = path
            
        def setTargets( self, image , path ):
            self.image = image
            self.path = path
                
        def reset( self ):
            self.gp2.setImage( None ); self.gp2.setCursor( None )
            self.image  = self.path = None
                        
        def run( self ):
                
            if self.image:# and self.cursor:
                tree = self.c.frame.tree.jtree
                epath = tree.getEditingPath()
                spath = tree.getSelectionPath()
                if not self.path.equals( epath ):
                    self.gp2.setImage( self.image )
                    #self.gp2.setCursor( self.cursor )
                else:
                    self.reset()
    #@-node:zorcanda!.20051128120143:class ImageSetter
    #@+node:zorcanda!.20051129194856:class TreeTransferHandler
    class TreeTransferHandler( swing.TransferHandler ):
        
        transferservice = java.util.concurrent.Executors.newSingleThreadExecutor()
        
        def __init__( self, c, jtree ):
            swing.TransferHandler.__init__( self )
            self.flavors = []
            DataFlavor = datatransfer.DataFlavor
            self.flavors.append( DataFlavor.javaFileListFlavor )
            self.uri = DataFlavor( "text/uri-list;class=java.lang.String" )
            self.smarker = DataFlavor( "text/internal-transfer;class=java.lang.String" )
            self.pspecflavor = DataFlavor( DataFlavor.javaJVMLocalObjectMimeType, 
                                           "class=%s" % PositionSpecification, 
                                           PositionSpecification.getClassLoader() ) #We use this one or the system can't find the PS class!
            self.flavors.append( self.uri )
            self.c = c
            self.jtree = jtree
            
        def createTransferable( self, jc ):
            pi = awt.MouseInfo.getPointerInfo()
            spot = pi.getLocation()
            swing.SwingUtilities.convertPointFromScreen( spot, self.jtree )
            path = self.jtree.getPathForLocation( spot.x, spot.y )
            rv = self.TreeTransferable( self.c, list( self.flavors ) )
            if path:
                p = path.getLastPathComponent().copy()
                rv.setPosition( p, self.pspecflavor )
                bi2 = self.c.frame.tree.getRendererImageOfNode( p.copy() ) 
            else:
                rv.addDataFlavor( self.smarker )
            return rv
            
        def getSourceActions( self, jc ):
            return self.COPY_OR_MOVE
            
        #@    @+others
        #@+node:zorcanda!.20051205120716:canImport
        def canImport( self, jc, df ):
            
            for z in df:
                if z.equals( self.smarker ): return False
            
            for z in df:
                if z.isFlavorJavaFileListType(): return True
                elif z.equals( self.uri ): return True
                elif z.equals( self.pspecflavor ): return True
                
            return False
        #@nonl
        #@-node:zorcanda!.20051205120716:canImport
        #@+node:zorcanda!.20051205121039:importData
        def importData( self, jc, trans ):
            
            c = self.c
            try:
                if trans.isDataFlavorSupported( self.pspecflavor ):
                    pi = awt.MouseInfo.getPointerInfo()
                    spot = pi.getLocation()
                    swing.SwingUtilities.convertPointFromScreen( spot, self.jtree )
                    path = self.jtree.getPathForLocation( spot.x, spot.y )
                    if path:
                        node = trans.getTransferData( self.pspecflavor )
                        endpoint = path.getLastPathComponent().copy()
                        if node.v.t != endpoint.v.t and not node.isAncestorOf( endpoint ):
                            try:
                                c.beginUpdate()
                                if endpoint.numberOfChildren(): 
                                    self.c.dragToNthChildOf( node,endpoint,0)
                                else:
                                    self.c.dragAfter( node,endpoint)
                            finally:
                                c.endUpdate()
                    return True
                elif trans.isDataFlavorSupported( datatransfer.DataFlavor.javaFileListFlavor ):
                    files = trans.getTransferData( datatransfer.DataFlavor.javaFileListFlavor )
                    ifiles = self.ImportFiles( files, self )
                    self.transferservice.submit( ifiles )
                    return True
                elif trans.isDataFlavorSupported( self.uri ):
                    uri = trans.getTransferData( self.uri )
                    iurls = self.ImportUrls( uri, self )
                    self.transferservice.submit( iurls )
                    return True
            finally:
                pass
                
            return False
        #@nonl
        #@-node:zorcanda!.20051205121039:importData
        #@+node:zorcanda!.20051205135600:importFile
        def importFile( self, filename ):
            
            c = self.c
            at = c.atFileCommands
            io = java.io
            filename = java.net.URLDecoder.decode( filename, "UTF-8" )
            if filename.endswith( ".leo" ):
                try:
                    c.chapters.loadFileAsChapter( filename )
                except:
                    g.es( "Error loading %s" % filename )            
            else:
                isDerived = False
                thin = False
                try:
                    theFile = open(filename,'rb')
                    firstLines , readNew, thin = at.scanHeader(theFile,filename)
                    isDerived = ( readNew or thin )
                    theFile.close()
                except IOError:
                    g.es( "Could not import %s" % filename )
                    return
                if isDerived:
                    c.importCommands.importDerivedFiles( c.currentPosition().copy(), [ filename, ] )
                else:
                    c.importCommands.importFilesCommand( [ filename, ], "@file" )
                try:
                    nwname = io.File( filename ).getName()
                    if nwname:
                        cp = c.currentPosition()
                        cp.setHeadStringOrHeadline( nwname )
                            
                except:
                    pass
        
        #@-node:zorcanda!.20051205135600:importFile
        #@+node:zorcanda!.20051205160828:getVisualRepresentation
        def getVisualRepresentation( self, transf ):
        
            tree = self.c.frame.tree
            icon = tree.getRendererImageOfNode( self.c.currentPosition() )
            return icon
        #@nonl
        #@-node:zorcanda!.20051205160828:getVisualRepresentation
        #@+node:zorcanda!.20051205162524:class TreeTransferable
        class TreeTransferable( datatransfer.Transferable ):
            
            def __init__( self, c, flavors ):
                self.c = c
                self.flavors = flavors
                self.uri = datatransfer.DataFlavor( "text/uri-list;class=java.lang.String" )
                self.position = None
                self.pflavor = None
                self.writen = False
                self.nwfile = None
            
            def addDataFlavor( self, flavor ):
                self.flavors.append( flavor )
            
            def setPosition( self, position, flavor ):
                self.position = position
                self.pflavor = flavor
                self.flavors.append( flavor )
            
            def getTransferDataFlavors( self ):
                return self.flavors 
                
            def isDataFlavorSupported( self, flavor ):
                
                for z in self.flavors:
                    if flavor.equals( z ): return True
                return False
                
            #@    @+others
            #@+node:zorcanda!.20051205162524.1:getTransferData
            def getTransferData( self, df ):
                
                if df.equals( datatransfer.DataFlavor.javaFileListFlavor ):
                    rv = util.ArrayList()
                    if not self.writen:
                        tmpfile = io.File.createTempFile( "Node", "Drop" )
                        self.nwfile = self.writeNodeToFile( tmpfile )
                        self.written = True
                        
                    rv.add( self.nwfile )
                    return rv
                elif df.equals( self.uri ):
                    if not self.writen:
                        tmpfile = io.File.createTempFile( "Node", "Drop" )
                        self.nwfile = self.writeNodeToFile( tmpfile )
                        self.writen = True
                        
                    rv = self.nwfile.toURI().toString()
                    return rv
                elif self.pflavor and df.equals( self.pflavor ):
                    return self.position
                else:
                    raise datatransfer.UnsupportedFlavorException( df )
            #@nonl
            #@-node:zorcanda!.20051205162524.1:getTransferData
            #@+node:zorcanda!.20051205115420:writeNodeToFile
            def writeNodeToFile( self, tmpfile ):
                    
                c = self.c
                cp = c.currentPosition()
                at = c.atFileCommands
                c.fileCommands.assignFileIndices()
                fn = cp.v.anyAtFileNodeName()
                if fn:
                    nosentinels = cp.v.atNoSentinelsFileNodeName()
                    if nosentinels: nosentinels = True
                    else: nosentinels = False
                    thinFile = cp.v.atThinFileNodeName()
                    if thinFile: thinFile = True
                    else: thinFile = False
                    at.write( cp.copy(), thinFile = thinFile, nosentinels = nosentinels, toString = True, scriptWrite = False )
                else:
                    at.write( cp.copy(), thinFile = True, toString = True, scriptWrite = False )
                data = at.stringOutput 
                ps = None
                io = java.io
                encoding = "UTF-8"
                try:
                    try:
                        fos = io.FileOutputStream( tmpfile )
                        ps = io.PrintWriter( io.OutputStreamWriter( fos ) ) 
                        for z in data.split( "\n" ):
                            ps.println( z )
                        ps.close()
                        ps = None
                        frd = io.FileReader( tmpfile )
                        encoding = frd.getEncoding()
                        frd.close()
                        frd = None       
                    except io.IOException, io:
                        io.printStackTrace()
                finally:
                    if ps: ps.close()
                    if frd: frd.close()
                hstring = cp.headString()
                if cp.v.anyAtFileNodeName():
                    hstring = cp.v.anyAtFileNodeName()
                language = LeoUtilities.scanForLanguage( cp.copy() ) 
                if g.app.language_extension_dict.has_key( language ):
                    ext = g.app.language_extension_dict[ language ]
                else:
                    ext = language
                
                import binascii
                hstring = list( hstring )
                for i in xrange( len( hstring ) ):
                    ch = hstring[ i ]
                    if not ch.isalnum() and not ch.isspace() and ch not in ( "." ):
                        hstring[ i ] = binascii.hexlify( ch )
                        
                hstring = "".join( hstring )
                
                if not hstring.endswith( ext ):
                    nwname = "%s.%s" %( hstring, ext )
                else:
                    nwname = hstring
                nwname = java.net.URLEncoder.encode( nwname, encoding )
                pdirectory = tmpfile.getParent()
                try:
                    if fn:
                        fn2 = io.File( fn )
                        nwfile = io.File( pdirectory, fn2.getName() )
                    else:
                        nwfile = io.File( pdirectory, nwname )
                except io.IOException, ix:
                    ix.printStackTrace()
                tmpfile.renameTo( nwfile )
                nwfile.deleteOnExit()
                return nwfile
            #@-node:zorcanda!.20051205115420:writeNodeToFile
            #@-others
        #@-node:zorcanda!.20051205162524:class TreeTransferable
        #@+node:zorcanda!.20051207161701:class ImportUrls
        class ImportUrls( java.lang.Runnable ):
            
            def __init__( self, uri, tth ):
                self.uri = uri
                self.tth = tth
                
            def run( self ):
                uris = self.uri.split( "\r\n" )
                for z in uris:
                    try:
                        if z:
                            f = java.net.URL( z ).getFile()
                            self.tth.importFile( f )
                    except java.lang.Exception, x:
                        x.printStackTrace()
        #@-node:zorcanda!.20051207161701:class ImportUrls
        #@+node:zorcanda!.20051207161701.1:class ImportFiles
        class ImportFiles( java.lang.Runnable ):
            
            def __init__( self, files, tth ):
                self.files = files
                self.tth = tth
                
            def run( self ):
                
                for z in self.files:
                    try:
                        fname = z.getAbsolutePath()
                        if fname:
                            self.tth.importFile( fname )
                    except java.lang.Exception, x:
                        x.printStackTrace()
        #@-node:zorcanda!.20051207161701.1:class ImportFiles
        #@-others
        
    #@-node:zorcanda!.20051129194856:class TreeTransferHandler
    #@-others
    #@-node:zorcanda!.20050530212448:helper classes
    #@+node:zorcanda!.20050418135625:focuslistener interface
    def focusGained( self, event ):
    
        if self.jtree.isEditing():
            self.jtree.getCellEditor().requestFocusInWindow()
        
    def focusLost( self, event ):
        pass
    #@-node:zorcanda!.20050418135625:focuslistener interface
    #@+node:orkman.20050128172108:doneLoading
    def doneLoading( self ):
        
        self.loaded = True
        c = self.c
        #awt.EventQueue.invokeLater( self.__reloader( self.posTM, self.tree_reloader ) )
        #swing.SwingUtilities.invokeLater( self.tree_reloader )
        #g.es( "Expanding tree( last startup operation )..." )
        c.frame.body.editor.sync()
        #c.frame.body.editor.cdertminer.last_p = None
        c.frame.body.jdp.repaint()
        
    
    class __reloader( java.lang.Runnable ):
        
        def __init__( self, model , tree_reloader ):
            self.model = model
            self.tree_reloader = tree_reloader
            
        def run( self ):
            self.model.reload( full_reload = False );
            self.tree_reloader.run()
            #awt.EventQueue.invokeLater( self.tree_reloader ) 
    #@nonl
    #@-node:orkman.20050128172108:doneLoading
    #@+node:orkman.20050128125516:valueChanged --tree selection Event
    def valueChanged( self, event ):
        
        path = event.getPath()
        o = path.getLastPathComponent()
        #if not self.c.currentPosition().equal( o ):
        if not self.chapter.getCurrentPosition().equal( o ):
            self.settingPosition = True
            #cp = self.c.currentPosition()
            cp = self.chapter.getCurrentPosition()
            #if hasattr( cp ,'v' ):
            #    leoSwingTree.positions.put( cp.v, self.c.frame.body.editor.editor.getCaretPosition() )
            #self.c.setCurrentPosition( o )
            self.select( o )
            #self.frame.body.editor.sync()
            self.settingPosition = False
            #if hasattr( o, 'v' ) and leoSwingTree.positions.containsKey( o.v ):
            #    spot = leoSwingTree.positions.get( o.v )
            #    editor = self.c.frame.body.editor
            #    doc = editor.editor.getStyledDocument()
            #    if doc.getLength() < spot: return
            #    
            #    editor.editor.setCaretPosition( spot )
            #    rec = editor.editor.modelToView( spot )
            #    if rec:
            #        editor.view.getViewport().scrollRectToVisible( rec )
            #else:
            #    self.c.frame.body.editor.editor.setCaretPosition( 0 )
    #@nonl
    #@-node:orkman.20050128125516:valueChanged --tree selection Event
    #@+node:mork.20050127125058.85: Must be defined in subclasses
    #@+node:mork.20050127125058.86:Drawing
    def drawIcon(self,v,x=None,y=None):
        self.oops()
    
    
    def _redraw( self, event = None ):
        pass
    
    def redraw(self,event=None): # May be bound to an event.
        
        if len( self.c.hoistStack ) or self.lastHoistStackLength: #This ensures the correct Hoisted part of the tree is displayed
            if self.lastHoistStackLength != len( self.c.hoistStack ):
                self.lastHoistStackLength = len( self.c.hoistStack )
                #self.posTM.reload()
                #swing.SwingUtilities.invokeLater( self.tree_reloader )
    
        #self.jtree.repaint()
        self.jtree.repaint( 10 )
        
    
    def _redraw_now( self, scroll = False ):
        pass
    
    def redraw_now(self, scroll = False):
        self.jtree.repaint()
        
    def redrawAfterException (self):
        self.redraw()
        
    def alterationInTreeNodes( self ):
        #self.jtree.getParent().revalidate()
        #self.posTM.reload( full_reload = True )
        self.beginUpdate()
        self.endUpdate()
        
    def nodeDidChange( self, pos ):
        self.jtree.treeDidChange()
    
        
    
        
    
    #@-node:mork.20050127125058.86:Drawing
    #@+node:mork.20050127125058.87:Edit label
    def editLabel(self,v):
    
      if self.loaded: #If the system isnt loaded this can result in a different root than what is in the Leo File!.
        self._EditLabelEnabler.setNodeToEdit( v )
      if self.updateCount == 0:
          self._EditLabelEnabler.addToEventQueue()
    
    
            
    def endEditLabel(self):
    
        if self.jtree.isEditing():
            dc = DefCallable( self.__stopediting )
            ft = dc.wrappedAsFutureTask()
            java.awt.EventQueue.invokeLater( ft )
            #self.jtree.stopEditing()
    
    def __stopediting( self ): 
        self.jtree.stopEditing()
        g.doHook( "headline-editing-finished", p = self.chapter.getCurrentPosition(), chapter = self.chapter )
    
    def setNormalLabelState(self,v):
        pass
    #@nonl
    #@-node:mork.20050127125058.87:Edit label
    #@+node:mork.20050127125058.89:Notifications
    # These should all be internal to the tkinter.frame class.
    
    def OnActivateHeadline(self,v):
        self.oops()
        
    def onHeadChanged(self,v):
        self.oops()
    
    def OnHeadlineKey(self,v,event):
        self.oops()
    
    def idle_head_key(self,v,ch=None):
        self.oops()
    #@nonl
    #@-node:mork.20050127125058.89:Notifications
    #@+node:mork.20050127125058.90:Scrolling
    def scrollTo(self,v):
        self.oops()
        
    def scrollRight( self, increment = 0 ):
        
        sbar = self.jspane.getHorizontalScrollBar()
        max = sbar.getMaximum()
        value = sbar.getValue()
        if not increment:
            increment = sbar.getBlockIncrement()
        value += increment
        if value > max:
            value = max
        sbar.setValue( value )
        
    def scrollLeft( self, increment = 0 ):
        sbar = self.jspane.getHorizontalScrollBar()
        min = sbar.getMinimum()
        value = sbar.getValue()
        if not increment:
            increment = sbar.getBlockIncrement()
        value -= increment
        if value < min:
            value = min
        sbar.setValue( value )
        
    def scrollUp( self, increment = 0 ):
        
        sbar = self.jspane.getVerticalScrollBar()
        min = sbar.getMinimum()
        value = sbar.getValue()
        if not increment:
            increment = sbar.getBlockIncrement()
        value -= increment
        if value < min:
            value = min
        sbar.setValue( value )
    
    def scrollDown( self, increment = 0 ):
        
        sbar = self.jspane.getVerticalScrollBar()
        max = sbar.getMaximum()
        value = sbar.getValue()
        if not increment:
            increment = sbar.getBlockIncrement()
        value += increment
        if value > max:
            value = max
        sbar.setValue( value )    
    
    def idle_scrollTo(self,v):
        
        self.oops()
    
    
    
    #@-node:mork.20050127125058.90:Scrolling
    #@+node:mork.20050127125058.91:Selecting
    def select(self,p,updateBeadList=True):
        
        c = self.c
        jtree = self.jtree
        editor = c.frame.body.editor.editor
        
        cpy = p.copy()
        tp = self.posTM.getPathToRoot( cpy )
        if tp.getPath():
            jtree.setSelectionPath( tp )
            jtree.scrollPathToVisible( tp )
    
        #old_p = c.currentPosition()
        old_p = self.chapter.getCurrentPosition()
        if hasattr( old_p ,'v' ):
            leoSwingTree.positions.put( old_p.v, editor.getCaretPosition() )
        
        #c.setCurrentPosition( cpy )
        self.chapter.setCurrentPosition( cpy )
        if c.frame.body.editor.lastPosition == cpy:
            g.doHook("select1",c=self.c,new_p=cpy,old_p=old_p,new_v=cpy,old_v=old_p)
            return
            
        c.frame.body.editor.sync( pos = cpy)
        
        if hasattr( cpy, 'v' ) and leoSwingTree.positions.containsKey( cpy.v ):
            
            spot = leoSwingTree.positions.get( cpy.v )
            doc = editor.getStyledDocument()
            if doc.getLength() < spot: return
            
            editor.setCaretPosition( spot )
            try:
                rec = editor.modelToView( spot )
                if rec:
                    c.frame.body.editor.view.getViewport().scrollRectToVisible( rec )
            except: #the darn thing blows up here if not enough of the editor is showing...
                pass
        else:
            editor.setCaretPosition( 0 )
        
        g.doHook("select1",c=self.c,new_p=cpy,old_p=old_p,new_v=cpy,old_v=old_p)
        
    #@nonl
    #@-node:mork.20050127125058.91:Selecting
    #@+node:mork.20050127125058.92:Tree operations
    def expandAllAncestors(self,p):
        
    
        tp = self.posTM.getPathToRoot( p.copy() )
        self.jtree.expandPath( tp )
        
    #@nonl
    #@-node:mork.20050127125058.92:Tree operations
    #@-node:mork.20050127125058.85: Must be defined in subclasses
    #@+node:zorcanda!.20051128113408:image creation
    def getEditorImageOfNode( self, p ):
        
        path = self.posTM.getPathToRoot( p )
        row = self.jtree.getRowForPath( path )
        comp = self.tcEdi.getTreeCellEditorComponent( self.jtree, p, p.isCurrentPosition(), p.isExpanded(), p.numberOfChildren(), row )
        return self.__createImage( comp )    
        
        
        
    def getRendererImageOfNode( self, p ):
    
        path = self.posTM.getPathToRoot( p )
        row = self.jtree.getRowForPath( path ) 
        comp = self.renderer.getTreeCellRendererComponent( self.jtree, p, p.isCurrentPosition(), 
                                                           p.isExpanded(), p.numberOfChildren(), row, True ) 
        return self.__createImage( comp )
        
    def __createImage( self, component ):
        
        psize = component.getPreferredSize()
        bi = awt.image.BufferedImage( psize.width, psize.height, awt.image.BufferedImage.TYPE_INT_RGB )
        g = bi.createGraphics()
    
        #jw = swing.JWindow()
        #jw.toBack()
        #mpi = awt.MouseInfo.getPointerInfo()
        #location = mpi.getLocation()
        #jw.setLocation( location )
        #jw.add( component )
        #jw.setSize( psize )
        opaque = component.isOpaque()
        background = component.getBackground()
        component.setOpaque( True )
        component.setBackground( awt.Color.WHITE )
        #jw.visible = 1
        self.jtree.add( component )
        component.setSize( component.getPreferredSize() ) #this appears to work better then making a short lived window
        component.paint( g ) 
        self.jtree.remove( component )
        #jw.visible = 0
        component.setOpaque( opaque )
        component.setBackground( background )
        #jw.dispose()
        g.dispose()
        return bi          
        
        
        
    #@-node:zorcanda!.20051128113408:image creation
    #@+node:mork.20050127125058.93:beginUpdate
    def beginUpdate (self):
        
        self.updateCount += 1
        self.endEditLabel()
        if not self.settingPosition:
            self.paths = True
    #@nonl
    #@-node:mork.20050127125058.93:beginUpdate
    #@+node:mork.20050127125058.94:endUpdate
    def endUpdate (self,flag=True ):
    
        #print java.lang.Thread.currentThread() , self.updateCount
        #try:
        assert(self.updateCount > 0)
        self.updateCount -= 1
    
        # g.trace(self.updateCount)
        #if flag and self.updateCount == 0:
        #    self.redraw()
        if self.paths:
            self.reloading = True
            #posTM = self.posTM
            #c = self.c
            if not self.skip_reload and self.updateCount == 0:
                #cp = c.currentPosition().copy()
                #cp = self.chapter.getCurrentPosition().copy()
                self.posTM.dRun()
                #tp = self.posTM.getPathToRoot( cp )
                #self.tree_reloader.setCurrentPosition( tp )
                #swing.SwingUtilities.invokeLater( self.tree_reloader )               
                self._op = None
                self.paths = False
                self.reloading = False
                if hasattr( self, "_EditLabelEnabler" ):
                    self._EditLabelEnabler.addToEventQueue()
                
    #@-node:mork.20050127125058.94:endUpdate
    #@+node:mork.20050127125058.95:Getters/Setters (tree)
    def dragging(self):
        return self._dragging
    
    def getEditTextDict(self,v):
        # New in 4.2: the default is an empty list.
        return self.edit_text_dict.get(v,[])
    
    def editPosition(self):
        return self._editPosition
        
    def setDragging(self,flag):
        self._dragging = flag
    
    def setEditPosition(self,p):
        self._editPosition = p
    #@nonl
    #@-node:mork.20050127125058.95:Getters/Setters (tree)
    #@+node:zorcanda!.20050308094526:tree.getFont,setFont,setFontFromConfig
    def getFont (self):
    
        return self.font
            
    # Called by leoFontPanel.
    def setFont(self,font=None, fontName=None):
        
        # ESSENTIAL: retain a link to font.
        if fontName:
            self.fontName = fontName
            #self.font = tkFont.Font(font=fontName)
        else:
            self.fontName = None
            self.font = font
        print "SETTING FONT!!!!"
            
        self.setLineHeight(self.font)
        
    # Called by ctor and when config params are reloaded.
    def setFontFromConfig (self):
        
        c = self.c
        font = c.config.getFontFromParams(
            "headline_text_font_family", "headline_text_font_size",
            "headline_text_font_slant",  "headline_text_font_weight",
            c.config.defaultTreeFontSize, tag = "tree")
        
        
        #    font = config.getFontFromParams( self.c,
        #    "log_text_font_family", "log_text_font_size",
        #    "log_text_font_slant",  "log_text_font_weight",
        #    config.defaultLogFontSize)
        
        #font2 = c.config.getFontFromParams( self.c,
        #    "headline_text_font_family", "headline_text_font_size",
        #    "headline_text_font_slant",  "headline_text_font_weight",
        #    c.config.defaultTreeFontSize )#, tag = "tree")
        
        
        #self.setFont(font)
        self.jtree.setFont( font )
    #@nonl
    #@-node:zorcanda!.20050308094526:tree.getFont,setFont,setFontFromConfig
    #@+node:zorcanda!.20050308094526.1:setBackgroundColor
    def setBackgroundColor (self, notification = None, handback = None ):
        
        c = self.c
    
        color = c.config.getColor("outline_pane_background_color")
        bg = getColorInstance( color, awt.Color.WHITE )
    
        try:
            #self.canvas.configure(bg=bg)
            self.jtree.setBackground( bg )
        except:
            g.es("exception setting outline pane background color")
            g.es_exception()
    #@nonl
    #@-node:zorcanda!.20050308094526.1:setBackgroundColor
    #@+node:mork.20050127125058.96:oops
    def oops(self):
        
        print "leoTree oops:", g.callerName(2), "should be overridden in subclass"
    #@nonl
    #@-node:mork.20050127125058.96:oops
    #@+node:mork.20050127125058.97:tree.OnIconDoubleClick (@url)
    def OnIconDoubleClick (self,v,event=None):
    
        # Note: "icondclick" hooks handled by vnode callback routine.
    
        c = self.c
        s = v.headString().strip()
        if g.match_word(s,0,"@url"):
            if not g.doHook("@url1",c=c,v=v):
                url = s[4:].strip()
                #@            << stop the url after any whitespace >>
                #@+node:mork.20050127125058.98:<< stop the url after any whitespace  >>
                # For safety, the URL string should end at the first whitespace.
                
                url = url.replace('\t',' ')
                i = url.find(' ')
                if i > -1:
                    if 0: # No need for a warning.  Assume everything else is a comment.
                        g.es("ignoring characters after space in url:"+url[i:])
                        g.es("use %20 instead of spaces")
                    url = url[:i]
                #@-node:mork.20050127125058.98:<< stop the url after any whitespace  >>
                #@nl
                #@            << check the url; return if bad >>
                #@+node:mork.20050127125058.99:<< check the url; return if bad >>
                if not url or len(url) == 0:
                    g.es("no url following @url")
                    return
                    
                #@+at 
                #@nonl
                # A valid url is (according to D.T.Hein):
                # 
                # 3 or more lowercase alphas, followed by,
                # one ':', followed by,
                # one or more of: (excludes !"#;<>[\]^`|)
                #   $%&'()*+,-./0-9:=?@A-Z_a-z{}~
                # followed by one of: (same as above, except no minus sign or 
                # comma).
                #   $%&'()*+/0-9:=?@A-Z_a-z}~
                #@-at
                #@@c
                
                urlPattern = "[a-z]{3,}:[\$-:=?-Z_a-z{}~]+[\$-+\/-:=?-Z_a-z}~]"
                import re
                # 4/21/03: Add http:// if required.
                if not re.match('^([a-z]{3,}:)',url):
                    url = 'http://' + url
                if not re.match(urlPattern,url):
                    g.es("invalid url: "+url)
                    return
                #@-node:mork.20050127125058.99:<< check the url; return if bad >>
                #@nl
                #@            << pass the url to the web browser >>
                #@+node:mork.20050127125058.100:<< pass the url to the web browser >>
                #@+at 
                #@nonl
                # Most browsers should handle the following urls:
                #   ftp://ftp.uu.net/public/whatever.
                #   http://localhost/MySiteUnderDevelopment/index.html
                #   file://home/me/todolist.html
                #@-at
                #@@c
                
                try:
                    import os
                    os.chdir(g.app.loadDir)
                
                    if g.match(url,0,"file:") and url[-4:]==".leo":
                        ok,frame = g.openWithFileName(url[5:],c)
                        if ok:
                            frame.bringToFront()
                    else:
                        import webbrowser
                        
                        # Mozilla throws a weird exception, then opens the file!
                        try: webbrowser.open(url)
                        except: pass
                except:
                    g.es("exception opening " + url)
                    g.es_exception()
                
                #@-node:mork.20050127125058.100:<< pass the url to the web browser >>
                #@nl
            g.doHook("@url2",c=c,v=v)
    #@nonl
    #@-node:mork.20050127125058.97:tree.OnIconDoubleClick (@url)
    #@+node:mork.20050127125058.101:tree.enableDrawingAfterException
    def enableDrawingAfterException (self):
        pass
    #@nonl
    #@-node:mork.20050127125058.101:tree.enableDrawingAfterException
    #@+node:orkman.20050201170249:edit_text --had to be added
    def edit_text( self, p ):
        
        return self.c.frame.body.editor.editor
        
    #@-node:orkman.20050201170249:edit_text --had to be added
    #@-others
#@nonl
#@-node:mork.20050127125058.83:class leoSwingTree
#@+node:zorcanda!.20050307120246:functions
#@+node:zorcanda!.20050307120246.1:getColorInstance
def getColorInstance( val, OnNone=None ):
    
    if hasattr( awt.Color, val ):
        return getattr( awt.Color, val )
    else:
        try:
            l = java.lang.Long.parseLong( val, 16 )
            l2 = java.lang.Long( l )
            color = awt.Color.decode( "%s" % l2.intValue() )
            return color
            
        except java.lang.Exception, x:
            #print 'WHATDA!!!!  %s' % x
            pass
    
    return OnNone
#@nonl
#@-node:zorcanda!.20050307120246.1:getColorInstance
#@-node:zorcanda!.20050307120246:functions
#@+node:zorcanda!.20050307205914:execute on load
tk = awt.Toolkit.getDefaultToolkit()
tk.setDynamicLayout( True )
#@nonl
#@-node:zorcanda!.20050307205914:execute on load
#@+node:zorcanda!.20050415161103:class leoJSPFocusListener
class leoJSPFocusListener( aevent.FocusListener ):
    '''A Class that changes the border of a focused JViewPort'''
    
    _listeners = {}
    
    def __init__( self, jsp, c ):
        self.jsp = jsp
        self.c = c
        color = g.app.config.getColor( c, "component_focused_bordor_color" )
        self.fcolor = getColorInstance( color, awt.Color.RED )
        color = g.app.config.getColor( c, "component_unfocused_bordor_color" )
        self.ucolor = getColorInstance( color, awt.Color.GREEN )
        
        self.border = self.LineBorder2( self.ucolor )
        jsp.setViewportBorder( self.border )
        if not leoJSPFocusListener._listeners.has_key( c ):
            group =  leoJSPFocusListener._listeners[ c ] = []
        else:
            group = leoJSPFocusListener._listeners[ c ]
        group.append( self )

    def focusGained( self, event ):
        
        self.border.setColor( self.fcolor )
        self.jsp.repaint()
        group = leoJSPFocusListener._listeners[ self.c ] 
        for x in group:
            if x == self: continue
            else:
                x.border.setColor( self.ucolor )
                x.jsp.repaint()
    
    def focusLost( self, event ):
        pass 
        
        
    class LineBorder2( sborder.LineBorder ):
        
        def __init__( self, color ):
            sborder.LineBorder.__init__( self, color )
            self.color = color
            
            
        def setColor( self, color ):
            self.color = color
            
            
        def paintBorder( self, c, g, x,y,w,h ):
            
            g.setColor( self.color )
            g.drawRect( x, y, w -1, h -1 )
            
#@nonl
#@-node:zorcanda!.20050415161103:class leoJSPFocusListener
#@+node:zorcanda!.20050810151252:class VisibleInformer
class VisibleInformer( sevent.ChangeListener ):
    '''A class that allows a change in the tab of a tabbed pane to
       be used as a notification to registered callbacks.'''
       
    def __init__( self, tabbedpane ):
        self.tabbedpane = tabbedpane #should be a JTabbedPane, or at least a component that has:
                                     #getSelectedComponent and an addChangeListener method
        tabbedpane.addChangeListener( self )
        self.callbacks = {}
        
    def addCallback( self, component, callback ):
        self.callbacks[ component ] = callback
        
    def stateChanged( self, event ):
        
        component = self.tabbedpane.getSelectedComponent()
        if self.callbacks.has_key( component ):
            self.callbacks[ component ]()    
    
#@nonl
#@-node:zorcanda!.20050810151252:class VisibleInformer
#@-others
#@nonl
#@-node:mork.20050127125058.31:@thin leoSwingFrame.py
#@-leo
