blob: 86c79c3f03a4bb77652011a9dc49384cf8c3f753 [file] [log] [blame]
Just van Rossumf7f93882001-11-02 19:24:41 +00001from Carbon import Evt, Events, Fm, Fonts
2from Carbon import Qd, Res, Scrap
3from Carbon import TE, TextEdit, Win
Just van Rossumf376ef02001-11-18 14:12:43 +00004from Carbon import App
5from Carbon.Appearance import kThemeStateActive, kThemeStateInactive
Just van Rossum40f9b7b1999-01-30 22:39:17 +00006import waste
7import WASTEconst
Just van Rossum40f9b7b1999-01-30 22:39:17 +00008import Wbase
9import Wkeys
10import Wcontrols
11import PyFontify
Just van Rossumf7f93882001-11-02 19:24:41 +000012import string
13from types import TupleType, StringType
Just van Rossum40f9b7b1999-01-30 22:39:17 +000014
15
16class TextBox(Wbase.Widget):
17
18 """A static text widget"""
19
Just van Rossumb7ad8211999-09-26 12:21:32 +000020 def __init__(self, possize, text="", align=TextEdit.teJustLeft,
21 fontsettings=None,
22 backgroundcolor=(0xffff, 0xffff, 0xffff)
Just van Rossum40f9b7b1999-01-30 22:39:17 +000023 ):
Just van Rossumb7ad8211999-09-26 12:21:32 +000024 if fontsettings is None:
25 import W
26 fontsettings = W.getdefaultfont()
Just van Rossum40f9b7b1999-01-30 22:39:17 +000027 Wbase.Widget.__init__(self, possize)
28 self.fontsettings = fontsettings
29 self.text = text
30 self.align = align
31 self._backgroundcolor = backgroundcolor
32
33 def draw(self, visRgn = None):
34 if self._visible:
35 (font, style, size, color) = self.fontsettings
36 fontid = GetFNum(font)
37 savestate = Qd.GetPenState()
38 Qd.TextFont(fontid)
39 Qd.TextFace(style)
40 Qd.TextSize(size)
41 Qd.RGBForeColor(color)
42 Qd.RGBBackColor(self._backgroundcolor)
43 TE.TETextBox(self.text, self._bounds, self.align)
44 Qd.RGBBackColor((0xffff, 0xffff, 0xffff))
45 Qd.SetPenState(savestate)
46
47 def get(self):
48 return self.text
49
50 def set(self, text):
51 self.text = text
52 if self._parentwindow and self._parentwindow.wid:
53 self.SetPort()
54 self.draw()
55
56
57class _ScrollWidget:
58
59 # to be overridden
Just van Rossumf376ef02001-11-18 14:12:43 +000060 def getscrollrects(self):
61 """Return (destrect, viewrect)."""
Just van Rossum40f9b7b1999-01-30 22:39:17 +000062 return None, None
63
64 # internal method
Just van Rossum40f9b7b1999-01-30 22:39:17 +000065
Just van Rossumf376ef02001-11-18 14:12:43 +000066 def updatescrollbars(self):
67 (dl, dt, dr, db), (vl, vt, vr, vb) = self.getscrollrects()
68 if self._parent._barx:
69 viewwidth = vr - vl
70 destwidth = dr - dl
71 bar = self._parent._barx
72 bar.setmax(destwidth - viewwidth)
Jack Jansenb6b6c6c2001-12-04 13:30:29 +000073
74 # MacOS 8.1 doesn't automatically disable
75 # scrollbars whose max <= min
76 bar.enable(destwidth > viewwidth)
77
Just van Rossumf376ef02001-11-18 14:12:43 +000078 bar.setviewsize(viewwidth)
79 bar.set(vl - dl)
80 if self._parent._bary:
81 viewheight = vb - vt
82 destheight = db - dt
83 bar = self._parent._bary
84 bar.setmax(destheight - viewheight)
Jack Jansenb6b6c6c2001-12-04 13:30:29 +000085
86 # MacOS 8.1 doesn't automatically disable
87 # scrollbars whose max <= min
88 bar.enable(destheight > viewheight)
89
Just van Rossumf376ef02001-11-18 14:12:43 +000090 bar.setviewsize(viewheight)
91 bar.set(vt - dt)
92
Just van Rossum40f9b7b1999-01-30 22:39:17 +000093
94UNDOLABELS = [ # Indexed by WEGetUndoInfo() value
Jack Jansen316a0102001-02-21 15:45:55 +000095 None, "", "typing", "Cut", "Paste", "Clear", "Drag", "Style",
96 "Ruler", "backspace", "delete", "transform", "resize"]
Just van Rossum40f9b7b1999-01-30 22:39:17 +000097
98
99class EditText(Wbase.SelectableWidget, _ScrollWidget):
100
101 """A text edit widget, mainly for simple entry fields."""
102
Just van Rossumb7ad8211999-09-26 12:21:32 +0000103 def __init__(self, possize, text="",
104 callback=None, inset=(3, 3),
105 fontsettings=None,
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000106 tabsettings = (32, 0),
107 readonly = 0):
Just van Rossumb7ad8211999-09-26 12:21:32 +0000108 if fontsettings is None:
109 import W
110 fontsettings = W.getdefaultfont()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000111 Wbase.SelectableWidget.__init__(self, possize)
112 self.temptext = text
113 self.ted = None
114 self.selection = None
Just van Rossumf7f93882001-11-02 19:24:41 +0000115 self.oldselection = None
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000116 self._callback = callback
117 self.changed = 0
118 self.selchanged = 0
119 self._selected = 0
120 self._enabled = 1
121 self.wrap = 1
122 self.readonly = readonly
123 self.fontsettings = fontsettings
124 self.tabsettings = tabsettings
125 if type(inset) <> TupleType:
126 self.inset = (inset, inset)
127 else:
128 self.inset = inset
129
130 def open(self):
131 if not hasattr(self._parent, "_barx"):
132 self._parent._barx = None
133 if not hasattr(self._parent, "_bary"):
134 self._parent._bary = None
135 self._calcbounds()
136 self.SetPort()
137 viewrect, destrect = self._calctextbounds()
138 flags = self._getflags()
139 self.ted = waste.WENew(destrect, viewrect, flags)
140 self.ted.WEInstallTabHooks()
141 self.ted.WESetAlignment(WASTEconst.weFlushLeft)
142 self.setfontsettings(self.fontsettings)
143 self.settabsettings(self.tabsettings)
144 self.ted.WEUseText(Res.Resource(self.temptext))
145 self.ted.WECalText()
146 if self.selection:
147 self.setselection(self.selection[0], self.selection[1])
148 self.selection = None
149 else:
150 self.selview()
151 self.temptext = None
152 self.updatescrollbars()
153 self.bind("pageup", self.scrollpageup)
154 self.bind("pagedown", self.scrollpagedown)
155 self.bind("top", self.scrolltop)
156 self.bind("bottom", self.scrollbottom)
157 self.selchanged = 0
158
159 def close(self):
160 self._parent._barx = None
161 self._parent._bary = None
162 self.ted = None
163 self.temptext = None
164 Wbase.SelectableWidget.close(self)
165
Just van Rossumf7f93882001-11-02 19:24:41 +0000166 def textchanged(self, all=0):
167 self.changed = 1
168
169 def selectionchanged(self):
170 self.selchanged = 1
171 self.oldselection = self.getselection()
172
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000173 def gettabsettings(self):
174 return self.tabsettings
175
176 def settabsettings(self, (tabsize, tabmode)):
177 self.tabsettings = (tabsize, tabmode)
178 if hasattr(self.ted, "WESetTabSize"):
179 port = self._parentwindow.wid.GetWindowPort()
180 if tabmode:
181 (font, style, size, color) = self.getfontsettings()
182 savesettings = GetPortFontSettings(port)
183 SetPortFontSettings(port, (font, style, size))
184 tabsize = Qd.StringWidth(' ' * tabsize)
185 SetPortFontSettings(port, savesettings)
186 tabsize = max(tabsize, 1)
187 self.ted.WESetTabSize(tabsize)
188 self.SetPort()
189 Qd.EraseRect(self.ted.WEGetViewRect())
190 self.ted.WEUpdate(port.visRgn)
191
192 def getfontsettings(self):
Jack Jansen5a6fdcd2001-08-25 12:15:04 +0000193 from Carbon import Res
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000194 (font, style, size, color) = self.ted.WEGetRunInfo(0)[4]
195 font = Fm.GetFontName(font)
196 return (font, style, size, color)
197
198 def setfontsettings(self, (font, style, size, color)):
199 self.SetPort()
200 if type(font) <> StringType:
201 font = Fm.GetFontName(font)
202 self.fontsettings = (font, style, size, color)
203 fontid = GetFNum(font)
204 readonly = self.ted.WEFeatureFlag(WASTEconst.weFReadOnly, -1)
205 if readonly:
206 self.ted.WEFeatureFlag(WASTEconst.weFReadOnly, 0)
207 try:
208 self.ted.WEFeatureFlag(WASTEconst.weFInhibitRecal, 1)
209 selstart, selend = self.ted.WEGetSelection()
210 self.ted.WESetSelection(0, self.ted.WEGetTextLength())
211 self.ted.WESetStyle(WASTEconst.weDoFace, (0, 0, 0, (0, 0, 0)))
212 self.ted.WESetStyle(WASTEconst.weDoFace |
213 WASTEconst.weDoColor |
214 WASTEconst.weDoFont |
215 WASTEconst.weDoSize,
216 (fontid, style, size, color))
217 self.ted.WEFeatureFlag(WASTEconst.weFInhibitRecal, 0)
218 self.ted.WECalText()
219 self.ted.WESetSelection(selstart, selend)
220 finally:
221 if readonly:
222 self.ted.WEFeatureFlag(WASTEconst.weFReadOnly, 1)
223 viewrect = self.ted.WEGetViewRect()
224 Qd.EraseRect(viewrect)
225 self.ted.WEUpdate(self._parentwindow.wid.GetWindowPort().visRgn)
Just van Rossumf7f93882001-11-02 19:24:41 +0000226 self.selectionchanged()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000227 self.updatescrollbars()
228
229 def adjust(self, oldbounds):
230 self.SetPort()
Jack Jansenb6b6c6c2001-12-04 13:30:29 +0000231 # Note: if App.DrawThemeEditTextFrame is ever used, it will be necessary
232 # to unconditionally outset the invalidated rectangles, since Appearance
233 # frames are drawn outside the bounds.
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000234 if self._selected and self._parentwindow._hasselframes:
Jack Jansen73023402001-01-23 14:58:20 +0000235 self.GetWindow().InvalWindowRect(Qd.InsetRect(oldbounds, -3, -3))
236 self.GetWindow().InvalWindowRect(Qd.InsetRect(self._bounds, -3, -3))
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000237 else:
Jack Jansen73023402001-01-23 14:58:20 +0000238 self.GetWindow().InvalWindowRect(oldbounds)
239 self.GetWindow().InvalWindowRect(self._bounds)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000240 viewrect, destrect = self._calctextbounds()
241 self.ted.WESetViewRect(viewrect)
242 self.ted.WESetDestRect(destrect)
243 if self.wrap:
244 self.ted.WECalText()
245 if self.ted.WEGetDestRect()[3] < viewrect[1]:
246 self.selview()
247 self.updatescrollbars()
248
249 # interface -----------------------
250 # selection stuff
251 def selview(self):
252 self.ted.WESelView()
253
254 def selectall(self):
255 self.ted.WESetSelection(0, self.ted.WEGetTextLength())
Just van Rossumf7f93882001-11-02 19:24:41 +0000256 self.selectionchanged()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000257 self.updatescrollbars()
258
259 def selectline(self, lineno, charoffset = 0):
260 newselstart, newselend = self.ted.WEGetLineRange(lineno)
261 # Autoscroll makes the *end* of the selection visible, which,
262 # in the case of a whole line, is the beginning of the *next* line.
263 # So sometimes it leaves our line just above the view rect.
264 # Let's fool Waste by initially selecting one char less:
265 self.ted.WESetSelection(newselstart + charoffset, newselend-1)
266 self.ted.WESetSelection(newselstart + charoffset, newselend)
Just van Rossumf7f93882001-11-02 19:24:41 +0000267 self.selectionchanged()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000268 self.updatescrollbars()
269
270 def getselection(self):
271 if self.ted:
272 return self.ted.WEGetSelection()
273 else:
274 return self.selection
275
276 def setselection(self, selstart, selend):
Just van Rossumf7f93882001-11-02 19:24:41 +0000277 self.selectionchanged()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000278 if self.ted:
279 self.ted.WESetSelection(selstart, selend)
280 self.ted.WESelView()
281 self.updatescrollbars()
282 else:
283 self.selection = selstart, selend
284
285 def offsettoline(self, offset):
286 return self.ted.WEOffsetToLine(offset)
287
288 def countlines(self):
289 return self.ted.WECountLines()
290
291 def getselectedtext(self):
292 selstart, selend = self.ted.WEGetSelection()
293 return self.ted.WEGetText().data[selstart:selend]
294
295 def expandselection(self):
296 oldselstart, oldselend = self.ted.WEGetSelection()
297 selstart, selend = min(oldselstart, oldselend), max(oldselstart, oldselend)
298 if selstart <> selend and chr(self.ted.WEGetChar(selend-1)) == '\r':
299 selend = selend - 1
Just van Rossumb10eb842001-06-21 17:51:17 +0000300 newselstart, dummy = self.ted.WEFindLine(selstart, 1)
301 dummy, newselend = self.ted.WEFindLine(selend, 1)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000302 if oldselstart <> newselstart or oldselend <> newselend:
303 self.ted.WESetSelection(newselstart, newselend)
304 self.updatescrollbars()
Just van Rossumf7f93882001-11-02 19:24:41 +0000305 self.selectionchanged()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000306
307 def insert(self, text):
308 self.ted.WEInsert(text, None, None)
Just van Rossumf7f93882001-11-02 19:24:41 +0000309 self.textchanged()
310 self.selectionchanged()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000311
312 # text
313 def set(self, text):
314 if not self.ted:
315 self.temptext = text
316 else:
317 self.ted.WEUseText(Res.Resource(text))
318 self.ted.WECalText()
319 self.SetPort()
320 viewrect, destrect = self._calctextbounds()
321 self.ted.WESetViewRect(viewrect)
322 self.ted.WESetDestRect(destrect)
323 rgn = Qd.NewRgn()
324 Qd.RectRgn(rgn, viewrect)
325 Qd.EraseRect(viewrect)
326 self.draw(rgn)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000327 self.updatescrollbars()
Just van Rossumf7f93882001-11-02 19:24:41 +0000328 self.textchanged(1)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000329
330 def get(self):
331 if not self._parent:
332 return self.temptext
333 else:
334 return self.ted.WEGetText().data
335
336 # events
337 def key(self, char, event):
338 (what, message, when, where, modifiers) = event
339 if self._enabled and not modifiers & Events.cmdKey or char in Wkeys.arrowkeys:
340 self.ted.WEKey(ord(char), modifiers)
341 if char not in Wkeys.navigationkeys:
Just van Rossumf7f93882001-11-02 19:24:41 +0000342 self.textchanged()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000343 if char not in Wkeys.scrollkeys:
Just van Rossumf7f93882001-11-02 19:24:41 +0000344 self.selectionchanged()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000345 self.updatescrollbars()
346 if self._callback:
347 Wbase.CallbackCall(self._callback, 0, char, modifiers)
348
349 def click(self, point, modifiers):
350 if not self._enabled:
351 return
352 self.ted.WEClick(point, modifiers, Evt.TickCount())
Just van Rossumf7f93882001-11-02 19:24:41 +0000353 self.selectionchanged()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000354 self.updatescrollbars()
355 return 1
356
357 def idle(self):
358 self.SetPort()
359 self.ted.WEIdle()
360
361 def rollover(self, point, onoff):
362 if onoff:
363 Wbase.SetCursor("iBeam")
364
365 def activate(self, onoff):
366 self._activated = onoff
Jack Jansenb6b6c6c2001-12-04 13:30:29 +0000367 if self._visible:
368 self.SetPort()
369
370 # DISABLED! There are too many places where it is assumed that
371 # the frame of an EditText item is 1 pixel, inside the bounds.
372 #state = [kThemeStateActive, kThemeStateInactive][not onoff]
373 #App.DrawThemeEditTextFrame(Qd.InsetRect(self._bounds, 1, 1), state)
374
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000375 if self._selected:
Jack Jansenb6b6c6c2001-12-04 13:30:29 +0000376 if onoff:
377 self.ted.WEActivate()
378 else:
379 self.ted.WEDeactivate()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000380 self.drawselframe(onoff)
381
382 def select(self, onoff, isclick = 0):
383 if Wbase.SelectableWidget.select(self, onoff):
384 return
385 self.SetPort()
386 if onoff:
387 self.ted.WEActivate()
388 if self._parentwindow._tabbable and not isclick:
389 self.selectall()
390 else:
391 self.ted.WEDeactivate()
392 self.drawselframe(onoff)
393
394 def draw(self, visRgn = None):
395 if self._visible:
396 if not visRgn:
397 visRgn = self._parentwindow.wid.GetWindowPort().visRgn
398 self.ted.WEUpdate(visRgn)
Jack Jansenb6b6c6c2001-12-04 13:30:29 +0000399
400 # DISABLED! There are too many places where it is assumed that
401 # the frame of an EditText item is 1 pixel, inside the bounds.
402 #state = [kThemeStateActive, kThemeStateInactive][not self._activated]
403 #App.DrawThemeEditTextFrame(Qd.InsetRect(self._bounds, 1, 1), state)
404 Qd.FrameRect(self._bounds)
405
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000406 if self._selected and self._activated:
407 self.drawselframe(1)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000408
409 # scrolling
410 def scrollpageup(self):
411 if self._parent._bary and self._parent._bary._enabled:
412 self.vscroll("++")
413
414 def scrollpagedown(self):
415 if self._parent._bary and self._parent._bary._enabled:
416 self.vscroll("--")
417
418 def scrolltop(self):
419 if self._parent._bary and self._parent._bary._enabled:
Just van Rossumf376ef02001-11-18 14:12:43 +0000420 self.vscroll(self._parent._bary.getmin())
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000421 if self._parent._barx and self._parent._barx._enabled:
Just van Rossumf376ef02001-11-18 14:12:43 +0000422 self.hscroll(self._parent._barx.getmin())
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000423
424 def scrollbottom(self):
425 if self._parent._bary and self._parent._bary._enabled:
Just van Rossumf376ef02001-11-18 14:12:43 +0000426 self.vscroll(self._parent._bary.getmax())
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000427
428 # menu handlers
429 def domenu_copy(self, *args):
430 selbegin, selend = self.ted.WEGetSelection()
431 if selbegin == selend:
432 return
Jack Jansenad8381a2001-12-31 14:53:05 +0000433 if hasattr(Scrap, 'ZeroScrap'):
434 Scrap.ZeroScrap()
435 else:
436 Scrap.ClearCurrentScrap()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000437 self.ted.WECopy()
438 self.updatescrollbars()
439
440 def domenu_cut(self, *args):
441 selbegin, selend = self.ted.WEGetSelection()
442 if selbegin == selend:
443 return
Jack Jansenad8381a2001-12-31 14:53:05 +0000444 if hasattr(Scrap, 'ZeroScrap'):
445 Scrap.ZeroScrap()
446 else:
447 Scrap.ClearCurrentScrap()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000448 self.ted.WECut()
449 self.updatescrollbars()
450 self.selview()
Just van Rossumf7f93882001-11-02 19:24:41 +0000451 self.textchanged()
452 self.selectionchanged()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000453 if self._callback:
454 Wbase.CallbackCall(self._callback, 0, "", None)
455
456 def domenu_paste(self, *args):
457 if not self.ted.WECanPaste():
458 return
459 self.selview()
460 self.ted.WEPaste()
461 self.updatescrollbars()
Just van Rossumf7f93882001-11-02 19:24:41 +0000462 self.textchanged()
463 self.selectionchanged()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000464 if self._callback:
465 Wbase.CallbackCall(self._callback, 0, "", None)
466
467 def domenu_clear(self, *args):
468 self.ted.WEDelete()
469 self.selview()
470 self.updatescrollbars()
Just van Rossumf7f93882001-11-02 19:24:41 +0000471 self.textchanged()
472 self.selectionchanged()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000473 if self._callback:
474 Wbase.CallbackCall(self._callback, 0, "", None)
475
476 def domenu_undo(self, *args):
477 which, redo = self.ted.WEGetUndoInfo()
478 if not which:
479 return
480 self.ted.WEUndo()
481 self.updatescrollbars()
Just van Rossumf7f93882001-11-02 19:24:41 +0000482 self.textchanged()
483 self.selectionchanged()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000484 if self._callback:
485 Wbase.CallbackCall(self._callback, 0, "", None)
486
487 def can_undo(self, menuitem):
488 #doundo = self.ted.WEFeatureFlag(WASTEconst.weFUndo, -1)
489 #print doundo
490 #if not doundo:
491 # return 0
492 which, redo = self.ted.WEGetUndoInfo()
Jack Jansen316a0102001-02-21 15:45:55 +0000493 if which < len(UNDOLABELS):
494 which = UNDOLABELS[which]
495 else:
496 which = ""
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000497 if which == None:
498 return None
499 if redo:
500 which = "Redo "+which
501 else:
502 which = "Undo "+which
503 menuitem.settext(which)
504 return 1
505
506 def domenu_selectall(self, *args):
507 self.selectall()
508
509 # private
Just van Rossumf376ef02001-11-18 14:12:43 +0000510 def getscrollrects(self):
511 return self.ted.WEGetDestRect(), self.ted.WEGetViewRect()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000512
513 def vscroll(self, value):
514 lineheight = self.ted.WEGetHeight(0, 1)
515 dr = self.ted.WEGetDestRect()
516 vr = self.ted.WEGetViewRect()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000517 viewheight = vr[3] - vr[1]
Just van Rossumf376ef02001-11-18 14:12:43 +0000518 maxdelta = vr[1] - dr[1]
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000519 mindelta = vr[3] - dr[3]
520 if value == "+":
521 delta = lineheight
522 elif value == "-":
523 delta = - lineheight
524 elif value == "++":
525 delta = viewheight - lineheight
526 elif value == "--":
527 delta = lineheight - viewheight
528 else: # in thumb
Just van Rossumf376ef02001-11-18 14:12:43 +0000529 delta = vr[1] - dr[1] - value
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000530 delta = min(maxdelta, delta)
531 delta = max(mindelta, delta)
532 self.ted.WEScroll(0, delta)
533 self.updatescrollbars()
534
535 def hscroll(self, value):
536 dr = self.ted.WEGetDestRect()
537 vr = self.ted.WEGetViewRect()
538 destwidth = dr[2] - dr[0]
539 viewwidth = vr[2] - vr[0]
540 viewoffset = maxdelta = vr[0] - dr[0]
541 mindelta = vr[2] - dr[2]
542 if value == "+":
543 delta = 32
544 elif value == "-":
545 delta = - 32
546 elif value == "++":
547 delta = 0.5 * (vr[2] - vr[0])
548 elif value == "--":
549 delta = 0.5 * (vr[0] - vr[2])
550 else: # in thumb
Just van Rossumf376ef02001-11-18 14:12:43 +0000551 delta = vr[0] - dr[0] - value
552 #cur = (32767 * viewoffset) / (destwidth - viewwidth)
553 #delta = (cur-value)*(destwidth - viewwidth)/32767
554 #if abs(delta - viewoffset) <=2:
555 # # compensate for irritating rounding error
556 # delta = viewoffset
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000557 delta = min(maxdelta, delta)
558 delta = max(mindelta, delta)
559 self.ted.WEScroll(delta, 0)
560 self.updatescrollbars()
561
562 # some internals
563 def _getflags(self):
564 flags = WASTEconst.weDoAutoScroll | WASTEconst.weDoMonoStyled
565 if self.readonly:
566 flags = flags | WASTEconst.weDoReadOnly
567 else:
568 flags = flags | WASTEconst.weDoUndo
569 return flags
570
571 def _getviewrect(self):
572 return Qd.InsetRect(self._bounds, self.inset[0], self.inset[1])
573
574 def _calctextbounds(self):
575 viewrect = l, t, r, b = self._getviewrect()
576 if self.ted:
577 dl, dt, dr, db = self.ted.WEGetDestRect()
578 vl, vt, vr, vb = self.ted.WEGetViewRect()
579 yshift = t - vt
580 if (db - dt) < (b - t):
581 destrect = viewrect
582 else:
583 destrect = l, dt + yshift, r, db + yshift
584 else:
585 destrect = viewrect
586 return viewrect, destrect
587
588
589class TextEditor(EditText):
590
591 """A text edit widget."""
592
Just van Rossumb7ad8211999-09-26 12:21:32 +0000593 def __init__(self, possize, text="", callback=None, wrap=1, inset=(4, 4),
594 fontsettings=None,
595 tabsettings=(32, 0),
596 readonly=0):
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000597 EditText.__init__(self, possize, text, callback, inset, fontsettings, tabsettings, readonly)
598 self.wrap = wrap
599
600 def _getflags(self):
601 flags = WASTEconst.weDoAutoScroll | WASTEconst.weDoMonoStyled | \
602 WASTEconst.weDoOutlineHilite
603 if self.readonly:
604 flags = flags | WASTEconst.weDoReadOnly
605 else:
606 flags = flags | WASTEconst.weDoUndo
607 return flags
608
609 def _getviewrect(self):
610 l, t, r, b = self._bounds
611 return (l + 5, t + 2, r, b - 2)
612
613 def _calctextbounds(self):
614 if self.wrap:
615 return EditText._calctextbounds(self)
616 else:
617 viewrect = l, t, r, b = self._getviewrect()
618 if self.ted:
619 dl, dt, dr, db = self.ted.WEGetDestRect()
620 vl, vt, vr, vb = self.ted.WEGetViewRect()
621 xshift = l - vl
622 yshift = t - vt
623 if (db - dt) < (b - t):
624 yshift = t - dt
625 destrect = (dl + xshift, dt + yshift, dr + xshift, db + yshift)
626 else:
627 destrect = (l, t, r + 5000, b)
628 return viewrect, destrect
629
630 def draw(self, visRgn = None):
631 if self._visible:
632 if not visRgn:
633 visRgn = self._parentwindow.wid.GetWindowPort().visRgn
634 self.ted.WEUpdate(visRgn)
635 if self._selected and self._activated:
636 self.drawselframe(1)
637
Jack Jansenb6b6c6c2001-12-04 13:30:29 +0000638 def activate(self, onoff):
639 self._activated = onoff
640 if self._visible:
641 self.SetPort()
642 # doesn't draw frame, as EditText.activate does
643 if self._selected:
644 if onoff:
645 self.ted.WEActivate()
646 else:
647 self.ted.WEDeactivate()
648 self.drawselframe(onoff)
649
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000650
Jack Jansen9ad27522001-02-21 13:54:31 +0000651import re
Just van Rossumb10eb842001-06-21 17:51:17 +0000652commentPat = re.compile("[ \t]*(#)")
653indentPat = re.compile("[ \t]*")
Just van Rossumf7f93882001-11-02 19:24:41 +0000654kStringColor = (0, 0x7fff, 0)
655kCommentColor = (0, 0, 0xb000)
Just van Rossumb10eb842001-06-21 17:51:17 +0000656
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000657
658class PyEditor(TextEditor):
659
660 """A specialized Python source edit widget"""
661
Just van Rossumb7ad8211999-09-26 12:21:32 +0000662 def __init__(self, possize, text="", callback=None, inset=(4, 4),
663 fontsettings=None,
664 tabsettings=(32, 0),
665 readonly=0,
666 debugger=None,
667 file=''):
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000668 TextEditor.__init__(self, possize, text, callback, 0, inset, fontsettings, tabsettings, readonly)
669 self.bind("cmd[", self.domenu_shiftleft)
670 self.bind("cmd]", self.domenu_shiftright)
671 self.bind("cmdshift[", self.domenu_uncomment)
672 self.bind("cmdshift]", self.domenu_comment)
Just van Rossumf7f93882001-11-02 19:24:41 +0000673 self.bind("cmdshiftd", self.alldirty)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000674 self.file = file # only for debugger reference
675 self._debugger = debugger
676 if debugger:
677 debugger.register_editor(self, self.file)
Just van Rossumf7f93882001-11-02 19:24:41 +0000678 self._dirty = (0, None)
679 self.do_fontify = 0
680
681 #def open(self):
682 # TextEditor.open(self)
683 # if self.do_fontify:
684 # self.fontify()
685 # self._dirty = (None, None)
686
687 def _getflags(self):
688 flags = (WASTEconst.weDoDrawOffscreen | WASTEconst.weDoUseTempMem |
689 WASTEconst.weDoAutoScroll | WASTEconst.weDoOutlineHilite)
690 if self.readonly:
691 flags = flags | WASTEconst.weDoReadOnly
692 else:
693 flags = flags | WASTEconst.weDoUndo
694 return flags
695
696 def textchanged(self, all=0):
697 self.changed = 1
698 if all:
699 self._dirty = (0, None)
700 return
701 oldsel = self.oldselection
702 sel = self.getselection()
703 if not sel:
704 # XXX what to do?
705 return
706 selstart, selend = sel
707 selstart, selend = min(selstart, selend), max(selstart, selend)
708 if oldsel:
709 oldselstart, oldselend = min(oldsel), max(oldsel)
710 selstart, selend = min(selstart, oldselstart), max(selend, oldselend)
711 startline = self.offsettoline(selstart)
712 endline = self.offsettoline(selend)
713 selstart, _ = self.ted.WEGetLineRange(startline)
714 _, selend = self.ted.WEGetLineRange(endline)
715 if selstart > 0:
716 selstart = selstart - 1
717 self._dirty = (selstart, selend)
718
719 def idle(self):
720 self.SetPort()
721 self.ted.WEIdle()
722 if not self.do_fontify:
723 return
724 start, end = self._dirty
725 if start is None:
726 return
727 textLength = self.ted.WEGetTextLength()
728 if end is None:
729 end = textLength
730 if start >= end:
731 self._dirty = (None, None)
732 else:
733 self.fontify(start, end)
734 self._dirty = (None, None)
735
736 def alldirty(self, *args):
737 self._dirty = (0, None)
738
739 def fontify(self, start=0, end=None):
740 #W.SetCursor('watch')
741 if self.readonly:
742 self.ted.WEFeatureFlag(WASTEconst.weFReadOnly, 0)
743 self.ted.WEFeatureFlag(WASTEconst.weFOutlineHilite, 0)
744 self.ted.WEDeactivate()
745 self.ted.WEFeatureFlag(WASTEconst.weFAutoScroll, 0)
746 self.ted.WEFeatureFlag(WASTEconst.weFUndo, 0)
747 pytext = self.get().replace("\r", "\n")
748 if end is None:
749 end = len(pytext)
750 else:
751 end = min(end, len(pytext))
752 selstart, selend = self.ted.WEGetSelection()
753 self.ted.WESetSelection(start, end)
754 self.ted.WESetStyle(WASTEconst.weDoFace | WASTEconst.weDoColor,
755 (0, 0, 12, (0, 0, 0)))
756
757 tags = PyFontify.fontify(pytext, start, end)
758 styles = {
759 'string': (WASTEconst.weDoColor, (0, 0, 0, kStringColor)),
760 'keyword': (WASTEconst.weDoFace, (0, 1, 0, (0, 0, 0))),
761 'comment': (WASTEconst.weDoFace | WASTEconst.weDoColor, (0, 0, 0, kCommentColor)),
762 'identifier': (WASTEconst.weDoColor, (0, 0, 0, (0xbfff, 0, 0)))
763 }
764 setselection = self.ted.WESetSelection
765 setstyle = self.ted.WESetStyle
766 for tag, start, end, sublist in tags:
767 setselection(start, end)
768 mode, style = styles[tag]
769 setstyle(mode, style)
770 self.ted.WESetSelection(selstart, selend)
771 self.SetPort()
772 self.ted.WEFeatureFlag(WASTEconst.weFAutoScroll, 1)
773 self.ted.WEFeatureFlag(WASTEconst.weFUndo, 1)
774 self.ted.WEActivate()
775 self.ted.WEFeatureFlag(WASTEconst.weFOutlineHilite, 1)
776 if self.readonly:
777 self.ted.WEFeatureFlag(WASTEconst.weFReadOnly, 1)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000778
779 def domenu_shiftleft(self):
780 self.expandselection()
781 selstart, selend = self.ted.WEGetSelection()
782 selstart, selend = min(selstart, selend), max(selstart, selend)
783 snippet = self.getselectedtext()
784 lines = string.split(snippet, '\r')
785 for i in range(len(lines)):
786 if lines[i][:1] == '\t':
787 lines[i] = lines[i][1:]
788 snippet = string.join(lines, '\r')
789 self.insert(snippet)
790 self.ted.WESetSelection(selstart, selstart + len(snippet))
791
792 def domenu_shiftright(self):
793 self.expandselection()
794 selstart, selend = self.ted.WEGetSelection()
795 selstart, selend = min(selstart, selend), max(selstart, selend)
796 snippet = self.getselectedtext()
797 lines = string.split(snippet, '\r')
798 for i in range(len(lines) - (not lines[-1])):
799 lines[i] = '\t' + lines[i]
800 snippet = string.join(lines, '\r')
801 self.insert(snippet)
802 self.ted.WESetSelection(selstart, selstart + len(snippet))
803
804 def domenu_uncomment(self):
805 self.expandselection()
806 selstart, selend = self.ted.WEGetSelection()
807 selstart, selend = min(selstart, selend), max(selstart, selend)
808 snippet = self.getselectedtext()
809 lines = string.split(snippet, '\r')
810 for i in range(len(lines)):
Jack Jansen9ad27522001-02-21 13:54:31 +0000811 m = commentPat.match(lines[i])
812 if m:
813 pos = m.start(1)
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000814 lines[i] = lines[i][:pos] + lines[i][pos+1:]
815 snippet = string.join(lines, '\r')
816 self.insert(snippet)
817 self.ted.WESetSelection(selstart, selstart + len(snippet))
818
819 def domenu_comment(self):
820 self.expandselection()
821 selstart, selend = self.ted.WEGetSelection()
822 selstart, selend = min(selstart, selend), max(selstart, selend)
823 snippet = self.getselectedtext()
824 lines = string.split(snippet, '\r')
825 indent = 3000 # arbitrary large number...
826 for line in lines:
827 if string.strip(line):
Jack Jansen9ad27522001-02-21 13:54:31 +0000828 m = indentPat.match(line)
829 if m:
830 indent = min(indent, m.regs[0][1])
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000831 else:
832 indent = 0
833 break
834 for i in range(len(lines) - (not lines[-1])):
835 lines[i] = lines[i][:indent] + "#" + lines[i][indent:]
836 snippet = string.join(lines, '\r')
837 self.insert(snippet)
838 self.ted.WESetSelection(selstart, selstart + len(snippet))
839
840 def setfile(self, file):
841 self.file = file
842
843 def set(self, text, file = ''):
844 oldfile = self.file
845 self.file = file
846 if self._debugger:
847 self._debugger.unregister_editor(self, oldfile)
848 self._debugger.register_editor(self, file)
849 TextEditor.set(self, text)
850
851 def close(self):
852 if self._debugger:
853 self._debugger.unregister_editor(self, self.file)
854 self._debugger = None
855 TextEditor.close(self)
856
857 def click(self, point, modifiers):
858 if not self._enabled:
859 return
860 if self._debugger and self.pt_in_breaks(point):
861 self.breakhit(point, modifiers)
862 elif self._debugger:
863 bl, bt, br, bb = self._getbreakrect()
864 Qd.EraseRect((bl, bt, br-1, bb))
865 TextEditor.click(self, point, modifiers)
866 self.drawbreakpoints()
867 else:
868 TextEditor.click(self, point, modifiers)
869 if self.ted.WEGetClickCount() >= 3:
870 # select block with our indent
871 lines = string.split(self.get(), '\r')
872 selstart, selend = self.ted.WEGetSelection()
873 lineno = self.ted.WEOffsetToLine(selstart)
874 tabs = 0
875 line = lines[lineno]
876 while line[tabs:] and line[tabs] == '\t':
877 tabs = tabs + 1
878 tabstag = '\t' * tabs
879 fromline = 0
880 toline = len(lines)
881 if tabs:
882 for i in range(lineno - 1, -1, -1):
883 line = lines[i]
884 if line[:tabs] <> tabstag:
885 fromline = i + 1
886 break
887 for i in range(lineno + 1, toline):
888 line = lines[i]
889 if line[:tabs] <> tabstag:
890 toline = i - 1
891 break
892 selstart, dummy = self.ted.WEGetLineRange(fromline)
893 dummy, selend = self.ted.WEGetLineRange(toline)
894 self.ted.WESetSelection(selstart, selend)
895
896 def breakhit(self, point, modifiers):
897 if not self.file:
898 return
899 destrect = self.ted.WEGetDestRect()
900 offset, edge = self.ted.WEGetOffset(point)
901 lineno = self.ted.WEOffsetToLine(offset) + 1
902 if point[1] <= destrect[3]:
903 self._debugger.clear_breaks_above(self.file, self.countlines())
904 self._debugger.toggle_break(self.file, lineno)
905 else:
906 self._debugger.clear_breaks_above(self.file, lineno)
907
908 def key(self, char, event):
909 (what, message, when, where, modifiers) = event
910 if modifiers & Events.cmdKey and not char in Wkeys.arrowkeys:
911 return
912 if char == '\r':
913 selstart, selend = self.ted.WEGetSelection()
914 selstart, selend = min(selstart, selend), max(selstart, selend)
915 lastchar = chr(self.ted.WEGetChar(selstart-1))
916 if lastchar <> '\r' and selstart:
917 pos, dummy = self.ted.WEFindLine(selstart, 0)
918 lineres = Res.Resource('')
919 self.ted.WECopyRange(pos, selstart, lineres, None, None)
920 line = lineres.data + '\n'
921 tabcount = self.extratabs(line)
922 self.ted.WEKey(ord('\r'), 0)
923 for i in range(tabcount):
924 self.ted.WEKey(ord('\t'), 0)
925 else:
926 self.ted.WEKey(ord('\r'), 0)
927 elif char in ')]}':
928 self.ted.WEKey(ord(char), modifiers)
929 self.balanceparens(char)
930 else:
931 self.ted.WEKey(ord(char), modifiers)
932 if char not in Wkeys.navigationkeys:
Just van Rossumf7f93882001-11-02 19:24:41 +0000933 self.textchanged()
934 self.selectionchanged()
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000935 self.updatescrollbars()
936
937 def balanceparens(self, char):
938 if char == ')':
939 target = '('
940 elif char == ']':
941 target = '['
942 elif char == '}':
943 target = '{'
944 recursionlevel = 1
945 selstart, selend = self.ted.WEGetSelection()
946 count = min(selstart, selend) - 2
947 mincount = max(0, count - 2048)
948 lastquote = None
949 while count > mincount:
950 testchar = chr(self.ted.WEGetChar(count))
951 if testchar in "\"'" and chr(self.ted.WEGetChar(count - 1)) <> '\\':
952 if lastquote == testchar:
953 recursionlevel = recursionlevel - 1
954 lastquote = None
955 elif not lastquote:
956 recursionlevel = recursionlevel + 1
957 lastquote = testchar
958 elif not lastquote and testchar == char:
959 recursionlevel = recursionlevel + 1
960 elif not lastquote and testchar == target:
961 recursionlevel = recursionlevel - 1
962 if recursionlevel == 0:
963 import time
964 autoscroll = self.ted.WEFeatureFlag(WASTEconst.weFAutoScroll, -1)
965 if autoscroll:
966 self.ted.WEFeatureFlag(WASTEconst.weFAutoScroll, 0)
967 self.ted.WESetSelection(count, count + 1)
Just van Rossumf376ef02001-11-18 14:12:43 +0000968 Qd.QDFlushPortBuffer(self._parentwindow.wid, None) # needed under OSX
Just van Rossum40f9b7b1999-01-30 22:39:17 +0000969 time.sleep(0.2)
970 self.ted.WESetSelection(selstart, selend)
971 if autoscroll:
972 self.ted.WEFeatureFlag(WASTEconst.weFAutoScroll, 1)
973 break
974 count = count - 1
975
976 def extratabs(self, line):
977 tabcount = 0
978 for c in line:
979 if c <> '\t':
980 break
981 tabcount = tabcount + 1
982 last = 0
983 cleanline = ''
984 tags = PyFontify.fontify(line)
985 # strip comments and strings
986 for tag, start, end, sublist in tags:
987 if tag in ('string', 'comment'):
988 cleanline = cleanline + line[last:start]
989 last = end
990 cleanline = cleanline + line[last:]
991 cleanline = string.strip(cleanline)
992 if cleanline and cleanline[-1] == ':':
993 tabcount = tabcount + 1
994 else:
995 # extra indent after unbalanced (, [ or {
996 for open, close in (('(', ')'), ('[', ']'), ('{', '}')):
997 count = string.count(cleanline, open)
998 if count and count > string.count(cleanline, close):
999 tabcount = tabcount + 2
1000 break
1001 return tabcount
1002
1003 def rollover(self, point, onoff):
1004 if onoff:
1005 if self._debugger and self.pt_in_breaks(point):
1006 Wbase.SetCursor("arrow")
1007 else:
1008 Wbase.SetCursor("iBeam")
1009
1010 def draw(self, visRgn = None):
1011 TextEditor.draw(self, visRgn)
1012 if self._debugger:
1013 self.drawbreakpoints()
1014
1015 def showbreakpoints(self, onoff):
1016 if (not not self._debugger) <> onoff:
1017 if onoff:
1018 if not __debug__:
1019 import W
Just van Rossumdc3c6172001-06-19 21:37:33 +00001020 raise W.AlertError, "Can't debug in \"Optimize bytecode\" mode.\r(see \"Default startup options\" in EditPythonPreferences)"
Just van Rossum40f9b7b1999-01-30 22:39:17 +00001021 import PyDebugger
1022 self._debugger = PyDebugger.getdebugger()
1023 self._debugger.register_editor(self, self.file)
1024 elif self._debugger:
1025 self._debugger.unregister_editor(self, self.file)
1026 self._debugger = None
1027 self.adjust(self._bounds)
1028
1029 def togglebreakpoints(self):
1030 self.showbreakpoints(not self._debugger)
1031
1032 def clearbreakpoints(self):
1033 if self.file:
1034 self._debugger.clear_all_file_breaks(self.file)
1035
1036 def editbreakpoints(self):
1037 if self._debugger:
1038 self._debugger.edit_breaks()
1039 self._debugger.breaksviewer.selectfile(self.file)
1040
1041 def drawbreakpoints(self, eraseall = 0):
1042 breakrect = bl, bt, br, bb = self._getbreakrect()
1043 br = br - 1
1044 self.SetPort()
1045 Qd.PenPat(Qd.qd.gray)
1046 Qd.PaintRect((br, bt, br + 1, bb))
1047 Qd.PenNormal()
1048 self._parentwindow.tempcliprect(breakrect)
1049 Qd.RGBForeColor((0xffff, 0, 0))
1050 try:
1051 lasttop = bt
1052 self_ted = self.ted
1053 Qd_PaintOval = Qd.PaintOval
1054 Qd_EraseRect = Qd.EraseRect
1055 for lineno in self._debugger.get_file_breaks(self.file):
1056 start, end = self_ted.WEGetLineRange(lineno - 1)
1057 if lineno <> self_ted.WEOffsetToLine(start) + 1:
1058 # breakpoints beyond our text: erase rest, and back out
1059 Qd_EraseRect((bl, lasttop, br, bb))
1060 break
1061 (x, y), h = self_ted.WEGetPoint(start, 0)
1062 bottom = y + h
1063 #print y, (lasttop, bottom)
1064 if bottom > lasttop:
1065 Qd_EraseRect((bl, lasttop, br, y + h * eraseall))
1066 lasttop = bottom
1067 redbullet = bl + 2, y + 3, bl + 8, y + 9
1068 Qd_PaintOval(redbullet)
1069 else:
1070 Qd_EraseRect((bl, lasttop, br, bb))
1071 Qd.RGBForeColor((0, 0, 0))
1072 finally:
1073 self._parentwindow.restoreclip()
1074
1075 def updatescrollbars(self):
1076 if self._debugger:
1077 self.drawbreakpoints(1)
1078 TextEditor.updatescrollbars(self)
1079
1080 def pt_in_breaks(self, point):
1081 return Qd.PtInRect(point, self._getbreakrect())
1082
1083 def _getbreakrect(self):
1084 if self._debugger:
1085 l, t, r, b = self._bounds
1086 return (l+1, t+1, l + 12, b-1)
1087 else:
1088 return (0, 0, 0, 0)
1089
1090 def _getviewrect(self):
1091 l, t, r, b = self._bounds
1092 if self._debugger:
1093 return (l + 17, t + 2, r, b - 2)
1094 else:
1095 return (l + 5, t + 2, r, b - 2)
1096
1097 def _calctextbounds(self):
1098 viewrect = l, t, r, b = self._getviewrect()
1099 if self.ted:
1100 dl, dt, dr, db = self.ted.WEGetDestRect()
1101 vl, vt, vr, vb = self.ted.WEGetViewRect()
1102 xshift = l - vl
1103 yshift = t - vt
1104 if (db - dt) < (b - t):
1105 yshift = t - dt
1106 destrect = (dl + xshift, dt + yshift, dr + xshift, db + yshift)
1107 else:
1108 destrect = (l, t, r + 5000, b)
1109 return viewrect, destrect
1110
1111
1112def GetFNum(fontname):
1113 """Same as Fm.GetFNum(), but maps a missing font to Monaco instead of the system font."""
1114 if fontname <> Fm.GetFontName(0):
1115 fontid = Fm.GetFNum(fontname)
1116 if fontid == 0:
1117 fontid = Fonts.monaco
1118 else:
1119 fontid = 0
1120 return fontid
1121
1122# b/w compat. Anyone using this?
1123GetFName = Fm.GetFontName
1124
1125def GetPortFontSettings(port):
1126 return Fm.GetFontName(port.txFont), port.txFace, port.txSize
1127
1128def SetPortFontSettings(port, (font, face, size)):
1129 saveport = Qd.GetPort()
1130 Qd.SetPort(port)
1131 Qd.TextFont(GetFNum(font))
1132 Qd.TextFace(face)
1133 Qd.TextSize(size)
1134 Qd.SetPort(saveport)