Hide keyboard shortcuts

Hot-keys on this page

r m x p   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. 

7 

8These classes hide the details of which gui is actually being used. 

9Leo's core calls this class to allocate all gui objects. 

10 

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. 

20 

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 

38 # For SpellTabHandler class only. 

39 self.root = None 

40 self.script = None 

41 self.splashScreen = None 

42 self.utils = None 

43 # To keep pylint happy. 

44 self.ScriptingControllerClass = NullScriptingControllerClass 

45 # 

46 # Define special keys that may be overridden is subclasses. 

47 self.ignoreChars = [] 

48 # Keys that are always to be ignore. 

49 self.FKeys = [] 

50 # The representation of F-keys. 

51 self.specialChars = [] 

52 # A list of characters/keys to be handle specially. 

53 #@+node:ekr.20061109212618.1: *3* LeoGui: Must be defined only in base class 

54 #@+node:ekr.20110605121601.18847: *4* LeoGui.create_key_event (LeoGui) 

55 def create_key_event(self, c, 

56 binding=None, char=None, event=None, w=None, 

57 x=None, x_root=None, 

58 y=None, y_root=None, 

59 ): 

60 # Do not call strokeFromSetting here! 

61 # For example, this would wrongly convert Ctrl-C to Ctrl-c, 

62 # in effect, converting a user binding from Ctrl-Shift-C to Ctrl-C. 

63 return LeoKeyEvent(c, char, event, binding, w, x, y, x_root, y_root) 

64 #@+node:ekr.20031218072017.3740: *4* LeoGui.guiName 

65 def guiName(self): 

66 try: 

67 return self.mGuiName 

68 except Exception: 

69 return "invalid gui name" 

70 #@+node:ekr.20031218072017.2231: *4* LeoGui.setScript 

71 def setScript(self, script=None, scriptFileName=None): 

72 self.script = script 

73 self.scriptFileName = scriptFileName 

74 #@+node:ekr.20110605121601.18845: *4* LeoGui.event_generate (LeoGui) 

75 def event_generate(self, c, char, shortcut, w): 

76 event = self.create_key_event(c, binding=shortcut, char=char, w=w) 

77 c.k.masterKeyHandler(event) 

78 c.outerUpdate() 

79 #@+node:ekr.20061109212618: *3* LeoGu: Must be defined in subclasses 

80 #@+node:ekr.20031218072017.3725: *4* LeoGui.destroySelf 

81 def destroySelf(self): 

82 self.oops() 

83 #@+node:ekr.20031218072017.3730: *4* LeoGui.dialogs 

84 def runAboutLeoDialog(self, c, version, theCopyright, url, email): 

85 """Create and run Leo's About Leo dialog.""" 

86 self.oops() 

87 

88 def runAskLeoIDDialog(self): 

89 """Create and run a dialog to get g.app.LeoID.""" 

90 self.oops() 

91 

92 def runAskOkDialog(self, c, title, message=None, text="Ok"): 

93 """Create and run an askOK dialog .""" 

94 self.oops() 

95 

96 def runAskOkCancelNumberDialog( 

97 self, c, title, message, cancelButtonText=None, okButtonText=None): 

98 """Create and run askOkCancelNumber dialog .""" 

99 self.oops() 

100 

101 def runAskOkCancelStringDialog(self, c, title, message, cancelButtonText=None, 

102 okButtonText=None, default="", wide=False): 

103 """Create and run askOkCancelString dialog .""" 

104 self.oops() 

105 

106 def runAskYesNoDialog(self, c, title, message=None, yes_all=False, no_all=False): 

107 """Create and run an askYesNo dialog.""" 

108 self.oops() 

109 

110 def runAskYesNoCancelDialog(self, c, title, 

111 message=None, yesMessage="Yes", noMessage="No", 

112 yesToAllMessage=None, defaultButton="Yes", cancelMessage=None, 

113 ): 

114 """Create and run an askYesNoCancel dialog .""" 

115 self.oops() 

116 

117 def runPropertiesDialog( 

118 self, title='Properties', data=None, callback=None, buttons=None): 

119 """Dispay a modal TkPropertiesDialog""" 

120 self.oops() 

121 #@+node:ekr.20031218072017.3731: *4* LeoGui.file dialogs 

122 def runOpenFileDialog( 

123 self, c, title, filetypes, defaultextension, multiple=False, startpath=None): 

124 """Create and run an open file dialog .""" 

125 self.oops() 

126 

127 def runSaveFileDialog(self, c, title, filetypes, defaultextension): 

128 """Create and run a save file dialog .""" 

129 self.oops() 

130 #@+node:ekr.20031218072017.3732: *4* LeoGui.panels 

131 def createColorPanel(self, c): 

132 """Create a color panel""" 

133 self.oops() 

134 

135 def createComparePanel(self, c): 

136 """Create Compare panel.""" 

137 self.oops() 

138 

139 def createFindTab(self, c, parentFrame): 

140 """Create a find tab in the indicated frame.""" 

141 self.oops() 

142 

143 def createFontPanel(self, c): 

144 """Create a hidden Font panel.""" 

145 self.oops() 

146 

147 def createLeoFrame(self, c, title): 

148 """Create a new Leo frame.""" 

149 self.oops() 

150 #@+node:ekr.20031218072017.3729: *4* LeoGui.runMainLoop 

151 def runMainLoop(self): 

152 """Run the gui's main loop.""" 

153 self.oops() 

154 #@+node:ekr.20031218072017.3733: *4* LeoGui.utils 

155 #@+at Subclasses are expected to subclass all of the following methods. 

156 # These are all do-nothing methods: callers are expected to check for 

157 # None returns. 

158 # The type of commander passed to methods depends on the type of frame 

159 # or dialog being created. The commander may be a Commands instance or 

160 # one of its subcommanders. 

161 #@+node:ekr.20031218072017.3734: *5* LeoGui.Clipboard 

162 def replaceClipboardWith(self, s): 

163 self.oops() 

164 

165 def getTextFromClipboard(self): 

166 self.oops() 

167 #@+node:ekr.20031218072017.3735: *5* LeoGui.Dialog utils 

168 def attachLeoIcon(self, window): 

169 """Attach the Leo icon to a window.""" 

170 self.oops() 

171 

172 def center_dialog(self, dialog): 

173 """Center a dialog.""" 

174 self.oops() 

175 

176 def create_labeled_frame( 

177 self, parent, caption=None, relief="groove", bd=2, padx=0, pady=0): 

178 """Create a labeled frame.""" 

179 self.oops() 

180 

181 def get_window_info(self, window): 

182 """Return the window information.""" 

183 self.oops() 

184 #@+node:ekr.20031218072017.3737: *5* LeoGui.Focus 

185 def get_focus(self, *args, **kwargs): 

186 """Return the widget that has focus, or the body widget if None.""" 

187 self.oops() 

188 

189 def set_focus(self, commander, widget): 

190 """Set the focus of the widget in the given commander if it needs to be changed.""" 

191 self.oops() 

192 #@+node:ekr.20031218072017.3736: *5* LeoGui.Font 

193 def getFontFromParams(self, family, size, slant, weight, defaultSize=12): 

194 

195 self.oops() 

196 #@+node:ekr.20070212145124: *5* LeoGui.getFullVersion 

197 def getFullVersion(self, c=None): 

198 return 'LeoGui: dummy version' 

199 #@+node:ekr.20070212070820: *5* LeoGui.makeScriptButton 

200 def makeScriptButton(self, c, 

201 args=None, 

202 p=None, 

203 script=None, 

204 buttonText=None, 

205 balloonText='Script Button', 

206 shortcut=None, 

207 bg='LightSteelBlue1', 

208 define_g=True, 

209 define_name='__main__', 

210 silent=False, 

211 ): 

212 self.oops() 

213 #@+node:ekr.20070228154059: *3* LeoGui: May be defined in subclasses 

214 #@+node:ekr.20110613103140.16423: *4* LeoGui.dismiss_spash_screen 

215 def dismiss_splash_screen(self): 

216 pass # May be overridden in subclasses. 

217 #@+node:tbrown.20110618095626.22068: *4* LeoGui.ensure_commander_visible 

218 def ensure_commander_visible(self, c): 

219 """E.g. if commanders are in tabs, make sure c's tab is visible""" 

220 pass 

221 #@+node:ekr.20070219084912: *4* LeoGui.finishCreate 

222 def finishCreate(self): 

223 # This may be overridden in subclasses. 

224 pass 

225 #@+node:ekr.20101028131948.5861: *4* LeoGui.killPopupMenu & postPopupMenu 

226 # These definitions keep pylint happy. 

227 

228 def postPopupMenu(self, *args, **keys): 

229 pass 

230 #@+node:ekr.20031218072017.3741: *4* LeoGui.oops 

231 def oops(self): 

232 # It is not usually an error to call methods of this class. 

233 # However, this message is useful when writing gui plugins. 

234 if 1: 

235 g.pr("LeoGui oops", g.callers(4), "should be overridden in subclass") 

236 #@+node:ekr.20170612065049.1: *4* LeoGui.put_help 

237 def put_help(self, c, s, short_title): 

238 pass 

239 #@+node:ekr.20051206103652: *4* LeoGui.widget_name (LeoGui) 

240 def widget_name(self, w): 

241 # First try the widget's getName method. 

242 if not 'w': 

243 return '<no widget>' 

244 if hasattr(w, 'getName'): 

245 return w.getName() 

246 if hasattr(w, '_name'): 

247 return w._name 

248 return repr(w) 

249 #@-others 

250#@+node:ekr.20070228160107: ** class LeoKeyEvent 

251class LeoKeyEvent: 

252 """A gui-independent wrapper for gui events.""" 

253 #@+others 

254 #@+node:ekr.20110605121601.18846: *3* LeoKeyEvent.__init__ 

255 def __init__(self, c, char, event, binding, w, 

256 x=None, y=None, x_root=None, y_root=None 

257 ): 

258 """Ctor for LeoKeyEvent class.""" 

259 if g.isStroke(binding): 

260 g.trace('***** (LeoKeyEvent) oops: already a stroke', binding, g.callers()) 

261 stroke = binding 

262 else: 

263 stroke = g.KeyStroke(binding) if binding else None 

264 assert g.isStrokeOrNone(stroke), f"(LeoKeyEvent) {stroke!r} {g.callers()}" 

265 if 0: # Doesn't add much. 

266 if 'keys' in g.app.debug: 

267 print(f"LeoKeyEvent: binding: {binding}, stroke: {stroke}, char: {char!r}") 

268 self.c = c 

269 self.char = char or '' 

270 self.event = event # New in Leo 4.11. 

271 self.stroke = stroke 

272 self.w = self.widget = w 

273 # Optional ivars 

274 self.x = x 

275 self.y = y 

276 # Support for fastGotoNode plugin 

277 self.x_root = x_root 

278 self.y_root = y_root 

279 #@+node:ekr.20140907103315.18774: *3* LeoKeyEvent.__repr__ 

280 def __repr__(self): 

281 

282 d = {'c': self.c.shortFileName()} 

283 for ivar in ('char', 'event', 'stroke', 'w'): 

284 d[ivar] = getattr(self, ivar) 

285 return f"LeoKeyEvent:\n{g.objToString(d)}" 

286 #@+node:ekr.20150511181702.1: *3* LeoKeyEvent.get & __getitem__ 

287 def get(self, attr): 

288 """Compatibility with g.bunch: return an attr.""" 

289 return getattr(self, attr, None) 

290 

291 def __getitem__(self, attr): 

292 """Compatibility with g.bunch: return an attr.""" 

293 return getattr(self, attr, None) 

294 #@+node:ekr.20140907103315.18775: *3* LeoKeyEvent.type 

295 def type(self): 

296 return 'LeoKeyEvent' 

297 #@-others 

298#@+node:ekr.20031218072017.2223: ** class NullGui (LeoGui) 

299class NullGui(LeoGui): 

300 """Null gui class.""" 

301 #@+others 

302 #@+node:ekr.20031218072017.2225: *3* NullGui.__init__ 

303 def __init__(self, guiName='nullGui'): 

304 """ctor for the NullGui class.""" 

305 super().__init__(guiName) 

306 self.clipboardContents = '' 

307 self.focusWidget = None 

308 self.script = None 

309 self.lastFrame = None 

310 # The outer frame, used only to set the g.app.log in runMainLoop. 

311 self.isNullGui = True 

312 self.idleTimeClass = g.NullObject 

313 #@+node:ekr.20031218072017.3744: *3* NullGui.dialogs 

314 def runAboutLeoDialog(self, c, version, theCopyright, url, email): 

315 return self.simulateDialog("aboutLeoDialog", None) 

316 

317 def runAskLeoIDDialog(self): 

318 return self.simulateDialog("leoIDDialog", None) 

319 

320 def runAskOkDialog(self, c, title, message=None, text="Ok"): 

321 return self.simulateDialog("okDialog", "Ok") 

322 

323 def runAskOkCancelNumberDialog(self, c, title, message, 

324 cancelButtonText=None, 

325 okButtonText=None, 

326 ): 

327 return self.simulateDialog("numberDialog", -1) 

328 

329 def runAskOkCancelStringDialog(self, c, title, message, 

330 cancelButtonText=None, 

331 okButtonText=None, 

332 default="", 

333 wide=False, 

334 ): 

335 return self.simulateDialog("stringDialog", '') 

336 

337 def runCompareDialog(self, c): 

338 return self.simulateDialog("compareDialog", '') 

339 

340 def runOpenFileDialog(self, c, title, filetypes, defaultextension, 

341 multiple=False, 

342 startpath=None, 

343 ): 

344 return self.simulateDialog("openFileDialog", None) 

345 

346 def runSaveFileDialog(self, c, title, filetypes, defaultextension): 

347 return self.simulateDialog("saveFileDialog", None) 

348 

349 def runAskYesNoDialog(self, c, title, 

350 message=None, 

351 yes_all=False, 

352 no_all=False, 

353 ): 

354 return self.simulateDialog("yesNoDialog", "no") 

355 

356 def runAskYesNoCancelDialog(self, c, title, 

357 message=None, 

358 yesMessage="Yes", 

359 noMessage="No", 

360 yesToAllMessage=None, 

361 defaultButton="Yes", 

362 cancelMessage=None, 

363 ): 

364 return self.simulateDialog("yesNoCancelDialog", "cancel") 

365 

366 def simulateDialog(self, key, defaultVal): 

367 return defaultVal 

368 #@+node:ekr.20170613101737.1: *3* NullGui.clipboard & focus 

369 def get_focus(self, *args, **kwargs): 

370 return self.focusWidget 

371 

372 def getTextFromClipboard(self): 

373 return self.clipboardContents 

374 

375 def replaceClipboardWith(self, s): 

376 self.clipboardContents = s 

377 

378 def set_focus(self, commander, widget): 

379 self.focusWidget = widget 

380 #@+node:ekr.20070301171901: *3* NullGui.do nothings 

381 def alert(self, c, message): 

382 pass 

383 

384 def attachLeoIcon(self, window): 

385 pass 

386 

387 def destroySelf(self): 

388 pass 

389 

390 def finishCreate(self): 

391 pass 

392 

393 def getFontFromParams(self, family, size, slant, weight, defaultSize=12): 

394 return g.app.config.defaultFont 

395 

396 def getIconImage(self, name): 

397 return None 

398 

399 def getImageImage(self, name): 

400 return None 

401 

402 def getTreeImage(self, c, path): 

403 return None 

404 

405 def get_window_info(self, window): 

406 return 600, 500, 20, 20 

407 

408 def onActivateEvent(self, *args, **keys): 

409 pass 

410 

411 def onDeactivateEvent(self, *args, **keys): 

412 pass 

413 

414 def set_top_geometry(self, w, h, x, y): 

415 pass 

416 #@+node:ekr.20070228155807: *3* NullGui.isTextWidget & isTextWrapper 

417 def isTextWidget(self, w): 

418 return True # Must be True for unit tests. 

419 

420 def isTextWrapper(self, w): 

421 """Return True if w is a Text widget suitable for text-oriented commands.""" 

422 return w and getattr(w, 'supportsHighLevelInterface', None) 

423 #@+node:ekr.20031218072017.2230: *3* NullGui.oops 

424 def oops(self): 

425 g.trace("NullGui", g.callers(4)) 

426 #@+node:ekr.20070301172456: *3* NullGui.panels 

427 def createComparePanel(self, c): 

428 """Create Compare panel.""" 

429 self.oops() 

430 

431 def createFindTab(self, c, parentFrame): 

432 """Create a find tab in the indicated frame.""" 

433 pass # Now always done during startup. 

434 

435 def createLeoFrame(self, c, title): 

436 """Create a null Leo Frame.""" 

437 gui = self 

438 self.lastFrame = leoFrame.NullFrame(c, title, gui) 

439 return self.lastFrame 

440 #@+node:ekr.20031218072017.2229: *3* NullGui.runMainLoop 

441 def runMainLoop(self): 

442 """Run the null gui's main loop.""" 

443 if self.script: 

444 frame = self.lastFrame 

445 g.app.log = frame.log 

446 self.lastFrame.c.executeScript(script=self.script) 

447 else: 

448 print('**** NullGui.runMainLoop: terminating Leo.') 

449 # Getting here will terminate Leo. 

450 #@-others 

451#@+node:ekr.20080707150137.5: ** class NullScriptingControllerClass 

452class NullScriptingControllerClass: 

453 """A default, do-nothing class to be overridden by mod_scripting or other plugins. 

454 

455 This keeps pylint happy.""" 

456 

457 def __init__(self, c, iconBar=None): 

458 self.c = c 

459 self.iconBar = iconBar 

460 

461 def createAllButtons(self): 

462 pass 

463#@+node:ekr.20171128093401.1: ** class StringCheckBox (leoGui.py) 

464class StringCheckBox: 

465 """Simulate a QCheckBox.""" 

466 

467 def __init__(self, name, label=None): 

468 self.label = label 

469 self.name = name 

470 self.value = True 

471 

472 def checkState(self): 

473 return self.value 

474 

475 isChecked = checkState 

476 

477 def objectName(self): 

478 return self.name 

479 

480 def setCheckState(self, value): 

481 self.value = value 

482 

483 def toggle(self): 

484 self.value = not self.value 

485#@+node:ekr.20210221130549.1: ** class StringFindTabManager (leoGui.py) (new) 

486class StringFindTabManager: 

487 """A string-based FindTabManager class for unit tests.""" 

488 #@+others 

489 #@+node:ekr.20210221130549.2: *3* sftm.ctor 

490 #@@nobeautify 

491 

492 def __init__(self, c): 

493 """Ctor for the FindTabManager class.""" 

494 self.c = c 

495 self.entry_focus = None # Accessed directly from code(!) 

496 # Find/change text boxes... 

497 self.find_findbox = StringLineEdit('find_text') 

498 self.find_replacebox = StringLineEdit('change_text') 

499 # Check boxes... 

500 self.check_box_ignore_case = StringCheckBox('ignore_case') 

501 self.check_box_mark_changes = StringCheckBox('mark_changes') 

502 self.check_box_mark_finds = StringCheckBox('mark_finds') 

503 self.check_box_regexp = StringCheckBox('pattern_match') 

504 self.check_box_search_body = StringCheckBox('search_body') 

505 self.check_box_search_headline = StringCheckBox('search_headline') 

506 self.check_box_whole_word = StringCheckBox('whole_word') 

507 # Radio buttons... 

508 self.radio_button_entire_outline = StringRadioButton('entire_outline') 

509 self.radio_button_node_only = StringRadioButton('node_only') 

510 self.radio_button_suboutline_only = StringRadioButton('suboutline_only') 

511 # Init the default values. 

512 self.init_widgets() 

513 #@+node:ekr.20210221130549.5: *3* sftm.clear_focus & init_focus & set_entry_focus 

514 def clear_focus(self): 

515 pass 

516 

517 def init_focus(self): 

518 pass 

519 

520 def set_entry_focus(self): 

521 pass 

522 #@+node:ekr.20210221130549.4: *3* sftm.get_settings 

523 #@@nobeautify 

524 

525 def get_settings(self): 

526 """ 

527 Return a g.bunch representing all widget values. 

528 

529 Similar to LeoFind.default_settings, but only for find-tab values. 

530 """ 

531 return g.Bunch( 

532 # Find/change strings... 

533 find_text = self.find_findbox.text(), 

534 change_text = self.find_replacebox.text(), 

535 # Find options... 

536 ignore_case = self.check_box_ignore_case.isChecked(), 

537 mark_changes = self.check_box_mark_changes.isChecked(), 

538 mark_finds = self.check_box_mark_finds.isChecked(), 

539 node_only = self.radio_button_node_only.isChecked(), 

540 pattern_match = self.check_box_regexp.isChecked(), 

541 search_body = self.check_box_search_body.isChecked(), 

542 search_headline = self.check_box_search_headline.isChecked(), 

543 suboutline_only = self.radio_button_suboutline_only.isChecked(), 

544 whole_word = self.check_box_whole_word.isChecked(), 

545 ) 

546 #@+node:ekr.20210221130549.7: *3* sftm.init_widgets 

547 def init_widgets(self): 

548 """ 

549 Init widgets and ivars from c.config settings. 

550 Create callbacks that always keep the LeoFind ivars up to date. 

551 """ 

552 c, find = self.c, self.c.findCommands 

553 # Find/change text boxes. 

554 table1 = ( 

555 ('find_findbox', 'find_text', '<find pattern here>'), 

556 ('find_replacebox', 'change_text', ''), 

557 ) 

558 for widget_ivar, setting_name, default in table1: 

559 w = getattr(self, widget_ivar) 

560 s = c.config.getString(setting_name) or default 

561 w.insert(s) 

562 # Check boxes. 

563 table2 = ( 

564 ('ignore_case', 'check_box_ignore_case'), 

565 ('mark_changes', 'check_box_mark_changes'), 

566 ('mark_finds', 'check_box_mark_finds'), 

567 ('pattern_match', 'check_box_regexp'), 

568 ('search_body', 'check_box_search_body'), 

569 ('search_headline', 'check_box_search_headline'), 

570 ('whole_word', 'check_box_whole_word'), 

571 ) 

572 for setting_name, widget_ivar in table2: 

573 w = getattr(self, widget_ivar) 

574 val = c.config.getBool(setting_name, default=False) 

575 setattr(find, setting_name, val) 

576 if val != w.isChecked(): # Support leoInteg. 

577 w.toggle() 

578 # Radio buttons 

579 table3 = ( 

580 ('node_only', 'node_only', 'radio_button_node_only'), 

581 ('entire_outline', None, 'radio_button_entire_outline'), 

582 ('suboutline_only', 'suboutline_only', 'radio_button_suboutline_only'), 

583 ) 

584 for setting_name, ivar, widget_ivar in table3: 

585 w = getattr(self, widget_ivar) 

586 val = c.config.getBool(setting_name, default=False) 

587 if ivar is not None: 

588 assert hasattr(find, setting_name), setting_name 

589 setattr(find, setting_name, val) 

590 if val != w.isChecked(): 

591 w.toggle() 

592 # Ensure one radio button is set. 

593 if not find.node_only and not find.suboutline_only: 

594 w = self.radio_button_entire_outline 

595 if val != w.isChecked(): 

596 w.toggle() 

597 #@+node:ekr.20210312122351.1: *3* sftm.set_body_and_headline_checkbox 

598 def set_body_and_headline_checkbox(self): 

599 """Return the search-body and search-headline checkboxes to their defaults.""" 

600 # #1840: headline-only one-shot 

601 c = self.c 

602 find = c.findCommands 

603 if not find: 

604 return 

605 table = ( 

606 ('search_body', self.check_box_search_body), 

607 ('search_headline', self.check_box_search_headline), 

608 ) 

609 for setting_name, w in table: 

610 val = c.config.getBool(setting_name, default=False) 

611 if val != w.isChecked(): 

612 w.toggle() 

613 #@+node:ekr.20210221130549.8: *3* sftm.set_radio_button 

614 #@@nobeautify 

615 

616 def set_radio_button(self, name): 

617 """Set the value of the radio buttons""" 

618 d = { 

619 'node-only': self.radio_button_node_only, 

620 'entire-outline': self.radio_button_entire_outline, 

621 'suboutline-only': self.radio_button_suboutline_only, 

622 } 

623 w = d.get(name) 

624 if not w.isChecked(): 

625 w.toggle() 

626 #@+node:ekr.20210221130549.3: *3* sftm.text getters/setters 

627 def get_find_text(self): 

628 s = self.find_findbox.text() 

629 if s and s[-1] in ('\r', '\n'): 

630 s = s[:-1] 

631 return s 

632 

633 def get_change_text(self): 

634 s = self.find_replacebox.text() 

635 if s and s[-1] in ('\r', '\n'): 

636 s = s[:-1] 

637 return s 

638 

639 def set_find_text(self, s): 

640 w = self.find_findbox 

641 w.clear() 

642 w.insert(s) 

643 

644 def set_change_text(self, s): 

645 w = self.find_replacebox 

646 w.clear() 

647 w.insert(s) 

648 #@+node:ekr.20210221130549.9: *3* sftm.toggle_checkbox 

649 #@@nobeautify 

650 

651 def toggle_checkbox(self, checkbox_name): 

652 """Toggle the value of the checkbox whose name is given.""" 

653 d = { 

654 'ignore_case': self.check_box_ignore_case, 

655 'mark_changes': self.check_box_mark_changes, 

656 'mark_finds': self.check_box_mark_finds, 

657 'pattern_match': self.check_box_regexp, 

658 'search_body': self.check_box_search_body, 

659 'search_headline': self.check_box_search_headline, 

660 'whole_word': self.check_box_whole_word, 

661 } 

662 w = d.get(checkbox_name) 

663 w.toggle() 

664 #@-others 

665#@+node:ekr.20170613095422.1: ** class StringGui (LeoGui) 

666class StringGui(LeoGui): 

667 """ 

668 A class representing all on-screen objects using subclasses of the 

669 leoFrame.StringTextWrapper class. 

670 """ 

671 #@+others 

672 #@+node:ekr.20170613095422.7: *3* StringGui.oops 

673 def oops(self): 

674 

675 g.trace("StringGui", g.callers(4)) 

676 #@+node:ekr.20170613114120.1: *3* StringGui.runMainLoop 

677 def runMainLoop(self): 

678 self.oops() 

679 #@-others 

680#@+node:ekr.20171128093503.1: ** class StringLineEdit (leoGui) 

681class StringLineEdit: 

682 """Simulate a QLineEdit.""" 

683 

684 def __init__(self, name, disabled=False): 

685 self.disabled = disabled 

686 self.name = name 

687 self.pos = 0 

688 self.s = '' 

689 

690 def clear(self): 

691 self.pos = 0 

692 self.s = '' 

693 

694 def insert(self, s): 

695 if s: 

696 i = self.pos 

697 self.s = self.s[:i] + s + self.s[i:] 

698 self.pos += len(s) 

699 

700 def objectName(self): 

701 return self.name 

702 

703 def text(self): 

704 return self.s 

705#@+node:ekr.20171128093602.1: ** class StringRadioButton (leoGui.py) 

706class StringRadioButton: 

707 """Simulate a QRadioButton.""" 

708 

709 def __init__(self, name, label=None): 

710 self.label = label 

711 self.name = name 

712 self.value = True 

713 

714 def isChecked(self): 

715 return self.value 

716 

717 def objectName(self): 

718 return self.name 

719 

720 def toggle(self): 

721 self.value = not self.value 

722#@+node:ekr.20031218072017.3742: ** class UnitTestGui (NullGui) 

723class UnitTestGui(NullGui): 

724 """A gui class for use by unit tests.""" 

725 # Presently used only by the import/export unit tests. 

726 #@+others 

727 #@+node:ekr.20031218072017.3743: *3* UnitTestGui.__init__ 

728 def __init__(self, theDict=None): 

729 """ctor for the UnitTestGui class.""" 

730 self.oldGui = g.app.gui 

731 super().__init__("UnitTestGui") 

732 self.theDict = {} if theDict is None else theDict 

733 g.app.gui = self 

734 

735 def destroySelf(self): 

736 g.app.gui = self.oldGui 

737 #@+node:ekr.20071128094234.1: *3* UnitTestGui.createSpellTab 

738 def createSpellTab(self, c, spellHandler, tabName): 

739 pass # This method keeps pylint happy. 

740 #@+node:ekr.20111001155050.15484: *3* UnitTestGui.runAtIdle 

741 if 1: # Huh? 

742 

743 def runAtIdle(self, aFunc): 

744 """Run aFunc immediately for a unit test. 

745 

746 This is a kludge, but it is probably the best that can be done. 

747 """ 

748 aFunc() 

749 #@-others 

750#@-others 

751#@@language python 

752#@@tabwidth -4 

753#@@pagewidth 70 

754#@-leo