Package teamwork :: Package widgets :: Module MyBrowser
[hide private]
[frames] | no frames]

Source Code for Module teamwork.widgets.MyBrowser

  1  # 
  2  #  FILE: MyBrowser.py 
  3  # 
  4  #  DESCRIPTION: 
  5  #    This file provides a generic hierarchical tree browser widget. 
  6  # 
  7  #  AUTHOR:  Steve Kinneberg <skinneberg@mvista.com>, 
  8  #           MontaVista Software, Inc. <source@mvista.com> 
  9  # 
 10  #  Modified: Stacy 
 11  # 
 12  #  Copyright 2001 MontaVista Software Inc. 
 13  # 
 14  #  This program is free software; you can redistribute  it and/or modify it 
 15  #  under  the terms of  the GNU General  Public License as published by the 
 16  #  Free Software Foundation;  either version 2 of the  License, or (at your 
 17  #  option) any later version. 
 18  # 
 19  #  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED 
 20  #  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF 
 21  #  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN 
 22  #  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT, 
 23  #  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
 24  #  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF 
 25  #  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 
 26  #  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT 
 27  #  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 
 28  #  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
 29  # 
 30  #  You should have received a copy of the  GNU General Public License along 
 31  #  with this program; if not, write  to the Free Software Foundation, Inc., 
 32  #  675 Mass Ave, Cambridge, MA 02139, USA. 
 33  # 
 34   
 35   
 36  import types 
 37  import Tkinter 
 38  import Pmw 
 39   
 40   
41 -class _Branching:
42 - def __init__(self):
43 # List of branch names 44 self._nodeNames = [] 45 46 # Map from branch name to branch info 47 # branch Either _LeafNode or _BranchNode widget of the branch 48 # nodetype Either 'TreeNode' or 'LeafNode' 49 self._nodeAttrs = {}
50
51 - def addbranch(self, nval, branchName = None, **kw):
52 kw['indent'] = self['indent'] 53 return apply(self._insertnode, 54 (nval, 'tree', branchName, len(self._nodeNames), 55 self._treeRoot), 56 kw)
57
58 - def addleaf(self, nval, leafName = None, **kw):
59 return apply(self._insertnode, 60 (nval, 'leaf', leafName, len(self._nodeNames), 61 self._treeRoot), 62 kw)
63
64 - def insertbranch(self, nval, branchName = None, before = 0, **kw):
65 kw['indent'] = self['indent'] 66 return apply(self._insertnode, 67 (nval, 'tree', branchName, before, self._treeRoot), 68 kw)
69
70 - def insertleaf(self, nval, leafName = None, before = 0, **kw):
71 return apply(self._insertnode, 72 (nval, 'leaf', leafName, before, self._treeRoot), 73 kw)
74
75 - def _insertnode(self, nval, type, nodeName, before, treeRoot, **kw):
76 77 if 'selectbackground' not in kw.keys(): 78 kw['selectbackground'] = self['selectbackground'] 79 80 if 'selectforeground' not in kw.keys(): 81 kw['selectforeground'] = self['selectforeground'] 82 83 if 'background' not in kw.keys(): 84 kw['background'] = self['background'] 85 86 if 'foreground' not in kw.keys(): 87 kw['foreground'] = self['foreground'] 88 89 90 if nodeName == None: 91 nodeName = self._nodeName + ".%d" % (len(self._nodeNames) + 1) 92 93 if self._nodeAttrs.has_key(nodeName): 94 msg = 'Node "%s" already exists.' % nodeName 95 raise ValueError, msg 96 97 # Do this early to catch bad <before> spec before creating any items. 98 beforeIndex = self.index(before, 1) 99 attributes = {} 100 101 last = (beforeIndex == len(self._nodeNames)) 102 if last and len(self._nodeNames) > 0: 103 # set the previous node to not last 104 self._nodeAttrs[self._nodeNames[-1]]['branch']._setlast(0) 105 106 if(type == 'tree'): 107 node = apply(self.createcomponent, ('branch%d'%len(self._nodeNames), 108 (), None, 109 _BranchNode, 110 self._branchFrame, 111 nodeName, 112 treeRoot, 113 self, 114 last, nval, 115 ), kw) 116 attributes['nodetype'] = 'TreeNode' 117 else: 118 node = apply(self.createcomponent, ('leaf%d'%len(self._nodeNames), 119 (), None, 120 _LeafNode, 121 self._branchFrame, 122 nodeName, 123 treeRoot, 124 self, 125 last, nval, 126 ), kw) 127 attributes['nodetype'] = 'LeafNode' 128 129 if len(self._nodeNames) == beforeIndex: 130 node.pack(anchor='w') 131 else: 132 bname = self._nodeNames[beforeIndex] 133 battrs = self._nodeAttrs[bname] 134 node.pack(anchor='w', before=battrs['branch']) 135 136 attributes['branch'] = node 137 138 self._nodeAttrs[nodeName] = attributes 139 self._nodeNames.insert(beforeIndex, nodeName) 140 self._sizechange() 141 return node
142
143 - def delete(self, *nodes):
144 curSel = self._treeRoot.curselection()[0] 145 for node in nodes: 146 index = self.index(node) 147 name = self._nodeNames.pop(index) 148 dnode = self._nodeAttrs[name]['branch'] 149 del self._nodeAttrs[name] 150 if dnode == curSel: 151 self._treeRoot._unhightlightnode(dnode) 152 dnode.destroy() 153 self._sizechange()
154
155 - def destroy(self):
156 for node in len(self._nodeNames): 157 self.delete(node) 158 Pmw.MegaWidget.destroy(self)
159
160 - def index(self, index, forInsert = 0):
161 if isinstance(index, _LeafNode): 162 index = index._nodeName 163 listLength = len(self._nodeNames) 164 if type(index) == types.IntType: 165 if forInsert and index <= listLength: 166 return index 167 elif not forInsert and index < listLength: 168 return index 169 else: 170 raise ValueError, 'index "%s" is out of range' % index 171 elif type(index) == types.StringType: 172 if index in self._nodeNames: 173 return self._nodeNames.index(index) 174 raise ValueError, 'bad branch or leaf name: %s' % index 175 elif index is Pmw.END: 176 if forInsert: 177 return listLength 178 elif listLength > 0: 179 return listLength - 1 180 else: 181 raise ValueError, 'TreeNode has no branches' 182 #elif index is Pmw.SELECT: 183 # if listLength == 0: 184 # raise ValueError, 'TreeNode has no branches' 185 # return self._pageNames.index(self.getcurselection()) 186 else: 187 validValues = 'a name, a number, Pmw.END, Pmw.SELECT, or a reference to a TreeBrowser Leaf or Branch' 188 raise ValueError, \ 189 'bad index "%s": must be %s' % (index, validValues)
190 191
192 - def getnodenames(self):
193 return self._nodeNames
194
195 - def getnode(self, node):
196 nodeName = self._nodeNames[self.index(node)] 197 return self._nodeAttrs[nodeName]['branch']
198 199
200 -class _LeafNode(Pmw.MegaWidget):
201
202 - def __init__(self, parent, nodeName, treeRoot, parentnode, last = 1, nval = None, **kw):
203 colors = Pmw.Color.getdefaultpalette(parent) 204 self._nodeName = nodeName 205 self._treeRoot = treeRoot 206 self._parentNode = parentnode 207 self._nval = nval 208 self._last = last 209 210 # Define the megawidget options. 211 INITOPT = Pmw.INITOPT 212 optiondefs = ( 213 ('selectbackground', colors['selectBackground'], INITOPT), 214 ('selectforeground', colors['selectForeground'], INITOPT), 215 ('background', colors['background'], INITOPT), 216 ('foreground', colors['foreground'], INITOPT), 217 ('selectcommand', None, None), 218 ('deselectcommand', None, None), 219 ('labelpos', 'e', INITOPT), 220 ('labelmargin', 0, INITOPT), 221 ('label', None, None), 222 ) 223 self.defineoptions(kw, optiondefs) 224 225 # Initialise the base class (after defining the options). 226 Pmw.MegaWidget.__init__(self, parent) 227 228 # Create the components 229 interior = self._hull 230 231 232 labelpos = self['labelpos'] 233 234 if self['label'] == None: 235 self._labelWidget = self.createcomponent('labelwidget', 236 (), None, 237 Pmw.LabeledWidget, 238 (interior,), 239 #background = self['background'], 240 #foreground = self['foreground'], 241 ) 242 else: 243 self._labelWidget = self.createcomponent('labelwidget', 244 (), None, 245 Pmw.LabeledWidget, 246 (interior,), 247 label_background = self['background'], 248 label_foreground = self['foreground'], 249 labelpos = labelpos, 250 labelmargin = self['labelmargin'], 251 label_text = self['label'], 252 ) 253 self._labelWidget.component('label').bind('<ButtonRelease-1>', 254 self._selectevent) 255 256 self._labelWidget.grid(column = 1, row = 0, sticky = 'w') 257 258 self._labelWidget.update() 259 260 self._labelheight = self._labelWidget.winfo_height() 261 262 self._lineCanvas = self.createcomponent('linecanvas', 263 (), None, 264 Tkinter.Canvas, 265 (interior,), 266 width = self._labelheight, 267 height = self._labelheight, 268 ) 269 self._lineCanvas.grid( column = 0, row = 0, sticky = 'news') 270 self._lineCanvas.update() 271 272 cw = int(self._lineCanvas['width']) 273 ch = int(self._lineCanvas['height']) 274 275 self._lineCanvas.create_line(cw/2, ch/2, cw, ch/2, tag='hline') 276 if last: 277 self._lineCanvas.create_line(cw/2, 0, cw/2, ch/2, tag='vline') 278 else: 279 self._lineCanvas.create_line(cw/2, 0, cw/2, ch, tag='vline') 280 281 # Check keywords and initialise options. 282 self.initialiseoptions()
283 284
285 - def interior(self):
286 return self._labelWidget.interior()
287
288 - def select(self):
289 self._highlight()
290
291 - def getname(self):
292 return self._nodeName
293
294 - def getlabel(self):
295 return self['label']
296
297 - def getval(self):
298 return self._nval
299
300 - def _selectevent(self, event):
301 self._highlight()
302
303 - def _highlight(self):
304 self._treeRoot._highlightnode(self) 305 #self._subHull.configure(background = self._selectbg, relief = 'raised') 306 if self['label'] != None: 307 self._labelWidget.configure(label_background = self['selectbackground']) 308 self._labelWidget.configure(label_foreground = self['selectforeground']) 309 #self._viewButton.configure(background = self._selectbg) 310 cmd = self['selectcommand'] 311 if callable(cmd): 312 cmd(self)
313
314 - def _unhighlight(self):
315 #self._subHull.configure(background = self._bg, relief = 'flat') 316 if self['label'] != None: 317 self._labelWidget.configure(label_background = self['background']) 318 self._labelWidget.configure(label_foreground = self['foreground']) 319 #self._viewButton.configure(background = self._bg) 320 cmd = self['deselectcommand'] 321 if callable(cmd): 322 cmd(self)
323
324 - def _setlast(self, last):
325 self._last = last 326 327 cw = int(self._lineCanvas['width']) 328 ch = int(self._lineCanvas['height']) 329 330 if last: 331 self._lineCanvas.create_line(cw/2, 0, cw/2, ch/2, tag='vline') 332 else: 333 self._lineCanvas.create_line(cw/2, 0, cw/2, ch, tag='vline')
334 335
336 -class _BranchNode(_LeafNode, _Branching): #Pmw.MegaWidget):
337
338 - def __init__(self, parent, nodeName, treeRoot, parentnode, last = 1, nval = None, **kw):
339 # Define the megawidget options. 340 INITOPT = Pmw.INITOPT 341 self._nval = nval 342 optiondefs = ( 343 ('view', 'collapsed', None), 344 ('expandcommand', None, None), 345 ('collapsecommand', None, None), 346 ('indent', 0, INITOPT) 347 ) 348 self.defineoptions(kw, optiondefs) 349 350 # Initialise the base class (after defining the options). 351 apply(_LeafNode.__init__, 352 (self, parent, nodeName, treeRoot, parentnode, last, nval), 353 kw) 354 _Branching.__init__(self) 355 356 def getval(self): 357 return self._nval
358 359 360 361 # Create the components 362 interior = self._hull 363 364 # Create the expand/collapse button 365 self._viewButton = self.createcomponent('viewbutton', (), None, 366 Tkinter.Canvas, 367 (interior,), 368 background = self['background'], 369 width = self._labelheight - 4, 370 height = self._labelheight - 4, 371 borderwidth = 2, 372 relief = 'raised') 373 374 self._viewButton.grid(column = 0, row = 0, sticky='se') 375 self._viewButton.bind('<ButtonPress-1>', self._showbuttonpress) 376 self._viewButton.bind('<ButtonRelease-1>', self._toggleview) 377 378 # The label widget is already created by the base class, however 379 # we do need to make some slight modifications. 380 if self['label'] != None: 381 self._labelWidget.component('label').bind('<Double-1>', 382 self._toggleview) 383 self._labelWidget.grid(column=1, row=0, columnspan = 3, sticky='sw') 384 385 # A line canvas is already created for us, we just need to make 386 # some slight modifications 387 self._lineCanvas.delete('hline') 388 self._lineCanvas.grid_forget() 389 390 391 # Set the minsize of column 1 to control additional branch frame indentation 392 self.grid_columnconfigure(1, minsize = self['indent']) 393 394 # Create the branch frame that will contain all the branch/leaf nodes 395 self._branchFrame = self.createcomponent('frame', (), None, 396 Tkinter.Frame, (interior,), 397 #borderwidth=2, 398 #relief='ridge', 399 ) 400 self.grid_columnconfigure(2,minsize=0, weight=1) 401 #self.grid_rowconfigure(0,minsize=0) 402 403 if(self['view'] == 'expanded'): 404 Pmw.drawarrow(self._viewButton, 405 self['foreground'], 406 'down', 'arrow') 407 self._branchFrame.grid(column = 2, row = 1, sticky='nw') 408 if not self._last: 409 self._branchFrame.update() 410 bh = self._branchFrame.winfo_height() 411 self._lineCanvas.configure(height = bh) 412 self._lineCanvas.grid(column = 0, row = 1, sticky='news') 413 cw = int(self._lineCanvas['width']) 414 ch = int(self._lineCanvas['height']) 415 #self._lineCanvas.create_line(cw/2, 1, cw/2, ch, tag = 'vline') 416 self._lineCanvas.coords('vline', cw/2, 1, cw/2, ch) 417 else: 418 Pmw.drawarrow(self._viewButton, 419 self['foreground'], 420 'right', 'arrow') 421 self._viewButton.configure(relief = 'raised') 422 423 424 # Check keywords and initialise options. 425 self.initialiseoptions() 426 427 428
429 - def _showbuttonpress(self, event):
430 self._viewButton.configure(relief = 'sunken')
431
432 - def _toggleview(self, event):
433 self._viewButton.configure(relief = 'sunken') 434 self.select() 435 if(self['view'] == 'expanded'): 436 self.collapsetree() 437 else: 438 self.expandtree() 439 self._viewButton.configure(relief = 'raised')
440
441 - def expandtree(self):
442 if(self['view'] == 'collapsed'): 443 cmd = self['expandcommand'] 444 if cmd is not None: 445 cmd(self) 446 self['view'] = 'expanded' 447 Pmw.drawarrow(self._viewButton, 448 self['foreground'], 449 'down', 'arrow') 450 self._branchFrame.grid(column = 2, row = 1, sticky='nw') 451 452 if not self._last: 453 self._branchFrame.update() 454 bh = self._branchFrame.winfo_height() 455 self._lineCanvas.configure(height = bh) 456 self._lineCanvas.grid(column = 0, row = 1, sticky='news') 457 cw = int(self._lineCanvas['width']) 458 ch = int(self._lineCanvas['height']) 459 #self._lineCanvas.create_line( cw/2, 1, cw/2, ch, tag = 'vline') 460 self._lineCanvas.coords('vline', cw/2, 1, cw/2, ch) 461 self._parentNode._sizechange()
462
463 - def collapsetree(self):
464 if(self['view'] == 'expanded'): 465 cmd = self['collapsecommand'] 466 if cmd is not None: 467 cmd(self) 468 self['view'] = 'collapsed' 469 Pmw.drawarrow(self._viewButton, 470 self['foreground'], 471 'right', 'arrow') 472 self._branchFrame.grid_forget() 473 if not self._last: 474 #self._lineCanvas.delete('vline') 475 self._lineCanvas.grid_forget() 476 self._parentNode._sizechange()
477
478 - def _setlast(self, last):
479 self._last = last 480 if self['view'] == 'expanded': 481 self._branchFrame.update() 482 bh = self._branchFrame.winfo_height() 483 self._lineCanvas.configure(height = bh) 484 cw = int(self._lineCanvas['width']) 485 ch = int(self._lineCanvas['height']) 486 self._lineCanvas.delete('vline') 487 if not last: 488 self._lineCanvas.create_line(cw/2, 1, cw/2, ch, tag='vline')
489 490
491 - def _sizechange(self):
492 if not self._last and self['view'] == 'expanded': 493 self._branchFrame.update() 494 bh = self._branchFrame.winfo_height() 495 self._lineCanvas.configure(height = bh) 496 if self._lineCanvas.coords('vline')[3] < bh: 497 cw = int(self._lineCanvas['width']) 498 ch = int(self._lineCanvas['height']) 499 #self._lineCanvas.delete('vline') 500 #self._lineCanvas.create_line(cw/2, 1, cw/2, ch, tag='vline') 501 self._lineCanvas.coords('vline', cw/2, 1, cw/2, ch) 502 self._parentNode._sizechange()
503
504 -class TreeBrowser(Pmw.MegaWidget, _Branching):
505
506 - def __init__(self, nval, parent = None, nodeName = '0', **kw):
507 colors = Pmw.Color.getdefaultpalette(parent) 508 509 # Define the megawidget options. 510 INITOPT = Pmw.INITOPT 511 optiondefs = ( 512 ('indent', 0, INITOPT), 513 ('selectbackground', colors['selectBackground'], INITOPT), 514 ('selectforeground', colors['selectForeground'], INITOPT), 515 ('background', colors['background'], INITOPT), 516 ('foreground', colors['foreground'], INITOPT), 517 #('selectrelief', 'raised', INITOPT), 518 ) 519 self._nval = nval 520 self.defineoptions(kw, optiondefs) 521 522 # Initialise the base class (after defining the options). 523 Pmw.MegaWidget.__init__(self, parent) 524 _Branching.__init__(self) 525 526 527 # Create the components 528 interior = self._hull 529 530 browserFrame = self.createcomponent('frame', (), None, 531 Pmw.ScrolledFrame, 532 (interior, ), # horizflex='elastic', vertflex='elastic' 533 ) 534 browserFrame.configure(clipper_width = 75) # , frame_width = 20) 535 # browserFrame.component('hull').configure(width = 20) 536 # browserFrame.component('clipper').configure(width = 20) 537 # browserFrame.component('frame').configure(width = 20) 538 539 browserFrame.pack(expand = 1, fill='both') 540 541 self._branchFrame = browserFrame.interior() 542 543 self._highlightedNode = None 544 self._treeRoot = self 545 self._nodeName = nodeName 546 # Check keywords and initialise options. 547 self.initialiseoptions()
548
549 - def _highlightnode(self, newNode):
550 if self._highlightedNode != newNode: 551 if self._highlightedNode != None: 552 self._highlightedNode._unhighlight() 553 self._highlightedNode = newNode
554
555 - def _unhighlightnode(self):
556 if self._highlightedNode != None: 557 self._highlightedNode._unhighlight() 558 self._highlightedNode = None
559
560 - def curselection(self):
561 retVal = None 562 if self._highlightedNode != None: 563 retVal = (self._highlightedNode, 564 self._highlightedNode._nodeName, 565 self._highlightedNode['label'], 566 self._highlightedNode._nval) 567 return retVal
568
569 - def getname(self):
570 return self._nodeName
571 572 # The top-level TreeBrowser widget only shows nodes in an expanded view 573 # but still provides collapsetree() and expandtree() methods so that users 574 # don't have to special case the top-level node 575
576 - def collapsetree(self):
577 return
578
579 - def expandtree(self):
580 return
581
582 - def _sizechange(self):
583 return
584