Coverage for C:\leo.repo\leo-editor\leo\core\leoGui.py: 71%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# -*- coding: utf-8 -*-
2#@+leo-ver=5-thin
3#@+node:ekr.20031218072017.3719: * @file leoGui.py
4#@@first
5"""
6A module containing the base gui-related classes.
8These classes hide the details of which gui is actually being used.
9Leo's core calls this class to allocate all gui objects.
11Plugins may define their own gui classes by setting g.app.gui.
12"""
13from leo.core import leoGlobals as g
14from leo.core import leoFrame
15 # for NullGui and StringTextWrapper.
16#@+others
17#@+node:ekr.20031218072017.3720: ** class LeoGui
18class LeoGui:
19 """The base class of all gui classes.
21 Subclasses are expected to override all do-nothing methods of this class.
22 """
23 #@+others
24 #@+node:ekr.20031218072017.3722: *3* LeoGui.__init__
25 def __init__(self, guiName):
26 """Ctor for the LeoGui class."""
27 self.active = None # Used only by qt_gui.
28 self.consoleOnly = True # True if g.es goes to console.
29 self.globalFindTabManager = None
30 self.globalFindTab = None
31 self.idleTimeClass = None
32 self.isNullGui = False
33 self.lastFrame = None
34 self.leoIcon = None
35 self.mGuiName = guiName
36 self.mainLoop = None
37 self.plainTextWidget = None # For SpellTabHandler class only.
38 self.root = None
39 self.script = None
40 self.splashScreen = None
41 self.utils = None
42 # To keep pylint happy.
43 self.ScriptingControllerClass = NullScriptingControllerClass
44 #
45 # Define special keys that may be overridden is subclasses.
46 self.ignoreChars = [] # Keys that should always be ignored.
47 self.FKeys = [] # The representation of F-keys.
48 self.specialChars = [] # A list of characters/keys to be handle specially.
49 #@+node:ekr.20061109212618.1: *3* LeoGui: Must be defined only in base class
50 #@+node:ekr.20110605121601.18847: *4* LeoGui.create_key_event (LeoGui)
51 def create_key_event(self, c,
52 binding=None, char=None, event=None, w=None,
53 x=None, x_root=None,
54 y=None, y_root=None,
55 ):
56 # Do not call strokeFromSetting here!
57 # For example, this would wrongly convert Ctrl-C to Ctrl-c,
58 # in effect, converting a user binding from Ctrl-Shift-C to Ctrl-C.
59 return LeoKeyEvent(c, char, event, binding, w, x, y, x_root, y_root)
60 #@+node:ekr.20031218072017.3740: *4* LeoGui.guiName
61 def guiName(self):
62 try:
63 return self.mGuiName
64 except Exception:
65 return "invalid gui name"
66 #@+node:ekr.20031218072017.2231: *4* LeoGui.setScript
67 def setScript(self, script=None, scriptFileName=None):
68 self.script = script
69 self.scriptFileName = scriptFileName
70 #@+node:ekr.20110605121601.18845: *4* LeoGui.event_generate (LeoGui)
71 def event_generate(self, c, char, shortcut, w):
72 event = self.create_key_event(c, binding=shortcut, char=char, w=w)
73 c.k.masterKeyHandler(event)
74 c.outerUpdate()
75 #@+node:ekr.20061109212618: *3* LeoGu: Must be defined in subclasses
76 #@+node:ekr.20031218072017.3725: *4* LeoGui.destroySelf
77 def destroySelf(self):
78 self.oops()
79 #@+node:ekr.20031218072017.3730: *4* LeoGui.dialogs
80 def runAboutLeoDialog(self, c, version, theCopyright, url, email):
81 """Create and run Leo's About Leo dialog."""
82 self.oops()
84 def runAskLeoIDDialog(self):
85 """Create and run a dialog to get g.app.LeoID."""
86 self.oops()
88 def runAskOkDialog(self, c, title, message=None, text="Ok"):
89 """Create and run an askOK dialog ."""
90 self.oops()
92 def runAskOkCancelNumberDialog(
93 self, c, title, message, cancelButtonText=None, okButtonText=None):
94 """Create and run askOkCancelNumber dialog ."""
95 self.oops()
97 def runAskOkCancelStringDialog(self, c, title, message, cancelButtonText=None,
98 okButtonText=None, default="", wide=False):
99 """Create and run askOkCancelString dialog ."""
100 self.oops()
102 def runAskYesNoDialog(self, c, title, message=None, yes_all=False, no_all=False):
103 """Create and run an askYesNo dialog."""
104 self.oops()
106 def runAskYesNoCancelDialog(self, c, title,
107 message=None, yesMessage="Yes", noMessage="No",
108 yesToAllMessage=None, defaultButton="Yes", cancelMessage=None,
109 ):
110 """Create and run an askYesNoCancel dialog ."""
111 self.oops()
113 def runPropertiesDialog(
114 self, title='Properties', data=None, callback=None, buttons=None):
115 """Dispay a modal TkPropertiesDialog"""
116 self.oops()
117 #@+node:ekr.20031218072017.3731: *4* LeoGui.file dialogs
118 def runOpenFileDialog(
119 self, c, title, filetypes, defaultextension, multiple=False, startpath=None):
120 """Create and run an open file dialog ."""
121 self.oops()
123 def runSaveFileDialog(self, c, title, filetypes, defaultextension):
124 """Create and run a save file dialog ."""
125 self.oops()
126 #@+node:ekr.20031218072017.3732: *4* LeoGui.panels
127 def createColorPanel(self, c):
128 """Create a color panel"""
129 self.oops()
131 def createComparePanel(self, c):
132 """Create Compare panel."""
133 self.oops()
135 def createFindTab(self, c, parentFrame):
136 """Create a find tab in the indicated frame."""
137 self.oops()
139 def createFontPanel(self, c):
140 """Create a hidden Font panel."""
141 self.oops()
143 def createLeoFrame(self, c, title):
144 """Create a new Leo frame."""
145 self.oops()
146 #@+node:ekr.20031218072017.3729: *4* LeoGui.runMainLoop
147 def runMainLoop(self):
148 """Run the gui's main loop."""
149 self.oops()
150 #@+node:ekr.20031218072017.3733: *4* LeoGui.utils
151 #@+at Subclasses are expected to subclass all of the following methods.
152 # These are all do-nothing methods: callers are expected to check for
153 # None returns.
154 # The type of commander passed to methods depends on the type of frame
155 # or dialog being created. The commander may be a Commands instance or
156 # one of its subcommanders.
157 #@+node:ekr.20031218072017.3734: *5* LeoGui.Clipboard
158 def replaceClipboardWith(self, s):
159 self.oops()
161 def getTextFromClipboard(self):
162 self.oops()
163 #@+node:ekr.20031218072017.3735: *5* LeoGui.Dialog utils
164 def attachLeoIcon(self, window):
165 """Attach the Leo icon to a window."""
166 self.oops()
168 def center_dialog(self, dialog):
169 """Center a dialog."""
170 self.oops()
172 def create_labeled_frame(
173 self, parent, caption=None, relief="groove", bd=2, padx=0, pady=0):
174 """Create a labeled frame."""
175 self.oops()
177 def get_window_info(self, window):
178 """Return the window information."""
179 self.oops()
180 #@+node:ekr.20031218072017.3737: *5* LeoGui.Focus
181 def get_focus(self, *args, **kwargs):
182 """Return the widget that has focus, or the body widget if None."""
183 self.oops()
185 def set_focus(self, commander, widget):
186 """Set the focus of the widget in the given commander if it needs to be changed."""
187 self.oops()
188 #@+node:ekr.20031218072017.3736: *5* LeoGui.Font
189 def getFontFromParams(self, family, size, slant, weight, defaultSize=12):
191 self.oops()
192 #@+node:ekr.20070212145124: *5* LeoGui.getFullVersion
193 def getFullVersion(self, c=None):
194 return 'LeoGui: dummy version'
195 #@+node:ekr.20070212070820: *5* LeoGui.makeScriptButton
196 def makeScriptButton(self, c,
197 args=None,
198 p=None,
199 script=None,
200 buttonText=None,
201 balloonText='Script Button',
202 shortcut=None,
203 bg='LightSteelBlue1',
204 define_g=True,
205 define_name='__main__',
206 silent=False,
207 ):
208 self.oops()
209 #@+node:ekr.20070228154059: *3* LeoGui: May be defined in subclasses
210 #@+node:ekr.20110613103140.16423: *4* LeoGui.dismiss_spash_screen
211 def dismiss_splash_screen(self):
212 pass # May be overridden in subclasses.
213 #@+node:tbrown.20110618095626.22068: *4* LeoGui.ensure_commander_visible
214 def ensure_commander_visible(self, c):
215 """E.g. if commanders are in tabs, make sure c's tab is visible"""
216 pass
217 #@+node:ekr.20070219084912: *4* LeoGui.finishCreate
218 def finishCreate(self):
219 # This may be overridden in subclasses.
220 pass
221 #@+node:ekr.20101028131948.5861: *4* LeoGui.killPopupMenu & postPopupMenu
222 # These definitions keep pylint happy.
224 def postPopupMenu(self, *args, **keys):
225 pass
226 #@+node:ekr.20031218072017.3741: *4* LeoGui.oops
227 def oops(self):
228 # It is not usually an error to call methods of this class.
229 # However, this message is useful when writing gui plugins.
230 if 1:
231 g.pr("LeoGui oops", g.callers(4), "should be overridden in subclass")
232 #@+node:ekr.20170612065049.1: *4* LeoGui.put_help
233 def put_help(self, c, s, short_title):
234 pass
235 #@+node:ekr.20051206103652: *4* LeoGui.widget_name (LeoGui)
236 def widget_name(self, w):
237 # First try the widget's getName method.
238 if not 'w':
239 return '<no widget>'
240 if hasattr(w, 'getName'):
241 return w.getName()
242 if hasattr(w, '_name'):
243 return w._name
244 return repr(w)
245 #@-others
246#@+node:ekr.20070228160107: ** class LeoKeyEvent
247class LeoKeyEvent:
248 """A gui-independent wrapper for gui events."""
249 #@+others
250 #@+node:ekr.20110605121601.18846: *3* LeoKeyEvent.__init__
251 def __init__(self, c, char, event, binding, w,
252 x=None, y=None, x_root=None, y_root=None
253 ):
254 """Ctor for LeoKeyEvent class."""
255 if g.isStroke(binding):
256 g.trace('***** (LeoKeyEvent) oops: already a stroke', binding, g.callers())
257 stroke = binding
258 else:
259 stroke = g.KeyStroke(binding) if binding else None
260 assert g.isStrokeOrNone(stroke), f"(LeoKeyEvent) {stroke!r} {g.callers()}"
261 if 0: # Doesn't add much.
262 if 'keys' in g.app.debug:
263 print(f"LeoKeyEvent: binding: {binding}, stroke: {stroke}, char: {char!r}")
264 self.c = c
265 self.char = char or ''
266 self.event = event # New in Leo 4.11.
267 self.stroke = stroke
268 self.w = self.widget = w
269 # Optional ivars
270 self.x = x
271 self.y = y
272 # Support for fastGotoNode plugin
273 self.x_root = x_root
274 self.y_root = y_root
275 #@+node:ekr.20140907103315.18774: *3* LeoKeyEvent.__repr__
276 def __repr__(self):
278 d = {'c': self.c.shortFileName()}
279 for ivar in ('char', 'event', 'stroke', 'w'):
280 d[ivar] = getattr(self, ivar)
281 return f"LeoKeyEvent:\n{g.objToString(d)}"
282 #@+node:ekr.20150511181702.1: *3* LeoKeyEvent.get & __getitem__
283 def get(self, attr):
284 """Compatibility with g.bunch: return an attr."""
285 return getattr(self, attr, None)
287 def __getitem__(self, attr):
288 """Compatibility with g.bunch: return an attr."""
289 return getattr(self, attr, None)
290 #@+node:ekr.20140907103315.18775: *3* LeoKeyEvent.type
291 def type(self):
292 return 'LeoKeyEvent'
293 #@-others
294#@+node:ekr.20031218072017.2223: ** class NullGui (LeoGui)
295class NullGui(LeoGui):
296 """Null gui class."""
297 #@+others
298 #@+node:ekr.20031218072017.2225: *3* NullGui.__init__
299 def __init__(self, guiName='nullGui'):
300 """ctor for the NullGui class."""
301 super().__init__(guiName)
302 self.clipboardContents = ''
303 self.focusWidget = None
304 self.script = None
305 self.lastFrame = None # The outer frame, to set g.app.log in runMainLoop.
306 self.isNullGui = True
307 self.idleTimeClass = g.NullObject
308 #@+node:ekr.20031218072017.3744: *3* NullGui.dialogs
309 def runAboutLeoDialog(self, c, version, theCopyright, url, email):
310 return self.simulateDialog("aboutLeoDialog", None)
312 def runAskLeoIDDialog(self):
313 return self.simulateDialog("leoIDDialog", None)
315 def runAskOkDialog(self, c, title, message=None, text="Ok"):
316 return self.simulateDialog("okDialog", "Ok")
318 def runAskOkCancelNumberDialog(self, c, title, message,
319 cancelButtonText=None,
320 okButtonText=None,
321 ):
322 return self.simulateDialog("numberDialog", -1)
324 def runAskOkCancelStringDialog(self, c, title, message,
325 cancelButtonText=None,
326 okButtonText=None,
327 default="",
328 wide=False,
329 ):
330 return self.simulateDialog("stringDialog", '')
332 def runCompareDialog(self, c):
333 return self.simulateDialog("compareDialog", '')
335 def runOpenFileDialog(self, c, title, filetypes, defaultextension,
336 multiple=False,
337 startpath=None,
338 ):
339 return self.simulateDialog("openFileDialog", None)
341 def runSaveFileDialog(self, c, title, filetypes, defaultextension):
342 return self.simulateDialog("saveFileDialog", None)
344 def runAskYesNoDialog(self, c, title,
345 message=None,
346 yes_all=False,
347 no_all=False,
348 ):
349 return self.simulateDialog("yesNoDialog", "no")
351 def runAskYesNoCancelDialog(self, c, title,
352 message=None,
353 yesMessage="Yes",
354 noMessage="No",
355 yesToAllMessage=None,
356 defaultButton="Yes",
357 cancelMessage=None,
358 ):
359 return self.simulateDialog("yesNoCancelDialog", "cancel")
361 def simulateDialog(self, key, defaultVal):
362 return defaultVal
363 #@+node:ekr.20170613101737.1: *3* NullGui.clipboard & focus
364 def get_focus(self, *args, **kwargs):
365 return self.focusWidget
367 def getTextFromClipboard(self):
368 return self.clipboardContents
370 def replaceClipboardWith(self, s):
371 self.clipboardContents = s
373 def set_focus(self, commander, widget):
374 self.focusWidget = widget
375 #@+node:ekr.20070301171901: *3* NullGui.do nothings
376 def alert(self, c, message):
377 pass
379 def attachLeoIcon(self, window):
380 pass
382 def destroySelf(self):
383 pass
385 def finishCreate(self):
386 pass
388 def getFontFromParams(self, family, size, slant, weight, defaultSize=12):
389 return g.app.config.defaultFont
391 def getIconImage(self, name):
392 return None
394 def getImageImage(self, name):
395 return None
397 def getTreeImage(self, c, path):
398 return None
400 def get_window_info(self, window):
401 return 600, 500, 20, 20
403 def onActivateEvent(self, *args, **keys):
404 pass
406 def onDeactivateEvent(self, *args, **keys):
407 pass
409 def set_top_geometry(self, w, h, x, y):
410 pass
411 #@+node:ekr.20070228155807: *3* NullGui.isTextWidget & isTextWrapper
412 def isTextWidget(self, w):
413 return True # Must be True for unit tests.
415 def isTextWrapper(self, w):
416 """Return True if w is a Text widget suitable for text-oriented commands."""
417 return w and getattr(w, 'supportsHighLevelInterface', None)
418 #@+node:ekr.20031218072017.2230: *3* NullGui.oops
419 def oops(self):
420 g.trace("NullGui", g.callers(4))
421 #@+node:ekr.20070301172456: *3* NullGui.panels
422 def createComparePanel(self, c):
423 """Create Compare panel."""
424 self.oops()
426 def createFindTab(self, c, parentFrame):
427 """Create a find tab in the indicated frame."""
428 pass # Now always done during startup.
430 def createLeoFrame(self, c, title):
431 """Create a null Leo Frame."""
432 gui = self
433 self.lastFrame = leoFrame.NullFrame(c, title, gui)
434 return self.lastFrame
435 #@+node:ekr.20031218072017.2229: *3* NullGui.runMainLoop
436 def runMainLoop(self):
437 """Run the null gui's main loop."""
438 if self.script:
439 frame = self.lastFrame
440 g.app.log = frame.log
441 self.lastFrame.c.executeScript(script=self.script)
442 else:
443 print('**** NullGui.runMainLoop: terminating Leo.')
444 # Getting here will terminate Leo.
445 #@-others
446#@+node:ekr.20080707150137.5: ** class NullScriptingControllerClass
447class NullScriptingControllerClass:
448 """A default, do-nothing class to be overridden by mod_scripting or other plugins.
450 This keeps pylint happy."""
452 def __init__(self, c, iconBar=None):
453 self.c = c
454 self.iconBar = iconBar
456 def createAllButtons(self):
457 pass
458#@+node:ekr.20171128093401.1: ** class StringCheckBox (leoGui.py)
459class StringCheckBox:
460 """Simulate a QCheckBox."""
462 def __init__(self, name, label=None):
463 self.label = label
464 self.name = name
465 self.value = True
467 def checkState(self):
468 return self.value
470 isChecked = checkState
472 def objectName(self):
473 return self.name
475 def setCheckState(self, value):
476 self.value = value
478 def toggle(self):
479 self.value = not self.value
480#@+node:ekr.20210221130549.1: ** class StringFindTabManager (leoGui.py) (new)
481class StringFindTabManager:
482 """A string-based FindTabManager class for unit tests."""
483 #@+others
484 #@+node:ekr.20210221130549.2: *3* sftm.ctor
485 #@@nobeautify
487 def __init__(self, c):
488 """Ctor for the FindTabManager class."""
489 self.c = c
490 self.entry_focus = None # Accessed directly from code(!)
491 # Find/change text boxes...
492 self.find_findbox = StringLineEdit('find_text')
493 self.find_replacebox = StringLineEdit('change_text')
494 # Check boxes...
495 self.check_box_ignore_case = StringCheckBox('ignore_case')
496 self.check_box_mark_changes = StringCheckBox('mark_changes')
497 self.check_box_mark_finds = StringCheckBox('mark_finds')
498 self.check_box_regexp = StringCheckBox('pattern_match')
499 self.check_box_search_body = StringCheckBox('search_body')
500 self.check_box_search_headline = StringCheckBox('search_headline')
501 self.check_box_whole_word = StringCheckBox('whole_word')
502 # Radio buttons...
503 self.radio_button_entire_outline = StringRadioButton('entire_outline')
504 self.radio_button_node_only = StringRadioButton('node_only')
505 self.radio_button_suboutline_only = StringRadioButton('suboutline_only')
506 # Init the default values.
507 self.init_widgets()
508 #@+node:ekr.20210221130549.5: *3* sftm.clear_focus & init_focus & set_entry_focus
509 def clear_focus(self):
510 pass
512 def init_focus(self):
513 pass
515 def set_entry_focus(self):
516 pass
517 #@+node:ekr.20210221130549.4: *3* sftm.get_settings
518 #@@nobeautify
520 def get_settings(self):
521 """
522 Return a g.bunch representing all widget values.
524 Similar to LeoFind.default_settings, but only for find-tab values.
525 """
526 return g.Bunch(
527 # Find/change strings...
528 find_text = self.find_findbox.text(),
529 change_text = self.find_replacebox.text(),
530 # Find options...
531 ignore_case = self.check_box_ignore_case.isChecked(),
532 mark_changes = self.check_box_mark_changes.isChecked(),
533 mark_finds = self.check_box_mark_finds.isChecked(),
534 node_only = self.radio_button_node_only.isChecked(),
535 pattern_match = self.check_box_regexp.isChecked(),
536 search_body = self.check_box_search_body.isChecked(),
537 search_headline = self.check_box_search_headline.isChecked(),
538 suboutline_only = self.radio_button_suboutline_only.isChecked(),
539 whole_word = self.check_box_whole_word.isChecked(),
540 )
541 #@+node:ekr.20210221130549.7: *3* sftm.init_widgets
542 def init_widgets(self):
543 """
544 Init widgets and ivars from c.config settings.
545 Create callbacks that always keep the LeoFind ivars up to date.
546 """
547 c, find = self.c, self.c.findCommands
548 # Find/change text boxes.
549 table1 = (
550 ('find_findbox', 'find_text', '<find pattern here>'),
551 ('find_replacebox', 'change_text', ''),
552 )
553 for widget_ivar, setting_name, default in table1:
554 w = getattr(self, widget_ivar)
555 s = c.config.getString(setting_name) or default
556 w.insert(s)
557 # Check boxes.
558 table2 = (
559 ('ignore_case', 'check_box_ignore_case'),
560 ('mark_changes', 'check_box_mark_changes'),
561 ('mark_finds', 'check_box_mark_finds'),
562 ('pattern_match', 'check_box_regexp'),
563 ('search_body', 'check_box_search_body'),
564 ('search_headline', 'check_box_search_headline'),
565 ('whole_word', 'check_box_whole_word'),
566 )
567 for setting_name, widget_ivar in table2:
568 w = getattr(self, widget_ivar)
569 val = c.config.getBool(setting_name, default=False)
570 setattr(find, setting_name, val)
571 if val != w.isChecked(): # Support leoInteg.
572 w.toggle()
573 # Radio buttons
574 table3 = (
575 ('node_only', 'node_only', 'radio_button_node_only'),
576 ('entire_outline', None, 'radio_button_entire_outline'),
577 ('suboutline_only', 'suboutline_only', 'radio_button_suboutline_only'),
578 )
579 for setting_name, ivar, widget_ivar in table3:
580 w = getattr(self, widget_ivar)
581 val = c.config.getBool(setting_name, default=False)
582 if ivar is not None:
583 assert hasattr(find, setting_name), setting_name
584 setattr(find, setting_name, val)
585 if val != w.isChecked():
586 w.toggle()
587 # Ensure one radio button is set.
588 if not find.node_only and not find.suboutline_only:
589 w = self.radio_button_entire_outline
590 if val != w.isChecked():
591 w.toggle()
592 #@+node:ekr.20210312122351.1: *3* sftm.set_body_and_headline_checkbox
593 def set_body_and_headline_checkbox(self):
594 """Return the search-body and search-headline checkboxes to their defaults."""
595 # #1840: headline-only one-shot
596 c = self.c
597 find = c.findCommands
598 if not find:
599 return
600 table = (
601 ('search_body', self.check_box_search_body),
602 ('search_headline', self.check_box_search_headline),
603 )
604 for setting_name, w in table:
605 val = c.config.getBool(setting_name, default=False)
606 if val != w.isChecked():
607 w.toggle()
608 #@+node:ekr.20210221130549.8: *3* sftm.set_radio_button
609 #@@nobeautify
611 def set_radio_button(self, name):
612 """Set the value of the radio buttons"""
613 d = {
614 'node-only': self.radio_button_node_only,
615 'entire-outline': self.radio_button_entire_outline,
616 'suboutline-only': self.radio_button_suboutline_only,
617 }
618 w = d.get(name)
619 if not w.isChecked():
620 w.toggle()
621 #@+node:ekr.20210221130549.3: *3* sftm.text getters/setters
622 def get_find_text(self):
623 s = self.find_findbox.text()
624 if s and s[-1] in ('\r', '\n'):
625 s = s[:-1]
626 return s
628 def get_change_text(self):
629 s = self.find_replacebox.text()
630 if s and s[-1] in ('\r', '\n'):
631 s = s[:-1]
632 return s
634 def set_find_text(self, s):
635 w = self.find_findbox
636 w.clear()
637 w.insert(s)
639 def set_change_text(self, s):
640 w = self.find_replacebox
641 w.clear()
642 w.insert(s)
643 #@+node:ekr.20210221130549.9: *3* sftm.toggle_checkbox
644 #@@nobeautify
646 def toggle_checkbox(self, checkbox_name):
647 """Toggle the value of the checkbox whose name is given."""
648 d = {
649 'ignore_case': self.check_box_ignore_case,
650 'mark_changes': self.check_box_mark_changes,
651 'mark_finds': self.check_box_mark_finds,
652 'pattern_match': self.check_box_regexp,
653 'search_body': self.check_box_search_body,
654 'search_headline': self.check_box_search_headline,
655 'whole_word': self.check_box_whole_word,
656 }
657 w = d.get(checkbox_name)
658 w.toggle()
659 #@-others
660#@+node:ekr.20170613095422.1: ** class StringGui (LeoGui)
661class StringGui(LeoGui):
662 """
663 A class representing all on-screen objects using subclasses of the
664 leoFrame.StringTextWrapper class.
665 """
666 #@+others
667 #@+node:ekr.20170613095422.7: *3* StringGui.oops
668 def oops(self):
670 g.trace("StringGui", g.callers(4))
671 #@+node:ekr.20170613114120.1: *3* StringGui.runMainLoop
672 def runMainLoop(self):
673 self.oops()
674 #@-others
675#@+node:ekr.20171128093503.1: ** class StringLineEdit (leoGui)
676class StringLineEdit:
677 """Simulate a QLineEdit."""
679 def __init__(self, name, disabled=False):
680 self.disabled = disabled
681 self.name = name
682 self.pos = 0
683 self.s = ''
685 def clear(self):
686 self.pos = 0
687 self.s = ''
689 def insert(self, s):
690 if s:
691 i = self.pos
692 self.s = self.s[:i] + s + self.s[i:]
693 self.pos += len(s)
695 def objectName(self):
696 return self.name
698 def text(self):
699 return self.s
700#@+node:ekr.20171128093602.1: ** class StringRadioButton (leoGui.py)
701class StringRadioButton:
702 """Simulate a QRadioButton."""
704 def __init__(self, name, label=None):
705 self.label = label
706 self.name = name
707 self.value = True
709 def isChecked(self):
710 return self.value
712 def objectName(self):
713 return self.name
715 def toggle(self):
716 self.value = not self.value
717#@+node:ekr.20031218072017.3742: ** class UnitTestGui (NullGui)
718class UnitTestGui(NullGui):
719 """A gui class for use by unit tests."""
720 # Presently used only by the import/export unit tests.
721 #@+others
722 #@+node:ekr.20031218072017.3743: *3* UnitTestGui.__init__
723 def __init__(self, theDict=None):
724 """ctor for the UnitTestGui class."""
725 self.oldGui = g.app.gui
726 super().__init__("UnitTestGui")
727 self.theDict = {} if theDict is None else theDict
728 g.app.gui = self
730 def destroySelf(self):
731 g.app.gui = self.oldGui
732 #@+node:ekr.20071128094234.1: *3* UnitTestGui.createSpellTab
733 def createSpellTab(self, c, spellHandler, tabName):
734 pass # This method keeps pylint happy.
735 #@+node:ekr.20111001155050.15484: *3* UnitTestGui.runAtIdle
736 if 1: # Huh?
738 def runAtIdle(self, aFunc):
739 """Run aFunc immediately for a unit test.
741 This is a kludge, but it is probably the best that can be done.
742 """
743 aFunc()
744 #@-others
745#@-others
746#@@language python
747#@@tabwidth -4
748#@@pagewidth 70
749#@-leo