#@+leo-ver=4-thin #@+node:ekr.20040915144649.2:@thin chapters.py __version__ = '.2' #@<< imports >> #@+node:ekr.20040915144649.3:<< imports >> import leoGlobals as g import leoPlugins from leoNodes import * import leoTkinterFrame import leoColor,leoFrame,leoNodes import leoTkinterMenu,leoTkinterTree from leoTkinterFrame import leoTkinterLog from leoTkinterFrame import leoTkinterBody import leoFileCommands import leoTkinterTree import leoGlobals import os import string import sys import time import traceback try: import Tkinter as Tk import tkFileDialog import tkFont except ImportError: Tk = g.cantImport("Tk") try: import Pmw except: Pmw = g.cantImport("Pmw" ) import zipfile import time #@nonl #@-node:ekr.20040915144649.3:<< imports >> #@nl #@<< vars >> #@+node:ekr.20040915144649.4:<< vars >> notebooks = {} frames = {} scrollbars = {} canvass = {} yscrollbars = {} iscStringIO = False twidgets = {} pbodies = {} #@nonl #@-node:ekr.20040915144649.4:<< vars >> #@nl #@+others #@+node:ekr.20040915144649.5:getSV def getSV( name, c = None ): if not c : c = g.top() notebook = notebooks[ c ] index = notebook.index( name ) page = notebook.page( index ) return page.sv #@nonl #@-node:ekr.20040915144649.5:getSV #@+node:ekr.20040915144649.6:finishCreate def finishCreate ( self, c): frame = self ; frame.c = c ; frame.trees = {} #@ << create the toplevel frame >> #@+node:ekr.20040915153428:<< create the toplevel frame >> frames[ c ] = frame gui = g.app.gui frame.top = top = Tk.Toplevel() gui.attachLeoIcon(top) top.title(frame.title) top.minsize(30,10) # In grid units. frame.top.protocol("WM_DELETE_WINDOW", frame.OnCloseLeoEvent) frame.top.bind("", frame.OnActivateLeoEvent) frame.top.bind("", frame.OnActivateLeoEvent) # Doesn't work on windows. frame.top.bind("", frame.OnDeactivateLeoEvent) # Doesn't work on windows. frame.top.bind("",frame.OnControlKeyDown) frame.top.bind("",frame.OnControlKeyUp) # Create the outer frame. self.outerFrame = outerFrame = Tk.Frame(top) self.outerFrame.pack(expand=1,fill="both") self.createIconBar() #@nonl #@-node:ekr.20040915153428:<< create the toplevel frame >> #@nl #@ << create all the subframes >> #@+node:ekr.20040915153428.1:<< create all the subframes >> # Splitter 1 is the main splitter containing splitter2 and the body pane. f1,bar1,split1Pane1,split1Pane2 = self.createLeoSplitter(outerFrame, self.splitVerticalFlag) self.f1,self.bar1 = f1,bar1 self.split1Pane1,self.split1Pane2 = split1Pane1,split1Pane2 pbody = Pmw.PanedWidget( split1Pane2 , orient = 'horizontal' ) pbody.pack( expand = 1 , fill = 'both') zpane = pbody.add( '1' ) pbodies[ c ] = pbody # Splitter 2 is the secondary splitter containing the tree and log panes. f2,bar2,split2Pane1,split2Pane2 = self.createLeoSplitter( split1Pane1, not self.splitVerticalFlag) self.f2,self.bar2 = f2,bar2 self.split2Pane1,self.split2Pane2 = split2Pane1,split2Pane2 # Create the canvas, tree, log and body. notebooks[ c ] = notebook = Pmw.NoteBook( self.split2Pane1 ) hull = notebook.component( 'hull' ) makeTabMenu( hull, notebook, c ) notebook.configure( raisecommand = lambda name, notebook = notebook : setTree( name , notebook ) ) notebook.pack( fill = 'both' , expand = 1) def nameMaker(): i = 0 while 1: if len( notebook.pagenames() ) == 0: i = 0 i += 1 yield str( i ) notebook.nameMaker = nameMaker() t, page = constructTree( frame , notebook , '1' ) frame.log = leoTkinterLog(frame,self.split2Pane2) l, r =addHeading( zpane ) frame.body = leoTkinterBody(frame,zpane) frame.body.bodyCtrl.bind( "", lambda event, body = frame.body : editorHasFocus( event, body ) ) frame.body.l =l frame.body.r =r frame.body.editorName = '1' twidgets[ frame.body.bodyCtrl ] = frame.body l.configure( textvariable = getSV( '1', c ) ) # Yes, this an "official" ivar: this is a kludge. frame.bodyCtrl = frame.body.bodyCtrl # Configure. N.B. There may be Tk bugs here that make the order significant! frame.setTabWidth(c.tab_width) frame.tree.setTreeColorsFromConfig() self.reconfigurePanes() self.body.setFontFromConfig() if 0: # No longer done automatically. # Create the status line. self.createStatusLine() self.putStatusLine("Welcome to Leo") #@nonl #@-node:ekr.20040915153428.1:<< create all the subframes >> #@nl #@ << create the first tree node >> #@+node:ekr.20040915153428.2:<< create the first tree node >> t = leoNodes.tnode() v = leoNodes.vnode(c,t) p = leoNodes.position(v,[]) v.initHeadString("NewHeadline") p.moveToRoot() c.beginUpdate() c.selectVnode(p) c.redraw() c.frame.getFocus() c.editPosition(p) c.endUpdate(False) #@nonl #@-node:ekr.20040915153428.2:<< create the first tree node >> #@nl self.menu = leoTkinterMenu.leoTkinterMenu(frame) v = c.currentVnode() if not g.doHook("menu1",c=c,v=v): frame.menu.createMenuBar(self) g.app.setLog(frame.log,"tkinterFrame.__init__") # the leoTkinterFrame containing the log g.app.windowList.append(frame) c.initVersion() c.signOnWithVersion() self.body.createBindings(frame) #@nonl #@-node:ekr.20040915144649.6:finishCreate #@+node:ekr.20040915144649.7:constructTree def constructTree( frame , notebook, name ): canvas = treeBar = tree = None if frame.canvas: canvas = frame.canvas treeBar = frame.treeBar tree = frame.tree pname = notebook.nameMaker.next() page = notebook.add( pname ) indx = notebook.index( pname ) tab = notebook.tab( indx ) makeTabMenu( tab, notebook, frame.c ) hull = notebook.component( 'hull' ) tab.bind( '' , lambda event : hull.tmenu.post( event.x_root , event.y_root ) ) x = notebook.component( pname +'-tab' ) balloon = Pmw.Balloon( x, initwait = 100 ) balloon.bind( x , '' ) sv = Tk.StringVar() sv.set( name ) page.sv = sv balloon._label.configure( textvariable = sv ) frame.canvas = canvass[ sv ] = frame.createCanvas( page ) frame.tree = frame.trees[ sv ] = leoTkinterTree.leoTkinterTree( frame.c ,frame, frame.canvas) frame.tree.setTreeColorsFromConfig() yscrollbars[ sv ] = frame.treeBar if canvas: frame.canvas = canvas frame.treeBar = treeBar else: tree = frame.tree return tree , page #@-node:ekr.20040915144649.7:constructTree #@+node:ekr.20040915144649.8:addPage def addPage( c , name = None ): vnd = c.currentVnode() frame = frames[ c ] notebook = notebooks[ c ] if name == None : name = str( len( notebook.pagenames() ) + 1 ) otree, page = constructTree( frame, notebook, name ) t = leoNodes.tnode() v = leoNodes.vnode(c,t) v.initHeadString("NewHeadline") v.moveToRoot() c.beginUpdate() c.selectVnode(v) c.frame.getFocus() c.editVnode(v) c.endUpdate(False) frame.tree= otree c.selectVnode( vnd ) return page #@-node:ekr.20040915144649.8:addPage #@+node:ekr.20040915144649.9:setTree def setTree( name , notebook ): c = g.top() if c == None: return None page = notebook.page( notebook.index( name ) ) if not hasattr( page, 'sv' ) : return None sv = page.sv frame = frames[ c ] frame.canvas = canvass[ sv ] frame.treeBar = yscrollbars[ sv ] tree = frame.trees[ sv ] frame.tree = tree frame.body.lastChapter = name frame.body.lastNode = frame.tree.currentPosition() frame.body.l.configure( textvariable = sv ) frame.body.r.configure( text = frame.body.lastNode.headString() ) c.selectVnode( tree.currentVnode() ) c.redraw() #@-node:ekr.20040915144649.9:setTree #@+node:ekr.20040915144649.10:openWithFileNamez def openWithFileNamez(fileName,old_c,enableLog=True, samewindow = True): """Create a Leo Frame for the indicated fileName if the file exists.""" # trace(fileName) assert(g.app.config) if not fileName or len(fileName) == 0: return False, None # Create a full normalized path name. # Display the file name with case intact. fileName = g.os_path_join(os.getcwd(), fileName) fileName = g.os_path_normpath(fileName) oldFileName = fileName fileName = g.os_path_normcase(fileName) # If the file is already open just bring its window to the front. list = g.app.windowList for frame in list: fn = g.os_path_normcase(frame.c.mFileName) fn = g.os_path_normpath(fn) if fileName == fn: frame.deiconify() g.app.setLog(frame.log,"openWithFileName") # g.es("This window already open") if samewindow: return True, frame fileName = oldFileName # Use the idiosyncratic file name. try: file = None iszip = False if zipfile.is_zipfile( fileName ): zf = zipfile.ZipFile( fileName ) import cStringIO file = cStringIO.StringIO() name = zf.namelist() csfiles = {} for x in name: cs = csfiles[ x ] = cStringIO.StringIO() cs.write( zf.read( x ) ) cs.seek( 0 ) zf.close() iszip = True # 11/4/03: open the file in binary mode to allow 0x1a in bodies & headlines. else: file = open(fileName,'rb') if file: if samewindow: c,frame = g.app.gui.newLeoCommanderAndFrame(fileName) else: c = old_c frame = c.frame frame.log.enable(enableLog) if not g.doHook("open1",old_c=old_c,new_c=c,fileName=fileName): g.app.setLog(frame.log,"openWithFileName") g.app.lockLog() if iszip: c.frame.tree.drag_v = True notebook = notebooks[ c ] notebook.delete( '1' ) global iscStringIO iscStringIO = True g.es( str( len( name ) ) + " Chapters To Read", color = 'blue' ) for x in name: sv = addPage( c, x ).sv frame.tree = frame.trees[ sv ] frame.treeBar = yscrollbars[ sv ] frame.canvas = canvass[ sv ] cf = csfiles[ x ] frame.c.fileCommands.open( cf, sv.get() ) g.es( "Finished Reading Chapters", color = 'blue' ) iscStringIO = False c.frame.tree.drag_v = None setTree( notebook.index( 0 ) ) else: frame.c.fileCommands.open(file,fileName) # closes file. g.app.unlockLog() frame.openDirectory = g.os_path_dirname(fileName) g.doHook("open2",old_c=old_c,new_c=frame.c,fileName=fileName) return True, frame else: g.es("can not open: " + fileName,color="red") return False, None except IOError: g.es("can not open: " + fileName, color="blue") return False, None except: if 1: print "exceptions opening:", fileName traceback.print_exc() else: g.es("exceptions opening: " + fileName,color="red") g.es_exception() return False, None #@-node:ekr.20040915144649.10:openWithFileNamez #@+node:ekr.20040915144649.11:getLeoFile # The caller should enclose this in begin/endUpdate. def getLeoFile (self,fileName,atFileNodesFlag=True ): c = self.c c.setChanged(False) # 10/1/03: May be set when reading @file nodes. try: if not iscStringIO: self.read_only = False self.read_only = not os.access(fileName,os.W_OK) if self.read_only: g.es("read only: " + fileName,color="red") except: if 0: # testing only: access may not exist on all platforms. g.es("exception getting file access") g.es_exception() self.mFileName = c.mFileName #self.tnodesDict = {} ok = True c.loading = True # disable c.changed try: self.getXmlVersionTag() self.getXmlStylesheetTag() self.getTag("") self.getLeoHeader() self.getGlobals() self.getPrefs() self.getFindPanelSettings() # Causes window to appear. c.frame.resizePanesToRatio(c.frame.ratio,c.frame.secondary_ratio) g.es("reading: " + fileName) self.getVnodes() self.getTnodes() self.getCloneWindows() self.getTag("") except BadLeoFile, message: # All other exceptions are Leo bugs. g.es_exception() alert(self.mFileName + " is not a valid Leo file: " + `message`) ok = False c.frame.tree.redraw_now(scroll=False) if ok and atFileNodesFlag: c.atFileCommands.readAll(c.rootVnode(),partialFlag=False) if not c.currentPosition(): c.setCurrentPosition(c.rootPosition()) c.selectVnode(c.setCurrentPosition(c.rootPosition())) c.loading = False # reenable c.changed c.setChanged(c.changed) # Refresh the changed marker. #self.tnodesDict = {} return ok, self.ratio #@-node:ekr.20040915144649.11:getLeoFile #@+node:ekr.20040915144649.12:write_LEO_filez def write_LEO_filez(self,fileName,outlineOnlyFlag, singleChapter = False): c = self.c ; config = g.app.config if not outlineOnlyFlag: try: pagenames = notebooks[ c ].pagenames() at = c.atFileCommands if len( pagenames ) > 1 and not singleChapter: otree = c.frame.tree for z in pagenames: sv = getSV( z ) c.frame.tree = c.frame.trees[ sv ] at.writeAll() c.frame.tree = otree # Leo2: write all @file nodes and set orphan bits. else: at.writeAll() except: es_error("exception writing derived files") g.es_exception() return False # 1/29/03: self.read_only is not valid for Save As and Save To commands. if g.os_path_exists(fileName): try: if not os.access(fileName,os.W_OK): self.writeError("can not create: read only: " + self.targetFileName) return False except: pass # os.access() may not exist on all platforms. try: # rename fileName to fileName.bak if fileName exists. if g.os_path_exists(fileName): try: backupName = g.os_path_join(g.app.loadDir,fileName) backupName = fileName + ".bak" if g.os_path_exists(backupName): os.unlink(backupName) # os.rename(fileName,backupName) utils_rename(fileName,backupName) except OSError: if self.read_only: g.es("read only",color="red") else: g.es("exception creating backup file: " + backupName) g.es_exception() return False except: g.es("exception creating backup file: " + backupName) g.es_exception() backupName = None return False else: backupName = None self.mFileName = fileName iszip = False if len( pagenames ) > 1 and not singleChapter: import cStringIO names = notebooks[ c ].pagenames() cnames = {} for nms in names: cnames[ nms ] = cStringIO.StringIO() self.outputFile = cStringIO.StringIO() iszip = True else: self.outputFile = open(fileName, 'wb') # 9/18/02 if not self.outputFile: g.es("can not open " + fileName) if backupName and g.os_path_exists(backupName): try: os.unlink(backupName) except OSError: if self.read_only: g.es("read only",color="red") else: g.es("exception deleting backup file:" + backupName) g.es_exception() return False except: g.es("exception deleting backup file:" + backupName) g.es_exception() return False return False # 8/6/02: Update leoConfig.txt completely here. if iszip: sname = notebooks[ c ].getcurselection() for x in names: sv = getSV( x ) c.frame.tree = c.frame.trees[ sv ] self.outputFile = cnames[ x ] performWrite( self, c, config ) self.outputFile.seek( 0 ) setTree( sname , notebooks[ c ]) else: performWrite( self, c , config ) # raise BadLeoFile # testing except: g.es("exception writing: " + fileName) g.es_exception() if self.outputFile: try: self.outputFile.close() self.outputFile = None except: g.es("exception closing: " + fileName) g.es_exception() g.es("error writing " + fileName) if fileName and g.os_path_exists(fileName): try: os.unlink(fileName) except OSError: if self.read_only: g.es("read only",color="red") else: g.es("exception deleting: " + fileName) g.es_exception() except: g.es("exception deleting: " + fileName) g.es_exception() if backupName: g.es("restoring " + fileName + " from " + backupName) try: utils_rename(backupName, fileName) except OSError: if self.read_only: g.es("read only",color="red") else: g.es("exception renaming " + backupName + " to " + fileName) g.es_exception() except: g.es("exception renaming " + backupName + " to " + fileName) g.es_exception() return False if self.outputFile: try: if iszip: zf = zipfile.ZipFile( fileName, 'w', zipfile.ZIP_DEFLATED ) for fname in names: sv = getSV( fname ) zif = zipfile.ZipInfo( sv.get() ) zif.compress_type = zipfile.ZIP_DEFLATED zf.writestr( zif ,cnames[ fname ].read() ) zf.close() else: self.outputFile.close() self.outputFile = None except: g.es("exception closing: " + fileName) g.es_exception() if backupName and g.os_path_exists(backupName): try: os.unlink(backupName) except OSError: if self.read_only: g.es("read only",color="red") else: g.es("exception deleting backup file:" + backupName) g.es_exception() return False except: g.es("exception deleting backup file:" + backupName) g.es_exception() return False return True else: # This probably will never happen because errors should raise exceptions. g.es("error writing " + fileName) if fileName and g.os_path_exists(fileName): try: os.unlink(fileName) except OSError: if self.read_only: g.es("read only",color="red") else: g.es("exception deleting: " + fileName) g.es_exception() except: g.es("exception deleting: " + fileName) g.es_exception() if backupName: g.es("restoring " + fileName + " from " + backupName) try: utils_rename(backupName, fileName) except OSError: if self.read_only: g.es("read only",color="red") else: g.es("exception renaming " + backupName + " to " + fileName) g.es_exception() except: g.es("exception renaming " + backupName + " to " + fileName) g.es_exception() return False #@-node:ekr.20040915144649.12:write_LEO_filez #@+node:ekr.20040915144649.13:performWrite def performWrite(self, c , config ): # self in this case is a self pased in by a caller, it is not an object self self.assignFileIndices() c.setIvarsFromFind() config.setConfigFindIvars(c) c.setIvarsFromPrefs() config.setCommandsIvars(c) config.update() self.putProlog() self.putHeader() self.putGlobals() self.putPrefs() self.putFindSettings() self.putVnodes() self.putTnodes() self.putPostlog() #@-node:ekr.20040915144649.13:performWrite #@+node:ekr.20040915144649.14:cloneToChapter def cloneToChapter( c , name ): notebook = notebooks[ c ] page = notebook.page( notebook.index( name ) ) tree = c.frame.trees[ page.sv ] c.beginUpdate() vnd = c.currentVnode() clo = vnd.clone( vnd ) vndm = tree.currentVnode() clo.destroyDependents() clo.unlink() clo.linkAfter(vndm) clo.createDependents() c.endUpdate() #@nonl #@-node:ekr.20040915144649.14:cloneToChapter #@+node:ekr.20040915144649.15:moveToChapter def moveToChapter( c, name ): notebook = notebooks[ c ] page = notebook.page( notebook.index( name ) ) tree = c.frame.trees[ page.sv ] c.beginUpdate() vnd = c.currentVnode() if not vnd.parent() and not vnd.back() : c.endUpdate() return None vndm = tree.currentVnode() vnd.destroyDependents() vnd.unlink() vnd.linkAfter(vndm) vnd.createDependents() c.endUpdate() #@nonl #@-node:ekr.20040915144649.15:moveToChapter #@+node:ekr.20040915144649.16:copyToChapter def copyToChapter( c, name ): notebook = notebooks[ c ] page = notebook.page( notebook.index( name ) ) tree = c.frame.trees[ page.sv ] c.beginUpdate() vnd = c.currentVnode() mvnd = tree.currentVnode() mvnd.insertAfter( tnode( vnd.bodyString(), vnd.headString() ) ) c.endUpdate() #@nonl #@-node:ekr.20040915144649.16:copyToChapter #@+node:ekr.20040915145407:os_path_dirname def os_path_dirname(path,encoding=None): """Normalize the path and convert it to an absolute path.""" if iscStringIO: c = g.top() return os.path.dirname( c.mFileName ) else: path = g.toUnicodeFileEncoding(path,encoding) path = os.path.dirname(path) path = g.toUnicodeFileEncoding(path,encoding) return path #@nonl #@-node:ekr.20040915145407:os_path_dirname #@+node:ekr.20040915145407.1:editorHasFocus def editorHasFocus( event , body ): c = body.c ; notebook = notebooks[ c ] if not hasattr( body, 'lastNode' ): body.lastNode = c.currentPosition() body.lastChapter = notebook.getcurselection() body.frame.body = body body.frame.bodyCtrl = body.bodyCtrl txt = body.lastNode.bodyString() if body.lastChapter != notebook.getcurselection(): notebook.selectpage( body.lastChapter ) if body.lastNode != c.currentPosition(): body.frame.tree.select( body.lastNode ) ip = body.lastNode.t.insertSpot body.deleteAllText() body.insertAtEnd( txt ) if ip : body.setInsertionPoint( ip ) body.colorizer.colorize( body.lastNode ) #@-node:ekr.20040915145407.1:editorHasFocus #@+node:ekr.20040915145407.2:newEditor def newEditor( c ): frame = frames[ c ] pbody = pbodies[ c ] name = str( len( pbody.panes() ) + 1 ) zpane = pbody.add( name ) panes = pbody.panes() i = 1.0 / len( panes ) for z in pbody.panes(): pbody.configurepane( z , size = i ) pbody.updatelayout() l , r = addHeading( zpane ) af = leoTkinterBody( frame, zpane ) af.l = l af.r = r af.editorName = name twidgets[ af.bodyCtrl ] = af af.bodyCtrl.bind( "", lambda event, body = af : editorHasFocus( event, body ) ) af.setFontFromConfig() af.createBindings( frame ) af.bodyCtrl.focus_set() cname = notebooks[ c ].getcurselection() af.l.configure( textvariable = getSV(cname , c ) ) af.r.configure( text = c.currentVnode().headString() ) #@nonl #@-node:ekr.20040915145407.2:newEditor #@+node:ekr.20040915145407.3:removeEditor def removeEditor( c ): pbody = pbodies[ c ] if len( pbody.panes() ) == 1: return None body = c.frame.body pbody.delete( body.editorName ) pbody.updatelayout() #@-node:ekr.20040915145407.3:removeEditor #@+node:ekr.20040915145407.4:conversionToSimple def conversionToSimple( c ): notebook = notebooks[ c ] vnd = c.rootVnode() while 1: n = vnd.next() if n == None: break else: vnd = n pagenames = notebook.pagenames() current = notebook.getcurselection() pagenames.remove( current ) c.beginUpdate() for z in pagenames: index = notebook.index( z ) page = notebook.page( index ) tree = c.frame.trees[ page.sv ] rvNode = tree.rootVnode() while 1: nxt = rvNode.next() rvNode.moveAfter( vnd ) if nxt: rvNode = nxt else: vnd = rvNode break notebook.delete( z ) c.endUpdate() #@-node:ekr.20040915145407.4:conversionToSimple #@+node:ekr.20040915145407.5:conversionToChapters def conversionToChapters( c ): notebook = notebooks[ c ] vnd = c.rootVnode() while 1: nxt = vnd.next() if nxt: makeNodeIntoChapter(c , nxt ) else: break #@-node:ekr.20040915145407.5:conversionToChapters #@+node:ekr.20040915145407.6:makeNodeIntoChapter def makeNodeIntoChapter( c, vnd = None ): if vnd == None: vnd = c.currentVnode() page = addPage( c ) tree = c.frame.trees[ page.sv ] otree = c.frame.tree c.beginUpdate() c.frame.tree = tree root = tree.rootVnode() vnd.moveAfter( root ) tree.setRootVnode( vnd ) c.frame.tree = otree c.endUpdate() #@nonl #@-node:ekr.20040915145407.6:makeNodeIntoChapter #@+node:ekr.20040915145407.7:openz def openz(self,file,fileName): c = self.c ; frame = c.frame # Read the entire file into the buffer isZip = False if zipfile.is_zipfile( fileName ): isZip = True leoGlobals.openWithFileName( fileName, c , samewindow = False) else: self.fileBuffer = file.read() self.fileIndex = 0 file.close() dir = g.os_path_dirname(fileName) if len(dir) > 0: c.openDirectory = dir self.topVnode = None c.beginUpdate() if not isZip: ok, ratio = self.getLeoFile(fileName,atFileNodesFlag=True) c.endUpdate() # delete the file buffer self.fileBuffer = "" if isZip: return True return ok #@nonl #@-node:ekr.20040915145407.7:openz #@+node:ekr.20040915145407.8:walkChapters def walkChapters( c = None, ignorelist = []): if c == None : c = g.top() pagenames = notebooks[ c ].pagenames() for z in pagenames: sv = getSV( z , c) tree = c.frame.trees[ sv ] v = tree.rootVnode() while v: if v not in ignorelist: yield v v = v.threadNext() #@-node:ekr.20040915145407.8:walkChapters #@+node:ekr.20040915145407.9:makeTabMenu & callbacks def makeTabMenu( widget, notebook, c ): tmenu = Tk.Menu( widget, tearoff = 0 ) widget.bind( '' , lambda event : tmenu.post( event.x_root , event.y_root ) ) widget.tmenu = tmenu tmenu.add_command( command = tmenu.unpost ) tmenu.add_separator() tmenu.add_command( label = 'Add Chapter', command = lambda c = c: addPage( c ) ) rmenu = Tk.Menu( tmenu , tearoff = 0 ) #@ @+others #@+node:ekr.20040915150738:remove def remove(): rmenu.delete( 0 , Tk.END ) pn = notebook.pagenames() for z in pn: def rmz( name = z): if len( notebook.pagenames() ) == 1: return sv = getSV( name ) tree = c.frame.trees[ sv ] vnd = tree.rootVnode() cvnd = c.currentVnode() c.beginUpdate() otree = c.frame.tree c.frame.tree = tree while vnd: v = vnd nnd = vnd.next() if nnd == None: nnd = cvnd vnd = None else: vnd = nnd v.doDelete( nnd ) c.frame.tree = otree c.endUpdate() notebook.delete( name ) rmenu.add_command( label = z , command = rmz ) #@nonl #@-node:ekr.20040915150738:remove #@+node:ekr.20040915150738.1:rename def rename( rnframes = {} ): name = notebook.getcurselection() frame = notebook.page( notebook.index( name ) ) fr = frames[ g.top() ] if not rnframes.has_key( frame ): f = rnframes[ frame ] = Tk.Frame( frame ) e = Tk.Entry( f , background = 'white', textvariable = frame.sv ) b = Tk.Button( f , text = "Close" ) e.pack( side = 'left' ) b.pack( side = 'right' ) def change(): f.pack_forget() b.configure( command = change ) else: f = rnframes[ frame ] if f.winfo_viewable() : return None fr.canvas.pack_forget() f.pack( side = 'bottom' ) fr.canvas.pack( fill = 'both', expand = 1 ) #@nonl #@-node:ekr.20040915150738.1:rename #@+node:ekr.20040915150738.2:setupMenu def setupMenu( menu , command , all = False): menu.delete( 0 , Tk.END ) current = notebook.getcurselection() for z in notebook.pagenames(): if z == current and not all: continue menu.add_command( label = z , command = lambda c = c , name = z : command( c, name ) ) #@nonl #@-node:ekr.20040915150738.2:setupMenu #@-others rmenu.configure( postcommand = remove ) #men.createMenuItemsFromTable( "Outline" , table ) tmenu.add_cascade( menu = rmenu, label = "Remove Chapter" ) tmenu.add_command( label = "Add/Change Title" , command = rename ) opmenu = Tk.Menu( tmenu, tearoff = 0 ) tmenu.add_cascade( menu = opmenu , label = 'Node-Chapter Ops' ) cmenu = Tk.Menu( opmenu, tearoff = 0 ) movmenu = Tk.Menu( opmenu, tearoff = 0 ) copymenu = Tk.Menu( opmenu, tearoff = 0 ) swapmenu = Tk.Menu( opmenu, tearoff = 0 ) searchmenu = Tk.Menu( opmenu, tearoff = 0 ) opmenu.add_cascade( menu = cmenu, label = 'Clone To Chapter' ) opmenu.add_cascade( menu = movmenu, label = 'Move To Chapter' ) opmenu.add_cascade( menu = copymenu, label = 'Copy To Chapter' ) opmenu.add_cascade( menu = swapmenu, label = 'Swap With Chapter' ) opmenu.add_cascade( menu = searchmenu, label = 'Search and Clone To' ) opmenu.add_command( label ="Make Node Into Chapter", command = lambda c=c: makeNodeIntoChapter( c ) ) opmenu.add_command( label = "Add Trash Barrel", command = lambda c = c : addPage( c, "Trash" ) ) cmenu.configure( postcommand = lambda menu = cmenu, command = cloneToChapter : setupMenu( menu, command ) ) movmenu.configure( postcommand = lambda menu = movmenu, command = moveToChapter : setupMenu( menu, command ) ) copymenu.configure( postcommand = lambda menu = copymenu, command = copyToChapter : setupMenu( menu, command ) ) swapmenu.configure( postcommand = lambda menu = swapmenu, command = swapChapters : setupMenu( menu, command ) ) searchmenu.configure( postcommand = lambda menu = searchmenu, command = regexClone: setupMenu( menu, command, all = True ) ) edmenu = Tk.Menu( tmenu, tearoff = 0 ) tmenu.add_cascade( label = "Editor", menu = edmenu ) edmenu.add_command( label = "Add Editor" , command = lambda c =c : newEditor( c ) ) edmenu.add_command( label = "Remove Editor", command = lambda c = c : removeEditor( c ) ) conmenu = Tk.Menu( tmenu, tearoff = 0 ) tmenu.add_cascade( menu = conmenu, label = 'Conversion' ) conmenu.add_command( label = "Convert To Simple Outline", command = lambda c =c : conversionToSimple( c ) ) conmenu.add_command( label = "Convert Simple Outline into Chapters", command = lambda c= c : conversionToChapters( c ) ) iemenu = Tk.Menu( tmenu, tearoff = 0 ) tmenu.add_cascade( label = 'Import/Export', menu = iemenu ) iemenu.add_command( label = "Import Leo File ", command = lambda c = c: importLeoFile(c ) ) iemenu.add_command( label = "Export Chapter To Leo File", command = lambda c =c : exportLeoFile( c ) ) #@-node:ekr.20040915145407.9:makeTabMenu & callbacks #@+node:ekr.20040915145407.10:addHeading def addHeading( pane ): f = Tk.Frame( pane ) f.pack( side = 'top' ) l = Tk.Label( f ) l.pack( side = 'left' ) r = Tk.Label( f ) r.pack( side = 'right' ) return l , r #@-node:ekr.20040915145407.10:addHeading #@+node:ekr.20040915145407.11:endEditLabel def endEditLabel (self): """End editing for self.editText.""" c = self.c ; gui = g.app.gui p = self.editPosition() if p and p.edit_text(): self.setUnselectedLabelState(p) self.setEditPosition(None) if p: # Redraw ancestor headlines. self.force_redraw() # Force a redraw of joined and ancestor headlines. c.frame.body.r.configure(text = p.headString()) gui.set_focus(c,c.frame.bodyCtrl) #@nonl #@-node:ekr.20040915145407.11:endEditLabel #@+node:ekr.20040915145407.12:swapChapters def swapChapters( c, name ): tree = c.frame.tree tvnode = tree.rootVnode() notebook = notebooks[ c ] tree2 = c.frame.trees[ getSV( name, c ) ] t2vnode = tree2.rootVnode() tree2.setRootVnode( tvnode ) tree.setRootVnode( t2vnode ) c.beginUpdate() c.endUpdate() notebook = notebooks[ c ] cselection = notebook.getcurselection() tab1 = notebook.tab( cselection ) tab2 = notebook.tab( name ) tval1 = tab1.cget( 'text' ) tval2 = tab2.cget( 'text' ) tv1 = getSV( cselection, c ) tv2 = getSV( name, c ) val1 = tv1.get() val2 = tv2.get() if val2.isdigit() : tv1.set( notebook.index( cselection ) + 1 ) else: tv1.set( val2 ) if val1.isdigit() : tv2.set( notebook.index( name ) + 1 ) else: tv2.set( val1 ) #@-node:ekr.20040915145407.12:swapChapters #@+node:ekr.20040915145407.13:importLeoFile def importLeoFile( c ): name = tkFileDialog.askopenfilename() if name: page = addPage( c , name ) notebook = notebooks[ c ] notebook.selectpage( notebook.pagenames()[ - 1 ] ) openWithFileNamez(name ,c , samewindow = False ) #@-node:ekr.20040915145407.13:importLeoFile #@+node:ekr.20040915145407.14:exportLeoFile def exportLeoFile( c ): import tkFileDialog name = tkFileDialog.asksaveasfilename() if name: if not name.endswith('.leo' ): name += '.leo' c.fileCommands.write_LEO_file( name, False, singleChapter = True ) #@-node:ekr.20040915145407.14:exportLeoFile #@+node:ekr.20040915145407.15:trashDelete #@+at #@nonl # This is the main delete routine. It deletes the receiver's entire tree from # the screen. Because of the undo command we never actually delete vnodes or # tnodes. #@-at #@@c def trashDelete (self, newVnode): """Unlinks the receiver, but does not destroy it. May be undone.""" v = self ; c = v.c notebook = notebooks[ c ] pagenames = notebook.pagenames() pagenames = [ getSV( x, c ).get().upper() for x in pagenames ] name = getSV( notebook.getcurselection() , c ).get().upper() tsh = 'TRASH' if name != tsh and tsh in pagenames: index = pagenames.index( tsh ) tree = c.frame.trees[ getSV( index, c )] trashnode = tree.rootVnode() otree = c.frame.tree c.frame.tree = tree self.moveAfter( trashnode ) c.frame.tree = otree c.selectVnode( newVnode ) return self v.setDirty() # 1/30/02: mark @file nodes dirty! v.destroyDependents() v.unjoinTree() v.unlink() # Bug fix: 1/18/99: we must set the currentVnode here! c.selectVnode(newVnode) # Update all clone bits. c.initAllCloneBits() return self # We no longer need dvnodes: vnodes contain all needed info. #@-node:ekr.20040915145407.15:trashDelete #@+node:ekr.20040915145407.16:regexClone def regexClone( c , name ): if c == None: c = g.top() sv = getSV( name, c ) tree = c.frame.trees[ sv ] def cloneWalk( result , entry, widget, c = c): txt = entry.get() widget.deactivate() widget.destroy() if result == 'Cancel': return None import re regex = re.compile( txt ) rt = tree.rootVnode() stnode = tnode( '', txt ) otree = c.frame.tree c.frame.tree = tree snode = vnode( c, stnode) snode.moveAfter( rt ) ignorelist = [ snode ] it = walkChapters( c , ignorelist = ignorelist) for z in it: f = regex.match( z.bodyString() ) if f: clone = z.clone( z ) i = snode.numberOfChildren() clone.moveToNthChildOf( snode, i) ignorelist.append( clone ) c.frame.tree = otree notebook = notebooks[ c ] notebook.selectpage( name ) c.selectVnode( snode ) snode.expand() c.beginUpdate() c.endUpdate() sd = Pmw.PromptDialog( c.frame.top, title = 'Search and Clone', buttons = ( 'Search', 'Cancel' ), command =cloneWalk ) entry = sd.component( 'entry' ) sd.configure( command = lambda result, entry = entry, widget = sd: cloneWalk( result, entry, widget ) ) sd.activate( geometry = 'centerscreenalways' ) #@-node:ekr.20040915145407.16:regexClone #@+node:ekr.20040915145407.17:select def select (self,p,updateBeadList=True): if not p: return c = p.c self.frame.body.lastNode = p self.frame.body.lastChapter = notebooks[c].getcurselection() c.frame.body.r.configure( text = p.headString() ) return old_select(self,p,updateBeadList ) #@nonl #@-node:ekr.20040915145407.17:select #@-others old_select = leoTkinterTree.leoTkinterTree.select if Pmw and Tk: #@ << override Leo's core methods >> #@+node:ekr.20040915145728:<< override Leo's core methods >> leoTkinterFrame.leoTkinterFrame.finishCreate = finishCreate leoTkinterTree.leoTkinterTree.select = select leoTkinterTree.leoTkinterTree.endEditLabel = endEditLabel leoGlobals.openWithFileName = openWithFileNamez leoGlobals.os_path_dirname = os_path_dirname leoFileCommands.fileCommands.write_LEO_file = write_LEO_filez leoFileCommands.fileCommands.getLeoFile = getLeoFile leoFileCommands.fileCommands.open = openz leoNodes.vnode.doDelete = trashDelete #@nonl #@-node:ekr.20040915145728:<< override Leo's core methods >> #@nl g.plugin_signon(__name__) #@nonl #@-node:ekr.20040915144649.2:@thin chapters.py #@-leo