This commit was manufactured by cvs2svn to create tag 'r22b2-mac'.
[python/dscho.git] / Mac / Tools / IDE / Wlists.py
bloba05b8049623c1a40391b66ca7f13198566aff85b
1 import Wbase
2 import Wkeys
3 import string
4 from Carbon import Evt, Events, Fm, Lists, Qd, Scrap, Win
5 from Carbon.List import LNew, CreateCustomList, GetListPort
6 from Carbon.Lists import kListDefUserProcType, lInitMsg, lDrawMsg, lHiliteMsg, lCloseMsg
7 from Carbon.QuickDraw import hilitetransfermode
8 from Carbon import App
9 from Carbon.Appearance import kThemeStateActive, kThemeStateInactive, kThemeStatePressed
12 class List(Wbase.SelectableWidget):
14 """Standard list widget."""
16 LDEF_ID = 0
18 def __init__(self, possize, items = None, callback = None, flags = 0, cols = 1, typingcasesens=0):
19 if items is None:
20 items = []
21 self.items = items
22 Wbase.SelectableWidget.__init__(self, possize)
23 self._selected = 0
24 self._enabled = 1
25 self._list = None
26 self._cols = cols
27 self._callback = callback
28 self._flags = flags
29 self.typingcasesens = typingcasesens
30 self.lasttyping = ""
31 self.lasttime = Evt.TickCount()
32 self.timelimit = 30
33 self.setitems(items)
34 self.drawingmode = 0
36 def open(self):
37 self.setdrawingmode(0)
38 self.createlist()
39 self.setdrawingmode(1)
41 def createlist(self):
42 self._calcbounds()
43 self.SetPort()
44 rect = self._bounds
45 rect = rect[0]+1, rect[1]+1, rect[2]-16, rect[3]-1
46 self._list = LNew(rect, (0, 0, self._cols, 0), (0, 0), self.LDEF_ID, self._parentwindow.wid,
47 0, 1, 0, 1)
48 if self.drawingmode:
49 self._list.LSetDrawingMode(0)
50 self._list.selFlags = self._flags
51 self.setitems(self.items)
52 if hasattr(self, "_sel"):
53 self.setselection(self._sel)
54 del self._sel
56 def adjust(self, oldbounds):
57 self.SetPort()
58 if self._selected:
59 self.GetWindow().InvalWindowRect(Qd.InsetRect(oldbounds, -3, -3))
60 self.GetWindow().InvalWindowRect(Qd.InsetRect(self._bounds, -3, -3))
61 else:
62 self.GetWindow().InvalWindowRect(oldbounds)
63 self.GetWindow().InvalWindowRect(self._bounds)
64 if oldbounds[:2] == self._bounds[:2]:
65 # set visRgn to empty, to prevent nasty drawing side effect of LSize()
66 Qd.RectRgn(self._parentwindow.wid.GetWindowPort().visRgn, (0, 0, 0, 0))
67 # list still has the same upper/left coordinates, use LSize
68 l, t, r, b = self._bounds
69 width = r - l - 17
70 height = b - t - 2
71 self._list.LSize(width, height)
72 # now *why* doesn't the list manager recalc the cellrect???
73 l, t, r, b = self._list.LRect((0,0))
74 cellheight = b - t
75 self._list.LCellSize((width, cellheight))
76 # reset visRgn
77 self._parentwindow.wid.CalcVis()
78 else:
79 # oh well, since the list manager doesn't have a LMove call,
80 # we have to make the list all over again...
81 sel = self.getselection()
82 topcell = self.gettopcell()
83 self._list = None
84 self.setdrawingmode(0)
85 self.createlist()
86 self.setselection(sel)
87 self.settopcell(topcell)
88 self.setdrawingmode(1)
90 def close(self):
91 self._list = None
92 self._callback = None
93 self.items = []
94 Wbase.SelectableWidget.close(self)
96 def set(self, items):
97 self.setitems(items)
99 def setitems(self, items):
100 self.items = items
101 the_list = self._list
102 if not self._parent or not self._list:
103 return
104 self.setdrawingmode(0)
105 topcell = self.gettopcell()
106 the_list.LDelRow(0, 1)
107 the_list.LAddRow(len(self.items), 0)
108 self_itemrepr = self.itemrepr
109 set_cell = the_list.LSetCell
110 for i in range(len(items)):
111 set_cell(self_itemrepr(items[i]), (0, i))
112 self.settopcell(topcell)
113 self.setdrawingmode(1)
115 def click(self, point, modifiers):
116 if not self._enabled:
117 return
118 isdoubleclick = self._list.LClick(point, modifiers)
119 if self._callback:
120 Wbase.CallbackCall(self._callback, 0, isdoubleclick)
121 return 1
123 def key(self, char, event):
124 (what, message, when, where, modifiers) = event
125 sel = self.getselection()
126 newselection = []
127 if char == Wkeys.uparrowkey:
128 if len(sel) >= 1 and min(sel) > 0:
129 newselection = [min(sel) - 1]
130 else:
131 newselection = [0]
132 elif char == Wkeys.downarrowkey:
133 if len(sel) >= 1 and max(sel) < (len(self.items) - 1):
134 newselection = [max(sel) + 1]
135 else:
136 newselection = [len(self.items) - 1]
137 else:
138 modifiers = 0
139 if (self.lasttime + self.timelimit) < Evt.TickCount():
140 self.lasttyping = ""
141 if self.typingcasesens:
142 self.lasttyping = self.lasttyping + char
143 else:
144 self.lasttyping = self.lasttyping + string.lower(char)
145 self.lasttime = Evt.TickCount()
146 i = self.findmatch(self.lasttyping)
147 newselection = [i]
148 if modifiers & Events.shiftKey and not self._list.selFlags & Lists.lOnlyOne:
149 newselection = newselection + sel
150 self.setselection(newselection)
151 self._list.LAutoScroll()
152 self.click((-1, -1), 0)
154 def findmatch(self, tag):
155 lower = string.lower
156 items = self.items
157 typingcasesens = self.typingcasesens
158 taglen = len(tag)
159 match = '\377' * 100
160 match_i = -1
161 for i in range(len(items)):
162 item = str(items[i])
163 if not typingcasesens:
164 item = lower(item)
165 if tag <= item < match:
166 match = item
167 match_i = i
168 if match_i >= 0:
169 return match_i
170 else:
171 return len(items) - 1
173 def domenu_copy(self, *args):
174 sel = self.getselection()
175 selitems = []
176 for i in sel:
177 selitems.append(str(self.items[i]))
178 text = string.join(selitems, '\r')
179 if text:
180 Scrap.ZeroScrap()
181 Scrap.PutScrap('TEXT', text)
183 def can_copy(self, *args):
184 return len(self.getselection()) <> 0
186 def domenu_selectall(self, *args):
187 self.selectall()
189 def can_selectall(self, *args):
190 return not self._list.selFlags & Lists.lOnlyOne
192 def selectall(self):
193 if not self._list.selFlags & Lists.lOnlyOne:
194 self.setselection(range(len(self.items)))
195 self._list.LAutoScroll()
196 self.click((-1, -1), 0)
198 def getselection(self):
199 if not self._parent or not self._list:
200 if hasattr(self, "_sel"):
201 return self._sel
202 return []
203 items = []
204 point = (0,0)
205 while 1:
206 ok, point = self._list.LGetSelect(1, point)
207 if not ok:
208 break
209 items.append(point[1])
210 point = point[0], point[1]+1
211 return items
213 def setselection(self, selection):
214 if not self._parent or not self._list:
215 self._sel = selection
216 return
217 set_sel = self._list.LSetSelect
218 for i in range(len(self.items)):
219 if i in selection:
220 set_sel(1, (0, i))
221 else:
222 set_sel(0, (0, i))
223 self._list.LAutoScroll()
225 def getselectedobjects(self):
226 sel = self.getselection()
227 objects = []
228 for i in sel:
229 objects.append(self.items[i])
230 return objects
232 def setselectedobjects(self, objects):
233 sel = []
234 for o in objects:
235 try:
236 sel.append(self.items.index(o))
237 except:
238 pass
239 self.setselection(sel)
241 def gettopcell(self):
242 l, t, r, b = self._bounds
243 t = t + 1
244 cl, ct, cr, cb = self._list.LRect((0, 0))
245 cellheight = cb - ct
246 return (t - ct) / cellheight
248 def settopcell(self, topcell):
249 top = self.gettopcell()
250 diff = topcell - top
251 self._list.LScroll(0, diff)
253 def draw(self, visRgn = None):
254 if self._visible:
255 if not visRgn:
256 visRgn = self._parentwindow.wid.GetWindowPort().visRgn
257 self._list.LUpdate(visRgn)
258 App.DrawThemeListBoxFrame(self._bounds, kThemeStateActive)
259 #if self._selected and self._activated:
260 # self.drawselframe(1)
262 def select(self, onoff, isclick = 0):
263 if Wbase.SelectableWidget.select(self, onoff):
264 return
265 self.SetPort()
266 state = [kThemeStateActive, kThemeStatePressed][onoff]
267 App.DrawThemeListBoxFrame(self._bounds, kThemeStateActive)
268 #self.drawselframe(onoff)
270 def activate(self, onoff):
271 self._activated = onoff
272 if self._visible:
273 self._list.LActivate(onoff)
274 #if self._selected:
275 # self.drawselframe(onoff)
277 def get(self):
278 return self.items
280 def itemrepr(self, item):
281 return str(item)[:255]
283 def __getitem__(self, index):
284 return self.items[index]
286 def __setitem__(self, index, item):
287 if self._parent and self._list:
288 self._list.LSetCell(self.itemrepr(item), (0, index))
289 self.items[index] = item
291 def __delitem__(self, index):
292 if self._parent and self._list:
293 self._list.LDelRow(1, index)
294 del self.items[index]
296 def __getslice__(self, a, b):
297 return self.items[a:b]
299 def __delslice__(self, a, b):
300 if b-a:
301 if self._parent and self._list:
302 self._list.LDelRow(b-a, a)
303 del self.items[a:b]
305 def __setslice__(self, a, b, items):
306 if self._parent and self._list:
307 l = len(items)
308 the_list = self._list
309 self.setdrawingmode(0)
310 if b-a:
311 if b > len(self.items):
312 # fix for new 1.5 "feature" where b is sys.maxint instead of len(self)...
313 # LDelRow doesn't like maxint.
314 b = len(self.items)
315 the_list.LDelRow(b-a, a)
316 the_list.LAddRow(l, a)
317 self_itemrepr = self.itemrepr
318 set_cell = the_list.LSetCell
319 for i in range(len(items)):
320 set_cell(self_itemrepr(items[i]), (0, i + a))
321 self.items[a:b] = items
322 self.setdrawingmode(1)
323 else:
324 self.items[a:b] = items
326 def __len__(self):
327 return len(self.items)
329 def append(self, item):
330 if self._parent and self._list:
331 index = len(self.items)
332 self._list.LAddRow(1, index)
333 self._list.LSetCell(self.itemrepr(item), (0, index))
334 self.items.append(item)
336 def remove(self, item):
337 index = self.items.index(item)
338 self.__delitem__(index)
340 def index(self, item):
341 return self.items.index(item)
343 def insert(self, index, item):
344 if index < 0:
345 index = 0
346 if self._parent and self._list:
347 self._list.LAddRow(1, index)
348 self._list.LSetCell(self.itemrepr(item), (0, index))
349 self.items.insert(index, item)
351 def setdrawingmode(self, onoff):
352 if onoff:
353 self.drawingmode = self.drawingmode - 1
354 if self.drawingmode == 0 and self._list is not None:
355 self._list.LSetDrawingMode(1)
356 if self._visible:
357 bounds = l, t, r, b = Qd.InsetRect(self._bounds, 1, 1)
358 cl, ct, cr, cb = self._list.LRect((0, len(self.items)-1))
359 if cb < b:
360 self.SetPort()
361 Qd.EraseRect((l, cb, cr, b))
362 self._list.LUpdate(self._parentwindow.wid.GetWindowPort().visRgn)
363 self.GetWindow().ValidWindowRect(bounds)
364 else:
365 if self.drawingmode == 0 and self._list is not None:
366 self._list.LSetDrawingMode(0)
367 self.drawingmode = self.drawingmode + 1
370 class CustomList(List):
372 """Base class for writing custom list definitions."""
374 _cellHeight = 0
376 def createlist(self):
377 self._calcbounds()
378 self.SetPort()
379 rect = self._bounds
380 rect = rect[0]+1, rect[1]+1, rect[2]-16, rect[3]-1
381 self._list = CreateCustomList(
382 rect,
383 (0, 0, 1, 0),
384 (0, self._cellHeight),
385 (kListDefUserProcType, self.listDefinitionFunc),
386 self._parentwindow.wid,
387 0, 1, 0, 1)
388 if self.drawingmode:
389 self._list.LSetDrawingMode(0)
390 self._list.selFlags = self._flags
391 self.setitems(self.items)
392 if hasattr(self, "_sel"):
393 self.setselection(self._sel)
394 del self._sel
396 def listDefinitionFunc(self, message, selected, cellRect, theCell,
397 dataOffset, dataLen, theList):
398 """The LDEF message dispatcher routine, no need to override."""
399 if message == lInitMsg:
400 self.listDefInit(theList)
401 elif message == lDrawMsg:
402 self.listDefDraw(selected, cellRect, theCell,
403 dataOffset, dataLen, theList)
404 elif message == lHiliteMsg:
405 self.listDefHighlight(selected, cellRect, theCell,
406 dataOffset, dataLen, theList)
407 elif message == lCloseMsg:
408 self.listDefClose(theList)
410 def listDefInit(self, theList):
411 pass
412 def listDefClose(self, theList):
413 pass
414 def listDefDraw(self, selected, cellRect, theCell,
415 dataOffset, dataLen, theList):
416 pass
417 def listDefHighlight(self, selected, cellRect, theCell,
418 dataOffset, dataLen, theList):
419 pass
422 class TwoLineList(CustomList):
424 _cellHeight = 28
426 def listDefDraw(self, selected, cellRect, theCell,
427 dataOffset, dataLen, theList):
428 savedPort = Qd.GetPort()
429 Qd.SetPort(GetListPort(theList))
430 savedClip = Qd.NewRgn()
431 Qd.GetClip(savedClip)
432 Qd.ClipRect(cellRect)
433 savedPenState = Qd.GetPenState()
434 Qd.PenNormal()
435 Qd.EraseRect(cellRect)
437 #draw the cell if it contains data
438 ascent, descent, leading, size, hm = Fm.FontMetrics()
439 linefeed = ascent + descent + leading
441 if dataLen:
442 left, top, right, bottom = cellRect
443 data = theList.LGetCell(dataLen, theCell)
444 lines = data.split("\r")
445 line1 = lines[0]
446 if len(lines) > 1:
447 line2 = lines[1]
448 else:
449 line2 = ""
450 Qd.MoveTo(left + 4, top + ascent)
451 Qd.DrawText(line1, 0, len(line1))
452 if line2:
453 Qd.MoveTo(left + 4, top + ascent + linefeed)
454 Qd.DrawText(line2, 0, len(line2))
455 Qd.PenPat("\x11\x11\x11\x11\x11\x11\x11\x11")
456 bottom = top + theList.cellSize[1]
457 Qd.MoveTo(left, bottom - 1)
458 Qd.LineTo(right, bottom - 1)
459 if selected:
460 self.listDefHighlight(selected, cellRect, theCell,
461 dataOffset, dataLen, theList)
462 #restore graphics environment
463 Qd.SetPort(savedPort)
464 Qd.SetClip(savedClip)
465 Qd.DisposeRgn(savedClip)
466 Qd.SetPenState(savedPenState)
468 def listDefHighlight(self, selected, cellRect, theCell,
469 dataOffset, dataLen, theList):
470 savedPort = Qd.GetPort()
471 Qd.SetPort(GetListPort(theList))
472 savedClip = Qd.NewRgn()
473 Qd.GetClip(savedClip)
474 Qd.ClipRect(cellRect)
475 savedPenState = Qd.GetPenState()
476 Qd.PenNormal()
477 Qd.PenMode(hilitetransfermode)
478 Qd.PaintRect(cellRect)
480 #restore graphics environment
481 Qd.SetPort(savedPort)
482 Qd.SetClip(savedClip)
483 Qd.DisposeRgn(savedClip)
484 Qd.SetPenState(savedPenState)
487 class ResultsWindow:
489 """Simple results window. The user cannot make this window go away completely:
490 closing it will just hide it. It will remain in the windows list. The owner of this window
491 should call the done() method to indicate it's done with it.
494 def __init__(self, possize=None, title="Results", callback=None):
495 import W
496 if possize is None:
497 possize = (500, 200)
498 self.w = W.Window(possize, title, minsize=(200, 100))
499 self.w.results = W.TwoLineList((-1, -1, 1, -14), callback=None)
500 self.w.bind("<close>", self.hide)
501 self.w.open()
502 self._done = 0
504 def done(self):
505 self._done = 1
506 if not self.w.isvisible():
507 self.w.close()
509 def hide(self):
510 if not self._done:
511 self.w.show(0)
512 return -1
514 def append(self, msg):
515 if not self.w.isvisible():
516 self.w.show(1)
517 self.w.select()
518 msg = string.replace(msg, '\n', '\r')
519 self.w.results.append(msg)
520 self.w.results.setselection([len(self.w.results)-1])
522 def __getattr__(self, attr):
523 return getattr(self.w.results, attr)
526 class MultiList(List):
528 """XXX Experimantal!!!"""
530 def setitems(self, items):
531 self.items = items
532 if not self._parent or not self._list:
533 return
534 self._list.LDelRow(0, 1)
535 self.setdrawingmode(0)
536 self._list.LAddRow(len(self.items), 0)
537 self_itemrepr = self.itemrepr
538 set_cell = self._list.LSetCell
539 for i in range(len(items)):
540 row = items[i]
541 for j in range(len(row)):
542 item = row[j]
543 set_cell(self_itemrepr(item), (j, i))
544 self.setdrawingmode(1)
546 def getselection(self):
547 if not self._parent or not self._list:
548 if hasattr(self, "_sel"):
549 return self._sel
550 return []
551 items = []
552 point = (0,0)
553 while 1:
554 ok, point = self._list.LGetSelect(1, point)
555 if not ok:
556 break
557 items.append(point[1])
558 point = point[0], point[1]+1
559 return items
561 def setselection(self, selection):
562 if not self._parent or not self._list:
563 self._sel = selection
564 return
565 set_sel = self._list.LSetSelect
566 for i in range(len(self.items)):
567 if i in selection:
568 set_sel(1, (0, i))
569 else:
570 set_sel(0, (0, i))
571 #self._list.LAutoScroll()