leoChapters.py :  » Development » Leo » Leo-4.7.1-final » leo » core » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » Development » Leo 
Leo » Leo 4.7.1 final » leo » core » leoChapters.py
#@+leo-ver=4-thin
#@+node:ekr.20070317085508.1:@thin leoChapters.py
'''Classes that manage chapters in Leo's core.'''

#@@language python
#@@tabwidth -4
#@@pagewidth 70

import leo.core.leoGlobals as g

# To do later or never: Make body editors persistent. Create @body-editor node?

#@+others
#@+node:ekr.20070317085437:class chapterController
class chapterController:

    '''A per-commander controller that manages chapters and related nodes.'''

    #@    @+others
    #@+node:ekr.20070530075604:Birth
    #@+node:ekr.20070317085437.2: ctor: chapterController
    def __init__ (self,c):

        self.c = c

        self.chaptersDict = {}
            # Keys are chapter names, values are chapters.
            # Important: chapter names never change, even if their @chapter node changes.

        self.chaptersNode = None # Set later
        self.selectedChapter = None
        self.trace = False
        self.tt = None # May be set in finishCreate.
        self.use_tabs = c.config.getBool('use_chapter_tabs')

        # g.trace('chapterController',g.callers())
    #@-node:ekr.20070317085437.2: ctor: chapterController
    #@+node:ekr.20070325104904:cc.finishCreate
    def finishCreate (self):

        '''Find or make the @chapters and @chapter trash nodes.'''

        # This must be called late in the init process:
        # at present, called by g.openWithFileName and c.new.

        cc = self ; c = cc.c

        # Create the @chapters node if needed, and set cc.chaptersNode.
        if not cc.chaptersNode and not cc.findChaptersNode():
            cc.createChaptersNode()

        # Create the main chapter
        cc.chaptersDict['main'] = chapter(c=c,chapterController=cc,name='main',root=c.rootPosition())

        tag = '@chapter'
        for p in c.all_unique_positions():
            h = p.h
            if h.startswith(tag) and not h.startswith('@chapters'):
                tabName = h[len(tag):].strip()
                if tabName and tabName not in ('main',):
                    if cc.chaptersDict.get(tabName):
                        self.error('duplicate chapter name: %s' % tabName)
                    else:
                        cc.chaptersDict[tabName] = chapter(c=c,chapterController=cc,name=tabName,root=p)

        # Always select the main chapter.
        # It can be alarming to open a small chapter in a large .leo file.
        cc.selectChapterByName('main')
    #@-node:ekr.20070325104904:cc.finishCreate
    #@-node:ekr.20070530075604:Birth
    #@+node:ekr.20070317085437.30:Commands (chapters)
    #@+node:ekr.20070317085437.50:cc.cloneNodeToChapter & helper
    def cloneNodeToChapter (self,event=None):

        '''Prompt for a chapter name,
        then clone the selected node to the chapter.'''

        cc = self ; k = cc.c.k ; tag = 'clone-node-to-chapter'
        state = k.getState(tag)

        if state == 0:
            names = list(cc.chaptersDict.keys())
            prefix = 'Clone node to chapter: '
            k.setLabelBlue(prefix,protect=True)
            k.getArg(event,tag,1,self.cloneNodeToChapter,prefix=prefix,tabList=names)
        else:
            k.clearState()
            k.resetLabel()
            if k.arg:
                cc.cloneNodeToChapterHelper(k.arg)
    #@nonl
    #@+node:ekr.20070604155815.1:cc.cloneToChapterHelper
    def cloneNodeToChapterHelper (self,toChapterName):

        cc = self ; c = cc.c ;  u = c.undoer ; undoType = 'Clone Node To Chapter'
        p = c.p ; h = p.h
        fromChapter = cc.getSelectedChapter()
        toChapter = cc.getChapter(toChapterName)
        if not toChapter:
            return cc.error('no such chapter: %s' % toChapterName)
        if fromChapter.name == 'main' and h.startswith('@chapter'):
            return cc.error('can not clone @chapter node')
        # g.trace('from',fromChapter.name,'to',toChapter)

        # Open the group undo.
        c.undoer.beforeChangeGroup(p,undoType)
        # Do the clone.  c.clone handles the inner undo.
        clone = c.clone()
        # Do the move.
        undoData2 = u.beforeMoveNode(clone)
        if toChapter.name == 'main':
            clone.moveAfter(toChapter.p)
        else:
            parent = cc.getChapterNode(toChapter.name)
            clone.moveToLastChildOf(parent)
        u.afterMoveNode(clone,'Move Node',undoData2,dirtyVnodeList=[])
        c.redraw(clone)
        c.setChanged(True)
        # Close the group undo.
        # Only the ancestors of the moved node get set dirty.
        dirtyVnodeList = clone.setAllAncestorAtFileNodesDirty()
        c.undoer.afterChangeGroup(clone,undoType,reportFlag=False,dirtyVnodeList=dirtyVnodeList)

        toChapter.p = clone.copy()
        toChapter.select()
        fromChapter.p = p.copy()
    #@-node:ekr.20070604155815.1:cc.cloneToChapterHelper
    #@-node:ekr.20070317085437.50:cc.cloneNodeToChapter & helper
    #@+node:ekr.20070608072116:cc.convertNodeToChapter
    def convertNodeToChapter (self,event=None):

        '''convert-node-to-chapter command.

        Make the selected node into a new chapter, 'in place'.
        That is, create the new @chapter node as the next sibling of the node,
        then move the node as the first child of the new @chapter node.'''

        cc = self ; c = cc.c ; k = c.k ; tag = 'convert-node-to-chapter'
        state = k.getState(tag)

        p = c.p
        if p.h.startswith('@chapter'):
            cc.error('Can not create a new chapter from from an @chapter or @chapters node.')
            return

        if state == 0:
            names = list(cc.chaptersDict.keys())
            k.setLabelBlue('Convert node to chapter: ',protect=True)
            k.getArg(event,tag,1,self.convertNodeToChapter,tabList=names)
        else:
            k.clearState()
            k.resetLabel()
            if k.arg:
                cc.createChapterByName(k.arg,p=c.p,
                    undoType='Convert Node To Chapter')
    #@-node:ekr.20070608072116:cc.convertNodeToChapter
    #@+node:ekr.20070317085437.51:cc.copyNodeToChapter & helper
    def copyNodeToChapter (self,event=None):

        '''Prompt for a chapter name,
        then copy the selected node to the chapter.'''

        cc = self ; k = cc.c.k ; tag = 'copy-node-to-chapter'
        state = k.getState(tag)

        if state == 0:
            names = list(cc.chaptersDict.keys())
            prefix = 'Copy node to chapter: '
            k.setLabelBlue(prefix,protect=True)
            k.getArg(event,tag,1,self.copyNodeToChapter,prefix=prefix,tabList=names)
        else:
            k.clearState()
            k.resetLabel()
            if k.arg:
                cc.copyNodeToChapterHelper(k.arg)
    #@nonl
    #@+node:ekr.20070604155815.2:cc.copyNodeToChapterHelper
    def copyNodeToChapterHelper (self,toChapterName):

        cc = self ; c = cc.c ; u = c.undoer ; undoType = 'Copy Node To Chapter'
        p = c.p ; h = p.h
        fromChapter = cc.getSelectedChapter()
        toChapter = cc.getChapter(toChapterName)
        if not toChapter:
            return cc.error('no such chapter: %s' % toChapterName)
        if fromChapter.name == 'main' and h.startswith('@chapter'):
            return cc.error('can not copy @chapter node')
        # g.trace('from',fromChapter.name,'to',toChapter.name)

        # For undo, we treat the copy like a pasted (inserted) node.
        # Use parent as the node to select for undo.
        parent = cc.getChapterNode(toChapter.name)
        undoData = u.beforeInsertNode(parent,pasteAsClone=False,copiedBunchList=[])
        s = c.fileCommands.putLeoOutline()
        p2 = c.fileCommands.getLeoOutline(s)
        p2.moveToLastChildOf(parent)
        c.redraw(p2)
        u.afterInsertNode(p2,undoType,undoData)
        c.setChanged(True)

        toChapter.p = p2.copy()
        toChapter.select()
        fromChapter.p = p.copy()
    #@-node:ekr.20070604155815.2:cc.copyNodeToChapterHelper
    #@-node:ekr.20070317085437.51:cc.copyNodeToChapter & helper
    #@+node:ekr.20070317085437.31:cc.createChapter
    def createChapter (self,event=None):

        '''create-chapter command.
        Create a chapter with a dummy first node.'''

        cc = self ; k = cc.c.k ; tag = 'create-chapter'
        state = k.getState(tag)

        if state == 0:
            names = list(cc.chaptersDict.keys())
            k.setLabelBlue('Create chapter: ',protect=True)
            k.getArg(event,tag,1,self.createChapter,tabList=names)
        else:
            k.clearState()
            k.resetLabel()
            if k.arg:
                cc.createChapterByName(k.arg,p=None,
                    undoType='Create Chapter')
    #@nonl
    #@-node:ekr.20070317085437.31:cc.createChapter
    #@+node:ekr.20070603190617:cc.createChapterByName
    def createChapterByName (self,name,p,undoType):

        cc = self ; c = cc.c

        if not name:
            return cc.error('No name')

        oldChapter = cc.getSelectedChapter()
        theChapter = cc.chaptersDict.get(name)
        if theChapter:
            return cc.error('Duplicate chapter name: %s' % name)

        bunch = cc.beforeCreateChapter(c.p,oldChapter.name,name,undoType)
        if undoType == 'Convert Node To Chapter':
            root = p.insertAfter()
            root.initHeadString('@chapter %s' % name)
            p.moveToFirstChildOf(root)
        elif undoType in ('Create Chapter From Node','Create Chapter'):
            # Create the @chapter node.
            # If p exists, clone it as the first child, else create a dummy first child.
            root = cc.getChapterNode(name,p=p)
        else:
            return g.trace('Can not happen: bad undoType: %s' % undoType)

        cc.chaptersDict[name] = chapter(c=c,chapterController=cc,name=name,root=root)
        cc.selectChapterByName(name)
        cc.afterCreateChapter(bunch,c.p)

        # g.es('created chapter',name,color='blue')
        return True
    #@-node:ekr.20070603190617:cc.createChapterByName
    #@+node:ekr.20070607092909:cc.createChapterFromNode
    def createChapterFromNode (self,event=None):

        '''create-chapter-from nodecommand. import 

        Create a chapter whose first node is a clone of the presently selected node.'''

        cc = self ; c = cc.c ; k = c.k ; tag = 'create-chapter-from-node'
        state = k.getState(tag)

        p = c.p
        if p.h.startswith('@chapter'):
            cc.error('Can not create a new chapter from from an @chapter or @chapters node.')
            return

        if state == 0:
            names = list(cc.chaptersDict.keys())
            k.setLabelBlue('Create chapter from node: ',protect=True)
            k.getArg(event,tag,1,self.createChapterFromNode,tabList=names)
        else:
            k.clearState()
            k.resetLabel()
            if k.arg:
                cc.createChapterByName(k.arg,p=p,
                    undoType='Create Chapter From Node')
    #@-node:ekr.20070607092909:cc.createChapterFromNode
    #@+node:ekr.20070604155815.3:cc.moveNodeToChapter & helper
    def moveNodeToChapter (self,event=None):

        '''Prompt for a chapter name,
        then move the selected node to the chapter.'''

        cc = self ; k = cc.c.k ; tag = 'move-node-to-chapter'
        state = k.getState(tag)

        if state == 0:
            names = list(cc.chaptersDict.keys())
            prefix = 'Move node to chapter: '
            k.setLabelBlue(prefix,protect=True)
            k.getArg(event,tag,1,self.moveNodeToChapter,prefix=prefix,tabList=names)
        else:
            k.clearState()
            k.resetLabel()
            if k.arg:
                cc.moveNodeToChapterHelper(k.arg)
    #@nonl
    #@+node:ekr.20070317085437.52:cc.moveNodeToChapterHelper
    def moveNodeToChapterHelper (self,toChapterName):

        cc = self ; c = cc.c ; u = c.undoer ; undoType = 'Move Node To Chapter'
        p = c.p
        fromChapter = cc.getSelectedChapter()
        toChapter = cc.getChapter(toChapterName)
        if not toChapter:
            return cc.error('chapter "%s" does not exist' % toChapterName)

        if 1: # Defensive code: should never happen.
            if fromChapter.name == 'main' and p.h.startswith('@chapter'):
                return cc.error('can not move @chapter node')

        if toChapter.name == 'main':
            sel = (p.threadBack() != fromChapter.root and p.threadBack()) or p.nodeAfterTree()
        else:
            sel = p.threadBack() or p.nodeAfterTree()
        if sel:
            # Get 'before' undo data.
            inAtIgnoreRange = p.inAtIgnoreRange()
            undoData = u.beforeMoveNode(p)
            dirtyVnodeList = p.setAllAncestorAtFileNodesDirty()
            # Do the move.
            if toChapter.name == 'main':
                p.moveAfter(toChapter.p)
            else:
                p.moveToLastChildOf(toChapter.root)
            c.redraw(sel)
            c.setChanged(True)
            # Do the 'after' undo operation.
            if inAtIgnoreRange and not p.inAtIgnoreRange():
                # The moved nodes have just become newly unignored.
                dirtyVnodeList2 = p.setDirty() # Mark descendent @thin nodes dirty.
                dirtyVnodeList.extend(dirtyVnodeList2)
            else: # No need to mark descendents dirty.
                dirtyVnodeList2 = p.setAllAncestorAtFileNodesDirty()
                dirtyVnodeList.extend(dirtyVnodeList2)
            u.afterMoveNode(p,undoType,undoData,dirtyVnodeList=dirtyVnodeList)

        if sel:
            toChapter.p = p.copy()
            toChapter.select()
            fromChapter.p = sel.copy()
        else:
            cc.error('Can not move the last node of a chapter.')
    #@-node:ekr.20070317085437.52:cc.moveNodeToChapterHelper
    #@-node:ekr.20070604155815.3:cc.moveNodeToChapter & helper
    #@+node:ekr.20070317085437.40:cc.removeChapter
    def removeChapter (self,event=None):

        cc = self ; c = cc.c

        theChapter = cc.selectedChapter
        if not theChapter: return

        name = theChapter.name

        if name == 'main':
            return cc.error('Can not remove the main chapter')
        else:
            cc.removeChapterByName(name)
    #@-node:ekr.20070317085437.40:cc.removeChapter
    #@+node:ekr.20070606075434:cc.removeChapterByName
    def removeChapterByName (self,name):

        cc = self ; c = cc.c ; tt = cc.tt

        theChapter = cc.chaptersDict.get(name)
        if not theChapter: return

        savedRoot = theChapter.root
        bunch = cc.beforeRemoveChapter(c.p,name,savedRoot)
        cc.deleteChapterNode(name)
        del cc.chaptersDict[name] # Do this after calling deleteChapterNode.
        if tt:tt.destroyTab(name)
        cc.selectChapterByName('main')
        cc.afterRemoveChapter(bunch,c.p)
        c.redraw()
    #@-node:ekr.20070606075434:cc.removeChapterByName
    #@+node:ekr.20070317085437.41:cc.renameChapter
    # newName is for unitTesting.

    def renameChapter (self,event=None,newName=None):

        '''Use the minibuffer to get a new name for the present chapter.'''

        cc = self ; c = cc.c ; k = cc.c.k ; tt = cc.tt
        tag = 'rename-chapter'
        theChapter = cc.selectedChapter
        if not theChapter: return
        if theChapter.name == 'main':
            return cc.error('Can not rename the main chapter')

        state = k.getState(tag)

        if state == 0 and not newName:
            names = list(cc.chaptersDict.keys())
            prefix = 'Rename this chapter: '
            k.setLabelBlue(prefix,protect=True)
            k.getArg(event,tag,1,self.renameChapter,prefix=prefix,tabList=names)
        else:
            k.clearState()
            k.resetLabel()
            if newName: k.arg = newName
            if k.arg and k.arg != theChapter.name:
                oldChapterName = theChapter.name
                del cc.chaptersDict[theChapter.name]
                cc.chaptersDict[k.arg] = theChapter
                theChapter.name = k.arg
                root = theChapter.root
                root.initHeadString('@chapter %s' % k.arg)
                if tt:
                    tt.setTabLabel(k.arg)
                    tt.destroyTab(oldChapterName)
                    tt.createTab(k.arg)
                c.redraw()
    #@-node:ekr.20070317085437.41:cc.renameChapter
    #@+node:ekr.20070604165126:cc.selectChapter
    def selectChapter (self,event=None):

        '''Use the minibuffer to get a chapter name,
        then create the chapter.'''

        cc = self ; k = cc.c.k ; tag = 'select-chapter'
        state = k.getState(tag)

        if state == 0:
            names = list(cc.chaptersDict.keys())
            g.es('Chapters:\n' + '\n'.join(names))
            prefix = 'Select chapter: '
            k.setLabelBlue(prefix,protect=True)
            k.getArg(event,tag,1,self.selectChapter,prefix=prefix,tabList=names)
        else:
            k.clearState()
            k.resetLabel()
            if k.arg:
                cc.selectChapterByName(k.arg)
    #@-node:ekr.20070604165126:cc.selectChapter
    #@+node:ekr.20070317130250:cc.selectChapterByName & helper
    def selectChapterByName (self,name,collapse=True):

        '''Select a chapter.  Return True if a redraw is needed.'''

        cc = self ; c = cc.c

        chapter = cc.chaptersDict.get(name)

        if chapter:
            self.selectChapterByNameHelper(chapter,collapse=collapse)
        else:
            cc.error('cc.selectChapter: no such chapter: %s' % name)
            chapter = cc.chaptersDict.get('main')
            if chapter:
                self.selectChapterByNameHelper(chapter,collapse=collapse)
            else:
                cc.error('no main chapter!')
    #@+node:ekr.20090306060344.2:selectChapterHelper
    def selectChapterByNameHelper (self,chapter,collapse=True):

        cc = self ; c = cc.c

        if chapter != cc.selectedChapter:
            if cc.selectedChapter:
                cc.selectedChapter.unselect()
            chapter.select()
            c.setCurrentPosition(chapter.p)
            cc.selectedChapter = chapter

            # New in Leo 4.6 b2: clean up, but not initially.
            if collapse and chapter.name == 'main':
                for p in c.all_unique_positions():
                    # 2010/01/26: compare vnodes, not positions.
                    if p.v != c.p.v:
                        p.contract()

            # New in Leo 4.6 b2: *do* call c.redraw.
            c.redraw()
    #@-node:ekr.20090306060344.2:selectChapterHelper
    #@-node:ekr.20070317130250:cc.selectChapterByName & helper
    #@-node:ekr.20070317085437.30:Commands (chapters)
    #@+node:ekr.20070511081405:Creating/deleting nodes (chapterController)
    #@+node:ekr.20070325101652:cc.createChaptersNode
    def createChaptersNode (self):

        cc = self ; c = cc.c ; root = c.rootPosition()

        # Create the node with a postion method
        # so we don't involve the undo logic.
        # g.trace('root',root)
        p = root.insertAsLastChild()
        p.initHeadString('@chapters')
        p.moveToRoot(oldRoot=root)
        c.setRootPosition(p)
        cc.chaptersNode = p.copy()
        v = p.v
        assert(v.fileIndex)
        c.setChanged(True)
    #@-node:ekr.20070325101652:cc.createChaptersNode
    #@+node:ekr.20070325063303.2:cc.createChapterNode
    def createChapterNode (self,chapterName,p=None):

        '''Create an @chapter node for the named chapter.
        Use p for the first child, or create a first child if p is None.'''

        cc = self ; c = cc.c
        current = c.p or c.rootPosition()

        # Create the node with a postion method
        # so we don't involve the undo logic.
        root = current.insertAsLastChild()
        root.initHeadString('@chapter ' + chapterName)
        root.moveToFirstChildOf(cc.chaptersNode)
        if p:
            # Clone p and move it to the first child of the root.
            clone = p.clone()
            clone.moveToFirstChildOf(root)
        else:
            cc.createChild(root,'%s node 1' % chapterName)
        c.setChanged(True)

        return root
    #@-node:ekr.20070325063303.2:cc.createChapterNode
    #@+node:ekr.20070509081915.1:cc.createChild
    def createChild (self,parent,s):

        '''Create a child node of parent without changing the undo stack.
        set the headString of the new node to s.'''

        c = self.c
        p = parent.insertAsLastChild()
        p.initHeadString(s)
        c.setChanged(True)

        return p
    #@-node:ekr.20070509081915.1:cc.createChild
    #@+node:ekr.20070325063303.4:cc.deleteChapterNode
    def deleteChapterNode (self,chapterName):

        '''Delete the @chapter with the given name.'''

        cc = self ; c = cc.c

        chapter = cc.chaptersDict.get(chapterName)

        if chapter:
            # Do not involve undo logic.
            c.setCurrentPosition(chapter.root)
            chapter.root.doDelete()
            # The chapter selection logic will select a new node.
            c.setChanged(True)
    #@-node:ekr.20070325063303.4:cc.deleteChapterNode
    #@-node:ekr.20070511081405:Creating/deleting nodes (chapterController)
    #@+node:ekr.20070317130648:Utils
    #@+node:ekr.20070320085610:cc.error
    def error (self,s):

        g.es_print(s,color='red')
    #@-node:ekr.20070320085610:cc.error
    #@+node:ekr.20070325093617:cc.findChapterNode
    def findChapterNode (self,chapterName,giveError=True):

        '''Return the position of the @chapter node with the given name.'''

        cc = self

        if not cc.chaptersNode:
            return # An error has already been given.

        s = '@chapter ' + chapterName
        for p in cc.chaptersNode.children():
            h = p.h
            if h == s:
                return p

        if giveError:
            cc.error('*** findChapterNode: no @chapter node for: %s' % (chapterName))

        return None
    #@-node:ekr.20070325093617:cc.findChapterNode
    #@+node:ekr.20070325094401:cc.findChaptersNode
    def findChaptersNode (self):

        '''Return the position of the @chapters node.'''

        cc = self ; c = cc.c

        for p in c.all_unique_positions():
            if p.h == '@chapters':
                cc.chaptersNode = p.copy()
                return p

        # This is *not* an error.
        return None
    #@-node:ekr.20070325094401:cc.findChaptersNode
    #@+node:ekr.20070605124356:cc.inChapter
    def inChapter (self):

        cc = self

        theChapter = cc.getSelectedChapter()
        return theChapter and theChapter.name != 'main'
    #@-node:ekr.20070605124356:cc.inChapter
    #@+node:ekr.20070325115102:cc.getChapterNode
    def getChapterNode (self,chapterName,p=None):

        '''Return the position of the @chapter node with the given name.'''

        cc = self ; c = cc.c

        if chapterName == 'main':
            return c.rootPosition()
        else:
            val = (
                cc.findChapterNode(chapterName,giveError=False) or
                cc.createChapterNode(chapterName,p=p))
            return val
    #@-node:ekr.20070325115102:cc.getChapterNode
    #@+node:ekr.20070318124004:cc.getChapter
    def getChapter(self,name):

        cc = self

        return cc.chaptersDict.get(name)
    #@-node:ekr.20070318124004:cc.getChapter
    #@+node:ekr.20070318122708:cc.getSelectedChapter
    def getSelectedChapter (self):

        cc = self

        return cc.selectedChapter
    #@-node:ekr.20070318122708:cc.getSelectedChapter
    #@+node:ekr.20070510064813:cc.printChaptersTree
    def printChaptersTree(self,tag=''):

        cc = self ; c = cc.c ; root = cc.chaptersNode

        for p in c.rootPosition().self_and_siblings():
            for p2 in p.self_and_subtree():
                if p2 == root:
                    inTree = True ; break
        else:
            inTree = False

        g.trace('-'*40)

        full = True

        if root and full:
            g.pr('@chapters tree...','(in main tree: %s)' % inTree)
            for p in root.self_and_subtree():
                g.pr('.'*p.level(),p.v)
    #@nonl
    #@-node:ekr.20070510064813:cc.printChaptersTree
    #@+node:ekr.20070615075643:cc.selectChapterForPosition
    def selectChapterForPosition (self,p):

        '''
        Select a chapter containing position p.
        Do nothing if p if p does not exist or is in the presently selected chapter.
        '''
        cc = self ; c = cc.c ; trace = False

        if not p or not c.positionExists(p):
            return

        theChapter = cc.getSelectedChapter()
        if not theChapter:
            if trace: g.trace('no chapter')
            return

        if trace: g.trace('selected:',theChapter.name)
        # First, try the presently selected chapter.
        firstName = theChapter.name
        if firstName == 'main' or theChapter.positionIsInChapter(p):
            if trace: g.trace('in chapter:',theChapter.name)
            return

        for name in cc.chaptersDict:
            if name not in (firstName,'main'):
                theChapter = cc.chaptersDict.get(name)
                if theChapter.positionIsInChapter(p):
                    if trace: g.trace('select:',theChapter.name)
                    cc.selectChapterByName(name)
                    return
        else:
            if trace: g.trace('select main')
            cc.selectChapterByName('main')
    #@-node:ekr.20070615075643:cc.selectChapterForPosition
    #@+node:ekr.20071028091719:cc.findChapterNameForPosition
    def findChapterNameForPosition (self,p):

        '''
        Return the name of a chapter containing p or None if p does not exist.
        '''
        cc = self ; c = cc.c

        if not p or not c.positionExists(p):
            return None

        for name in cc.chaptersDict:
            if name != 'main':
                theChapter = cc.chaptersDict.get(name)
                if theChapter.positionIsInChapter(p):
                    return name
        else:
            return 'main'
    #@-node:ekr.20071028091719:cc.findChapterNameForPosition
    #@-node:ekr.20070317130648:Utils
    #@+node:ekr.20070610100031:Undo
    #@+node:ekr.20070606075125:afterCreateChapter
    def afterCreateChapter (self,bunch,p):

        cc = self ; u = cc.c.undoer
        if u.redoing or u.undoing: return

        bunch.kind = 'create-chapter'
        bunch.newP = p.copy()

        # Set helpers
        bunch.undoHelper = cc.undoInsertChapter
        bunch.redoHelper = cc.redoInsertChapter

        u.pushBead(bunch)
    #@-node:ekr.20070606075125:afterCreateChapter
    #@+node:ekr.20070610091608:afterRemoveChapter
    def afterRemoveChapter (self,bunch,p):

        cc = self ; u = cc.c.undoer
        if u.redoing or u.undoing: return

        bunch.kind = 'remove-chapter'
        bunch.newP = p.copy()

        # Set helpers
        bunch.undoHelper = cc.undoRemoveChapter
        bunch.redoHelper = cc.redoRemoveChapter

        u.pushBead(bunch)
    #@-node:ekr.20070610091608:afterRemoveChapter
    #@+node:ekr.20070606082729:beforeCreateChapter
    def beforeCreateChapter (self,p,oldChapterName,newChapterName,undoType):

        cc = self ; u = cc.c.undoer

        bunch = u.createCommonBunch(p)

        bunch.oldChapterName = oldChapterName
        bunch.newChapterName = newChapterName
        bunch.savedRoot = None
        bunch.undoType = undoType

        return bunch
    #@-node:ekr.20070606082729:beforeCreateChapter
    #@+node:ekr.20070610091608.1:beforeRemoveChapter
    def beforeRemoveChapter (self,p,newChapterName,savedRoot):

        cc = self ; u = cc.c.undoer

        bunch = u.createCommonBunch(p)

        bunch.newChapterName = newChapterName
        bunch.savedRoot = savedRoot
        bunch.undoType = 'Remove Chapter'

        return bunch
    #@-node:ekr.20070610091608.1:beforeRemoveChapter
    #@+node:ekr.20070606081341:redoInsertChapter
    def redoInsertChapter (self):

        cc = self ; c = cc.c ; u = c.undoer

        # g.trace(u.newChapterName,u.oldChapterName,u.p)

        cc.createChapterByName(u.newChapterName,p=u.savedRoot,undoType=u.undoType)
        theChapter = cc.getChapter(u.newChapterName)

        if u.undoType == 'Convert Node To Chapter':
            pass
        elif u.undoType in ('Create Chapter From Node','Create Chapter'):
            root = theChapter.root
            firstChild = root.firstChild()
            firstChild._unlink()
            firstChild = u.savedRoot.firstChild()
            firstChild._linkAsNthChild(root,0)
        else:
            return g.trace('Can not happen: bad undoType: %s' % u.undoType)
    #@-node:ekr.20070606081341:redoInsertChapter
    #@+node:ekr.20070610100555:redoRemoveChapter
    def redoRemoveChapter (self):

        cc = self ; u = cc.c.undoer

        cc.removeChapterByName(u.newChapterName)
        cc.selectChapterByName('main')
    #@nonl
    #@-node:ekr.20070610100555:redoRemoveChapter
    #@+node:ekr.20070606074705:undoInsertChapter
    def undoInsertChapter (self):

        cc = self ; c = cc.c ; u = c.undoer

        newChapter = cc.getChapter(u.newChapterName)

        bunch = u.beads[u.bead]
        bunch.savedRoot = root = newChapter.root

        if u.undoType == 'Convert Node To Chapter':
            p = root.firstChild()
            p.moveAfter(root)
        else:
            pass # deleting the chapter will delete the node.

        cc.removeChapterByName(u.newChapterName)
        cc.selectChapterByName('main')
    #@-node:ekr.20070606074705:undoInsertChapter
    #@+node:ekr.20070610100555.1:undoRemoveChapter
    def undoRemoveChapter (self):

        cc = self ; c = cc.c ; u = c.undoer

        # u.savedRoot is the entire @chapter tree.
        # Link it as the last child of the @chapters node.
        parent = cc.findChaptersNode()
        u.savedRoot._linkAsNthChild(parent,parent.numberOfChildren())

        # Now recreate the chapter.
        name = u.newChapterName
        cc.chaptersDict[name] = chapter(c=c,chapterController=cc,name=name,root=u.savedRoot)
        cc.selectChapterByName(name)
    #@-node:ekr.20070610100555.1:undoRemoveChapter
    #@-node:ekr.20070610100031:Undo
    #@-others
#@nonl
#@-node:ekr.20070317085437:class chapterController
#@+node:ekr.20070317085708:class chapter
class chapter:

    '''A class representing the non-gui data of a single chapter.'''

    #@    @+others
    #@+node:ekr.20070317085708.1: ctor: chapter
    def __init__ (self,c,chapterController,name,root):

        self.c = c 
        self.cc = cc = chapterController
        self.hoistStack = []
        self.name = name
        self.selectLockout = False # True: in chapter.select logic.
        self.trace = False

        # State variables: saved/restored when the chapter is unselected/selected.
        if self.name == 'main':
            self.p = c.p or c.rootPosition()
            self.root = None # Not used.
        else:
            self.p = None # Set later.
            self.root = root and root.copy() # The immutable @chapter node.
            bunch = g.Bunch(p=self.root.copy(),expanded=True)
            self.hoistStack.append(bunch)

        if cc.tt:
            cc.tt.createTab(name)
    #@nonl
    #@-node:ekr.20070317085708.1: ctor: chapter
    #@+node:ekr.20070317085708.2:__str__ and __repr__(chapter)
    def __str__ (self):

        return '<chapter id: %s name: %s p: %s>' % (
            id(self),
            self.name,
            self.p and self.p.h or '<no p>')

    __repr__ = __str__
    #@-node:ekr.20070317085708.2:__str__ and __repr__(chapter)
    #@+node:ekr.20070325155208.1:chapter.error
    def error (self,s):

        self.cc.error(s)
    #@nonl
    #@-node:ekr.20070325155208.1:chapter.error
    #@+node:ekr.20070317131205.1:chapter.select & helpers
    def select (self,w=None,selectEditor=True):

        '''Restore chapter information and redraw the tree when a chapter is selected.'''

        if self.selectLockout: return

        try:
            self.selectLockout = True
            self.chapterSelectHelper(w,selectEditor)
            if self.cc.tt:
                self.cc.tt.setTabLabel(self.name)
        finally:
            self.selectLockout = False
    #@+node:ekr.20070423102603.1:chapterSelectHelper
    def chapterSelectHelper (self,w=None,selectEditor=True):

        c = self.c ; cc = self.cc ; name = self.name

        # g.trace(name,'self.p',self.p) # ,'self.root',self.root) # 'w.leo_p',w and w.leo_p)

        cc.selectedChapter = self

        # Next, recompute p and possibly select a new editor.
        if w:
            assert w == c.frame.body.bodyCtrl
            assert w.leo_p
            # g.trace(name,'w.leo_p',w.leo_p,'p',p)
            self.p = p = self.findPositionInChapter(w.leo_p)
            if p != w.leo_p: g.trace('****** can not happen: lost p',w.leo_p)
        else:
            # This must be done *after* switching roots.
            target_p = self.p or self.root.firstChild() or self.root
            #g.trace(name,'target_p',target_p)
            #g.trace(name,'self.p',self.p,'self.root',self.root)
            self.p = p = self.findPositionInChapter(target_p)
            if selectEditor:
                w = self.findEditorInChapter(p)
                c.frame.body.selectEditor(w) # Switches text.

        if name == 'main' and cc.chaptersNode:
            cc.chaptersNode.contract()    
        c.hoistStack = self.hoistStack[:]

        c.selectPosition(p)
        c.redraw_after_select(p)
        g.doHook('hoist-changed',c=c)
        c.bodyWantsFocusNow()
    #@nonl
    #@-node:ekr.20070423102603.1:chapterSelectHelper
    #@+node:ekr.20070317131708:chapter.findPositionInChapter
    def findPositionInChapter (self,p1,strict=False):

        '''Return a valid position p such that p.v == v.'''

        # Do nothing if the present position is in the proper chapter.
        c = self.c ; name = self.name 

        root = g.choose(self.name=='main',c.rootPosition(),self.root)
        # g.trace('p1',p1)
        if p1 and c.positionExists(p1,root=root):
            # g.trace('using existing position',p)
            return p1

        if name == 'main':
            for p in self.c.all_unique_positions():
                if p.v == p1.v:
                    # g.trace('*** found in main chapter',p)
                    self.p = p.copy()
                    return self.p
            if strict:
                return None
            else:
                self.p = c.rootPosition()
        else:
            for p in self.root.self_and_subtree():
                # g.trace('testing',p,p1)
                if p.v == p1.v:
                    # g.trace('*** found in chapter',p)
                    self.p = p.copy()
                    return self.p
            if strict:
                return None
            else:
                self.p = self.root.copy()

        if 0:
            self.error('***** chapter: %s findPositionInChapter: lost %s' % (
                self.name,p1.h))
            g.trace(g.callers())

        return self.p.copy()
    #@-node:ekr.20070317131708:chapter.findPositionInChapter
    #@+node:ekr.20070425175522:chapter.findEditorInChapter
    def findEditorInChapter (self,p):

        '''return w, an editor displaying position p.'''

        chapter = self ; c = self.c

        w = c.frame.body.findEditorForChapter(chapter,p)
        w.leo_chapter = chapter
        w.leo_p = p and p.copy()
        return w
    #@nonl
    #@-node:ekr.20070425175522:chapter.findEditorInChapter
    #@+node:ekr.20070615065222:chapter.positionIsInChapter
    def positionIsInChapter (self,p):

        p2 = self.findPositionInChapter (p,strict=True)

        # g.trace(self.name,'returns',p2)
        return p2
    #@nonl
    #@-node:ekr.20070615065222:chapter.positionIsInChapter
    #@+node:ekr.20070529171934.1:chapter.rename (not used)
    def rename (self,newName):

        p = self.root
        s = '@chapter ' + newName
        p.setHeadString(s)
    #@-node:ekr.20070529171934.1:chapter.rename (not used)
    #@-node:ekr.20070317131205.1:chapter.select & helpers
    #@+node:ekr.20070320091806.1:chapter.unselect
    def unselect (self):

        '''Remember chapter info when a chapter is about to be unselected.'''

        c = self.c ; cc = self.cc
        self.hoistStack = c.hoistStack[:]
        self.p = c.p
        if self.trace: g.trace('chapter',self.name,'p',self.p.h)
    #@-node:ekr.20070320091806.1:chapter.unselect
    #@-others
#@nonl
#@-node:ekr.20070317085708:class chapter
#@-others
#@nonl
#@-node:ekr.20070317085508.1:@thin leoChapters.py
#@-leo
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.