<?xml version="1.0" encoding="utf-8"?>
<!-- Created by Leo: http://leoeditor.com/leo_toc.html -->
<leo_file xmlns:leo="http://leoeditor.com/namespaces/leo-python-editor/1.1" >
<leo_header file_format="2" tnodes="0" max_tnode_index="0" clone_windows="0"/>
<globals body_outline_ratio="0.54" body_secondary_ratio="0.78">
	<global_window_position top="108" left="527" height="957" width="1099"/>
	<global_log_window_position top="0" left="0" height="0" width="0"/>
</globals>
<preferences/>
<find_panel_settings/>
<vnodes>
<v t="ekr.20070417092935"><vh>Startup</vh>
<v t="ekr.20041121151002"><vh>@settings</vh>
<v t="ekr.20150602215639.1"><vh>@bool tidy_autobeautify = False</vh></v>
<v t="ekr.20150321155210.11"><vh>@bool verbose_check_outline = False</vh></v>
<v t="ekr.20140902101931.4478"><vh>@bool qt-use-scintilla = False</vh></v>
<v t="ekr.20110521073115.3494"><vh>colorizer colors</vh>
<v t="ekr.20110521073115.3495"><vh>@@color keyword3_color = orange</vh></v>
<v t="ekr.20110521073115.3496"><vh>@@color keyword4_color = pink</vh></v>
</v>
<v t="ekr.20111026111009.3972"><vh>@data import_xml_tags</vh></v>
<v t="ekr.20140217055617.4231"><vh>@bool scriptingatscriptnodes = True</vh></v>
<v t="ekr.20080324133327.2"><vh>@bool allow_middle_button_paste = True</vh></v>
<v t="ekr.20101009105124.6195"><vh>@bool put_expansion_bits_in_leo_files = True</vh></v>
<v t="ekr.20051013162226"><vh>@bool test_setting = True</vh></v>
<v t="ekr.20070503064257"><vh>@bool use_chapters = True</vh></v>
<v t="ekr.20070528100318"><vh>@bool write_strips_blank_lines = False</vh></v>
<v t="ekr.20111123042627.6654"><vh>@enabled-plugins</vh></v>
<v t="ekr.20111112093605.4679"><vh>@shortcuts</vh></v>
<v t="ekr.20111124094121.3941"><vh>Empty @buttons and @commands nodes</vh>
<v t="ekr.20111124094121.3942"><vh>@buttons</vh></v>
<v t="ekr.20111124094121.3943"><vh>@commands</vh></v>
</v>
<v t="ekr.20050328101834"><vh>@page http plugin</vh>
<v t="ekr.20050328101834.1"><vh>@bool http_active = False</vh></v>
<v t="ekr.20050328101834.2"><vh>@int  port = 8080</vh></v>
<v t="ekr.20050328101834.3"><vh>@string rst_http_attributename = ''</vh></v>
</v>
<v t="ekr.20131111155830.4249"><vh>Vim settings</vh>
<v t="ekr.20131111155830.4250"><vh>@@@data vim-control-character-commands</vh></v>
<v t="ekr.20131111155830.4251"><vh>@data vim-command-tails</vh></v>
<v t="ekr.20131111155830.4252"><vh>@data vim-commands</vh></v>
<v t="ekr.20131111155830.4253"><vh>@data vim-motions</vh></v>
<v t="ekr.20131111155830.4254"><vh>@data vim-motion-tails</vh></v>
</v>
</v>
<v t="ekr.20150216110251.11"><vh>@persistence</vh>
<v t="edward.20150612083734.1"><vh>@data:#@auto</vh></v>
<v t="edward.20150612083734.2"><vh>@data:#@auto</vh>
<v t="edward.20150612083734.3"><vh>@gnxs</vh></v>
</v>
<v t="edward.20150612083734.4"><vh>@data:#@auto</vh></v>
<v t="edward.20150612083734.5"><vh>@data:#@auto</vh>
<v t="edward.20150612083734.6"><vh>@gnxs</vh></v>
</v>
<v t="ekr.20150625052701.1"><vh>@data:@auto unittest/at-auto-line-number-test.py</vh>
<v t="ekr.20150625134618.1"><vh>@gnxs</vh></v>
</v>
<v t="ekr.20150625091937.3"><vh>@data:@auto ../test/at-auto-unit-test.py</vh>
<v t="ekr.20160403165232.24"><vh>@gnxs</vh></v>
</v>
<v t="ekr.20150626093952.1"><vh>@data:@auto-rst unittest/at-auto-rst-line-number-test.py</vh>
<v t="ekr.20160403165233.11"><vh>@gnxs</vh></v>
</v>
<v t="ekr.20150626100832.1"><vh>@data:@auto-otl unittest/at-auto-otl-line-number-test.py</vh>
<v t="ekr.20160403165232.9"><vh>@gnxs</vh></v>
</v>
<v t="ekr.20150626101730.1"><vh>@data:@auto-org unittest/at-auto-org-line-number-test.py</vh>
<v t="ekr.20160403165232.2"><vh>@gnxs</vh></v>
</v>
<v t="ekr.20150626102601.1"><vh>@data:@auto unittest/at-auto-md-line-number-test.md</vh>
<v t="ekr.20160403165231.9"><vh>@gnxs</vh></v>
</v>
<v t="ekr.20160403143348.1"><vh>@data:@auto unittest/at-auto-section-ref-test.py</vh>
<v t="ekr.20160403143348.2"><vh>@gnxs</vh></v>
</v>
<v t="ekr.20160403143351.1"><vh>@data:@auto unittest/at-auto-test.py</vh>
<v t="ekr.20160403143351.2"><vh>@gnxs</vh></v>
</v>
</v>
<v t="ekr.20101220161557.6011"><vh>@file unitTestStartup.txt</vh></v>
<v t="ekr.20111112092813.4154"><vh>@command cls</vh></v>
<v t="ekr.20140716121225.4354"><vh>@@button print-gnx</vh></v>
<v t="ekr.20100123172713.5114"><vh>Scripts</vh>
<v t="ekr.20100102164959.5088"><vh>Count pages</vh></v>
<v t="ekr.20100123172713.5116"><vh>Clean all tnodeLists</vh></v>
<v t="ekr.20070217065840"><vh>Scripts that make unit tests</vh>
<v t="ekr.20070217065840.1"><vh>@@command make-test @key = Alt-5</vh></v>
<v t="ekr.20070217065840.2"><vh>@@command do-before @key = Alt-6</vh>
<v t="ekr.20070217065840.3"><vh>getSel</vh></v>
<v t="ekr.20070217065840.4"><vh>findNodes</vh></v>
<v t="ekr.20070217065840.5"><vh>putSelectionInHeadline</vh></v>
</v>
<v t="ekr.20070217065840.6"><vh>@@command do-after @key = Alt-7</vh>
<v t="ekr.20070217072822"><vh>getSel</vh></v>
<v t="ekr.20070217065840.8"><vh>findNodes</vh></v>
<v t="ekr.20070217065840.9"><vh>putSelectionInHeadline</vh></v>
</v>
</v>
<v t="ekr.20070113145100"><vh>Create chinese folder</vh></v>
<v t="ekr.20071113140035"><vh>Find unique @ test nodes</vh></v>
<v t="ekr.20091206090247.5060"><vh>Clear all uA's, tnodeLists, etc.</vh>
<v t="ekr.20091206090247.5061"><vh>Clean unused tnodeLists</vh></v>
<v t="ekr.20091206090247.5062"><vh>Clear all timestamps</vh></v>
<v t="ekr.20091206090247.5063"><vh>Clear all uAs (unknown attributes)</vh></v>
</v>
</v>
</v>
<v t="ekr.20111123042627.6654"></v>
<v t="ekr.20111112093605.4679"></v>
<v t="ekr.20051012104957"><vh>@ignore Docs</vh>
<v t="bwmulder.20050108100437.1"><vh>How to run unit tests</vh></v>
<v t="ekr.20050618061835"><vh>How to use the @test directive, by Roger Erens</vh>
<v t="ekr.20050618061835.1"><vh>Intro</vh>
<v t="ekr.20050618061835.2"><vh>@url http://www.onlamp.com/pub/a/python/2005/02/03/tdd_pyunit2.html</vh></v>
</v>
<v t="ekr.20050618061835.3"><vh>Preparations: adding a button</vh>
<v t="ekr.20050618061835.4"><vh>@@button Do @test</vh></v>
</v>
<v t="ekr.20050618061835.5"><vh>Alpha</vh>
<v t="ekr.20050618061835.6"><vh>@test my first Leo test</vh></v>
<v t="ekr.20050618061835.7"><vh>output on the console</vh></v>
</v>
<v t="ekr.20050618061835.8"><vh>Bravo</vh>
<v t="ekr.20050618061835.9"><vh>@@test my second Leo test</vh></v>
<v t="ekr.20050618061835.10"><vh>output on the console</vh></v>
</v>
<v t="ekr.20050618061835.11"><vh>It takes two to tango</vh>
<v t="ekr.20050618061835.6"></v>
<v t="ekr.20050618061835.9"></v>
<v t="ekr.20050618061835.12"><vh>output on the console</vh></v>
</v>
<v t="ekr.20050618061835.13"><vh>Life gets more interesting</vh>
<v t="ekr.20050618061835.14"><vh>@@test koekiemonster.wants()</vh>
<v t="ekr.20050618061835.15"><vh>input data</vh></v>
<v t="ekr.20050618061835.16"><vh>expected result</vh></v>
</v>
<v t="ekr.20050618061835.17"><vh>output on the console</vh></v>
<v t="ekr.20050618061835.18"><vh>output on the console using print statements</vh></v>
</v>
<v t="ekr.20050618061835.19"><vh>How about @suite?</vh></v>
<v t="ekr.20050618061835.20"><vh>Final remarks</vh></v>
</v>
<v t="ekr.20111211094936.3970"><vh>@ignore To do</vh>
<v t="ekr.20111115080347.3872"><vh>To do: tests of the high-level interface</vh>
<v t="ekr.20100131171342.5478"><vh>@@@test that log and body implements high-level interface</vh></v>
</v>
<v t="ekr.20100131171342.5473"><vh>Tk gui tests</vh>
<v t="ekr.20100131171342.5474"><vh>@test leoBody is subset of leoTkBody</vh></v>
<v t="ekr.20100131171342.5475"><vh>@test leoFrame is subset of leoTkFrame</vh></v>
<v t="ekr.20100131171342.5476"><vh>@test leoGui is subset of leoTkGui</vh></v>
<v t="ekr.20100131171342.5477"><vh>@test leoTree is subset of leoTkTree</vh></v>
</v>
<v t="ekr.20111125183140.3952"><vh>@test ic.createOutline changes back-slashes to slashes</vh></v>
<v t="ekr.20111125182408.3947"><vh>@test ic.createImportParent changes back-slashes to slashes</vh></v>
</v>
</v>
<v t="ekr.20101220161557.6013"><vh>@ignore Slow and unused tests</vh>
<v t="ekr.20101220161557.6014"><vh>@file inactiveTests.txt</vh>
<v t="ekr.20111113194727.3869"><vh>@@@test BaseTextWrapper methods</vh></v>
<v t="ekr.20110615130436.3319"><vh>@@@test writing a .leo file retains orphan bits</vh></v>
<v t="ekr.20150529183247.1"><vh>@@test ptb.comment_leo_lines &amp; ptb.uncomment_leo_lines</vh>
<v t="ekr.20150529183259.1"><vh>indented docstring</vh></v>
<v t="ekr.20150529184545.1"><vh>indented docstring2</vh></v>
</v>
<v t="ekr.20150214063940.11"><vh>@ignore @shadow tests</vh>
<v t="ekr.20111210175541.3957"><vh>@@test at.readOneAtShadowNode retains @shadow links clones</vh>
<v t="ekr.20120228174052.3929"><vh>Node 1</vh></v>
</v>
<v t="ekr.20110610122533.3397"><vh>@@test goto-global-line @shadow</vh></v>
</v>
<v t="ekr.20130503061511.4137"><vh>@ignore from leoPy.leo</vh>
<v t="ekr.20130503061511.4140"><vh>@test html string</vh>
<v t="ekr.20130503061511.4141"><vh>@file c:/leo.repo/trunk/leo/core/html string</vh>
<v t="ekr.20130503061511.4150"><vh>html</vh>
<v t="ekr.20130503061511.4151"><vh>head</vh></v>
<v t="ekr.20130503061511.4152"><vh>body</vh></v>
</v>
</v>
<v t="ekr.20130503061511.4145"><vh>@file c:/leo.repo/trunk/leo/core/html string</vh>
<v t="ekr.20130503061511.4150"></v>
</v>
<v t="ekr.20130503061511.4149"><vh>@file c:/leo.repo/trunk/leo/core/html string</vh>
<v t="ekr.20130503061511.4150"></v>
</v>
</v>
<v t="ekr.20130503061511.4153"><vh>@test HtmlScanner.filterTokens</vh></v>
<v t="ekr.20130503061511.4154"><vh>@test import dataN.html</vh></v>
<v t="ekr.20130503061511.4155"><vh>@test unicode stuff</vh></v>
<v t="ekr.20130503061511.4156"><vh>@test external text operations</vh></v>
<v t="ekr.20130503061511.4157"><vh>@test nullBody text operations</vh></v>
<v t="ekr.20130503061511.4158"><vh>@test g.python_tokenize</vh></v>
</v>
<v t="ekr.20130503061820.4217"><vh>@ignore LeoInspect unit tests</vh>
<v t="ekr.20130503061820.4218"><vh>Basic tests</vh>
<v t="ekr.20130503061820.4219"><vh>@test leoInspect with multiple files</vh>
<v t="ekr.20130503061820.4220"><vh>&lt;&lt; define old_s &gt;&gt;</vh></v>
<v t="ekr.20130503061820.4221"><vh>&lt;&lt; define s &gt;&gt;</vh></v>
<v t="ekr.20130503061820.4222"><vh>test</vh></v>
</v>
<v t="ekr.20130503061820.4223"><vh>@test leoInspect.module.classes</vh></v>
<v t="ekr.20130503061820.4224"><vh>@test leoInspect.module.defs</vh></v>
<v t="ekr.20130503061820.4225"><vh>@test leoInspect.module.classes 2</vh></v>
<v t="ekr.20130503061820.4226"><vh>@test leoInspect.module.statements</vh></v>
<v t="ekr.20130503061820.4227"><vh>@test leoInspect (leoEditCommands.py)</vh></v>
<v t="ekr.20130503061820.4228"><vh>@test leoInspect.module (s)</vh>
<v t="ekr.20130503061820.4229"><vh>&lt;&lt; define s &gt;&gt;</vh></v>
</v>
</v>
<v t="ekr.20130503061820.4230"><vh>leoInspect speed tests</vh>
<v t="ekr.20130503061820.4231"><vh>@test speed of leoInspect.module (all core files)</vh></v>
<v t="ekr.20130503061820.4232"><vh>@test speed of AstTraverser (all Leo core files)</vh></v>
</v>
<v t="ekr.20130503061820.4233"><vh>@test compute all ivars in all classes</vh></v>
<v t="ekr.20130503061820.4234"><vh>@test find all ctors</vh></v>
<v t="ekr.20130503061820.4235"><vh>@test pickling</vh></v>
<v t="ekr.20130503061820.4236"><vh>@test cache contexts</vh></v>
<v t="ekr.20130503061820.4237"><vh>@test AstFormatter</vh></v>
<v t="ekr.20130503061820.4238"><vh>@test g_files_in_dir</vh></v>
<v t="ekr.20130503061820.4239"><vh>@test print-chains</vh></v>
<v t="ekr.20130503061820.4240"><vh>@test print-calls</vh></v>
<v t="ekr.20130503061820.4241"><vh>@test print-returns</vh></v>
<v t="ekr.20130503061820.4242"><vh>@test global names</vh></v>
<v t="ekr.20130503061820.4189"><vh>@test leoInspect.token_range (s)</vh>
<v t="ekr.20130503061820.4190"><vh>&lt;&lt; define s &gt;&gt;</vh></v>
</v>
</v>
<v t="ekr.20131231093529.3984"><vh>@ignore leoViews.py</vh>
<v t="ekr.20140110141116.4267"><vh>@@@test vc.create_tree_structure (rewrite)</vh>
<v t="ekr.20140110141116.4322"><vh>root_restore</vh>
<v t="ekr.20140110141116.4323"><vh>aClass</vh>
<v t="ekr.20140110141116.4324"><vh>before</vh></v>
<v t="ekr.20140110141116.4325"><vh>child11</vh></v>
<v t="ekr.20140110141116.4326"><vh>child12</vh></v>
<v t="ekr.20140110141116.4327"><vh>middle</vh></v>
<v t="ekr.20140110141116.4328"><vh>child21</vh></v>
<v t="ekr.20140110141116.4329"><vh>child22</vh></v>
<v t="ekr.20140110141116.4330"><vh>after</vh></v>
<v t="ekr.20140110141116.4331"><vh>last1</vh></v>
</v>
<v t="ekr.20140110141116.4332"><vh>top1</vh></v>
<v t="ekr.20140110141116.4333"><vh>top2</vh></v>
</v>
<v t="ekr.20140110141116.4351"><vh>root_before</vh>
<v t="ekr.20140110141116.4352"><vh>aClass</vh>
<v t="ekr.20140110141116.4353"><vh>before</vh></v>
<v t="ekr.20140110141116.4354"><vh>organizer node</vh>
<v t="ekr.20140110141116.4368"><vh>intermediate node</vh>
<v t="ekr.20140110141116.4355"><vh>inner org1</vh>
<v t="ekr.20140110141116.4356"><vh>child11</vh></v>
<v t="ekr.20140110141116.4357"><vh>child12</vh></v>
</v>
<v t="ekr.20140110141116.4358"><vh>middle</vh></v>
<v t="ekr.20140110141116.4359"><vh>inner org2</vh>
<v t="ekr.20140110141116.4360"><vh>child21</vh></v>
<v t="ekr.20140110141116.4361"><vh>child22</vh></v>
</v>
</v>
</v>
<v t="ekr.20140110141116.4362"><vh>after</vh></v>
<v t="ekr.20140110141116.4363"><vh>last organizer</vh>
<v t="ekr.20140110141116.4364"><vh>last1</vh></v>
</v>
</v>
<v t="ekr.20140110141116.4365"><vh>top-level</vh>
<v t="ekr.20140110141116.4366"><vh>top1</vh></v>
<v t="ekr.20140110141116.4367"><vh>top2</vh></v>
</v>
</v>
<v t="ekr.20140121160228.4834"><vh>root_after</vh>
<v t="ekr.20140121160228.4835"><vh>aClass</vh>
<v t="ekr.20140121160228.4836"><vh>before</vh></v>
<v t="ekr.20140121160228.4837"><vh>child11</vh></v>
<v t="ekr.20140121160228.4838"><vh>child12</vh></v>
<v t="ekr.20140121160228.4839"><vh>middle</vh></v>
<v t="ekr.20140121160228.4840"><vh>child21</vh></v>
<v t="ekr.20140121160228.4841"><vh>child22</vh></v>
<v t="ekr.20140121160228.4842"><vh>after</vh></v>
<v t="ekr.20140121160228.4843"><vh>last1</vh></v>
</v>
<v t="ekr.20140121160228.4844"><vh>top1</vh></v>
<v t="ekr.20140121160228.4845"><vh>top2</vh></v>
</v>
</v>
<v t="ekr.20140110044125.4362"><vh>@test atFile.new_auto</vh></v>
<v t="ekr.20140109162112.4219"><vh>@test p.sort_key</vh></v>
<v t="ekr.20140105222052.4170"><vh>@test vc.clean_nodes (to do)</vh>
<v t="ekr.20140105222052.4171"><vh>root1</vh></v>
<v t="ekr.20140105222052.4172"><vh>root2</vh></v>
</v>
<v t="ekr.20140103102956.4142"><vh>@test vc.create_clone_links</vh>
<v t="ekr.20140103102956.4143"><vh>@clones</vh></v>
<v t="ekr.20140211090146.4438"><vh>node1</vh></v>
<v t="ekr.20140103102956.4145"><vh>root</vh>
<v t="ekr.20140211090146.4438"></v>
</v>
</v>
<v t="ekr.20140105185509.4140"><vh>@test vc.create_organizer_node</vh>
<v t="ekr.20140105190941.4170"><vh>root_restore</vh>
<v t="ekr.20140105190941.4171"><vh>aClass</vh>
<v t="ekr.20140105190941.4172"><vh>before</vh></v>
<v t="ekr.20140105190941.4174"><vh>child1</vh></v>
<v t="ekr.20140105190941.4175"><vh>extra2</vh></v>
<v t="ekr.20140105190941.4176"><vh>child2</vh></v>
<v t="ekr.20140105190941.4178"><vh>after</vh></v>
</v>
</v>
<v t="ekr.20140105185509.4141"><vh>root_before</vh>
<v t="ekr.20140105185509.4142"><vh>aClass</vh>
<v t="ekr.20140105185509.4143"><vh>before</vh></v>
<v t="ekr.20140105185509.4144"><vh>organizer node</vh>
<v t="ekr.20140105185509.4145"><vh>child1</vh></v>
<v t="ekr.20140113034711.4461"><vh>extra2</vh></v>
<v t="ekr.20140105185509.4146"><vh>child2</vh></v>
</v>
<v t="ekr.20140105185509.4147"><vh>after</vh></v>
</v>
</v>
<v t="ekr.20140211090146.4446"><vh>root_after</vh>
<v t="ekr.20140211090146.4447"><vh>aClass</vh>
<v t="ekr.20140211090146.4448"><vh>before</vh></v>
<v t="ekr.20140211090146.4459"><vh>organizer node</vh>
<v t="ekr.20140211090146.4460"><vh>child1</vh></v>
<v t="ekr.20140211090146.4461"><vh>extra2</vh></v>
<v t="ekr.20140211090146.4462"><vh>child2</vh></v>
</v>
<v t="ekr.20140211090146.4452"><vh>after</vh></v>
</v>
</v>
</v>
<v t="ekr.20140106094713.4176"><vh>@test vc.drop_all_organizers_in_unl</vh></v>
<v t="ekr.20140103102956.4146"><vh>@test vc.find_absolute_unl_node</vh></v>
<v t="ekr.20140103102956.4165"><vh>@test vc.find_at_views_node</vh></v>
<v t="ekr.20140103102956.4147"><vh>@test vc.find_position_for_relative_unl</vh>
<v t="ekr.20140103102956.4148"><vh>node1</vh>
<v t="ekr.20140103102956.4149"><vh>child11</vh></v>
<v t="ekr.20140103102956.4150"><vh>child12</vh></v>
</v>
<v t="ekr.20140103102956.4151"><vh>node2</vh>
<v t="ekr.20140103102956.4152"><vh>child21</vh></v>
<v t="ekr.20140103102956.4153"><vh>child22</vh></v>
</v>
</v>
<v t="ekr.20140103102956.4154"><vh>@test vc.find_representative_node</vh>
<v t="ekr.20140103102956.4155"><vh>root</vh>
<v t="ekr.20140103102956.4157"><vh>clone</vh></v>
</v>
<v t="ekr.20140103102956.4157"></v>
</v>
<v t="ekr.20140103102956.4158"><vh>@test vc.find_views/clones/organizers_node</vh>
<v t="ekr.20140103102956.4159"><vh>root</vh>
<v t="ekr.20140103102956.4160"><vh>aClass</vh>
<v t="ekr.20140103102956.4164"><vh>clone</vh></v>
</v>
<v t="ekr.20140103102956.4162"><vh>organizer node</vh>
<v t="ekr.20140103102956.4163"><vh>child2</vh></v>
</v>
</v>
<v t="ekr.20140103102956.4164"></v>
</v>
<v t="ekr.20140105185509.4198"><vh>@test vc.has_*_node</vh>
<v t="ekr.20140105185509.4199"><vh>root</vh>
<v t="ekr.20140105185509.4200"><vh>aClass</vh>
<v t="ekr.20140105185509.4204"><vh>clone-test</vh></v>
<v t="ekr.20140105185509.4202"><vh>organizer node</vh>
<v t="ekr.20140105185509.4203"><vh>child2</vh></v>
</v>
</v>
</v>
<v t="ekr.20140105185509.4204"></v>
</v>
<v t="ekr.20140103102956.4166"><vh>@test vc.is_at_auto_node</vh></v>
<v t="ekr.20140103102956.4167"><vh>@test vc.is_organizer_node</vh>
<v t="ekr.20140103102956.4168"><vh>test python True</vh>
<v t="ekr.20140103102956.4169"><vh>child</vh></v>
</v>
<v t="ekr.20140103102956.4170"><vh>test python 2</vh>
<v t="ekr.20140103102956.4171"><vh>child</vh></v>
</v>
<v t="ekr.20140103102956.4172"><vh>test html True</vh>
<v t="ekr.20140103102956.4173"><vh>child</vh></v>
</v>
<v t="ekr.20140103102956.4174"><vh>test html 2</vh>
<v t="ekr.20140103102956.4175"><vh>child</vh></v>
</v>
</v>
<v t="ekr.20140103102956.4176"><vh>@test vc.unl</vh></v>
<v t="ekr.20140105185509.4181"><vh>@test vc.update_before_write_at_auto_file</vh>
<v t="ekr.20140105185509.4182"><vh>root</vh>
<v t="ekr.20140105185509.4183"><vh>aClass</vh>
<v t="ekr.20140105185509.4187"><vh>clone</vh></v>
</v>
<v t="ekr.20140105185509.4185"><vh>organizer node</vh>
<v t="ekr.20140105185509.4216"><vh>child1</vh></v>
<v t="ekr.20140105185509.4186"><vh>child2</vh></v>
</v>
</v>
<v t="ekr.20140105185509.4187"></v>
</v>
<v t="ekr.20140103102956.4184"><vh>@test view-pack &amp; view_unpack</vh>
<v t="ekr.20140103102956.4188"><vh>clone</vh></v>
<v t="ekr.20140103102956.4186"><vh>@view test</vh>
<v t="ekr.20140103102956.4187"><vh>not a clone</vh></v>
<v t="ekr.20140103102956.4188"></v>
</v>
</v>
<v t="ekr.20140106135225.4203"><vh>@test vc.create_organizer_node (nested organizers)</vh>
<v t="ekr.20140106135225.4204"><vh>root_restore</vh>
<v t="ekr.20140106135225.4285"><vh>aClass</vh>
<v t="ekr.20140106135225.4286"><vh>before</vh></v>
<v t="ekr.20140106135225.4289"><vh>child11</vh></v>
<v t="ekr.20140106135225.4290"><vh>child12</vh></v>
<v t="ekr.20140108143431.4248"><vh>middle</vh></v>
<v t="ekr.20140106135225.4292"><vh>child21</vh></v>
<v t="ekr.20140106135225.4293"><vh>child22</vh></v>
<v t="ekr.20140106135225.4294"><vh>after</vh></v>
<v t="ekr.20140109035139.4277"><vh>last1</vh></v>
</v>
<v t="ekr.20140109180433.4248"><vh>top1</vh></v>
<v t="ekr.20140109180433.4249"><vh>top2</vh></v>
</v>
<v t="ekr.20140106135225.4213"><vh>root_before</vh>
<v t="ekr.20140106135225.4214"><vh>aClass</vh>
<v t="ekr.20140106135225.4215"><vh>before</vh></v>
<v t="ekr.20140106135225.4216"><vh>organizer node</vh>
<v t="ekr.20140106135225.4229"><vh>inner org1</vh>
<v t="ekr.20140106135225.4217"><vh>child11</vh></v>
<v t="ekr.20140106135225.4218"><vh>child12</vh></v>
</v>
<v t="ekr.20140108143431.4249"><vh>middle</vh></v>
<v t="ekr.20140106135225.4233"><vh>inner org2</vh>
<v t="ekr.20140106135225.4234"><vh>child21</vh></v>
<v t="ekr.20140106135225.4235"><vh>child22</vh></v>
</v>
</v>
<v t="ekr.20140106135225.4219"><vh>after</vh></v>
<v t="ekr.20140109035139.4274"><vh>last organizer</vh>
<v t="ekr.20140109035139.4276"><vh>last1</vh></v>
</v>
</v>
<v t="ekr.20140109180433.4253"><vh>top-level</vh>
<v t="ekr.20140109180433.4254"><vh>top1</vh></v>
<v t="ekr.20140109180433.4255"><vh>top2</vh></v>
</v>
</v>
<v t="ekr.20140211090146.4494"><vh>root_after</vh>
<v t="ekr.20140211090146.4495"><vh>aClass</vh>
<v t="ekr.20140211090146.4496"><vh>before</vh></v>
<v t="ekr.20140211090146.4516"><vh>organizer node</vh>
<v t="ekr.20140211090146.4518"><vh>inner org1</vh>
<v t="ekr.20140211090146.4526"><vh>child11</vh></v>
<v t="ekr.20140211090146.4527"><vh>child12</vh></v>
</v>
<v t="ekr.20140211090146.4525"><vh>middle</vh></v>
<v t="ekr.20140211090146.4520"><vh>inner org2</vh>
<v t="ekr.20140211090146.4528"><vh>child21</vh></v>
<v t="ekr.20140211090146.4529"><vh>child22</vh></v>
</v>
</v>
<v t="ekr.20140211090146.4502"><vh>after</vh></v>
<v t="ekr.20140211090146.4522"><vh>last organizer</vh>
<v t="ekr.20140211090146.4530"><vh>last1</vh></v>
</v>
</v>
</v>
</v>
<v t="ekr.20140111164124.4414"><vh>@test vc.create_organizer_node (intermediate organizers)</vh>
<v t="ekr.20140111164124.4415"><vh>root_restore</vh>
<v t="ekr.20140111164124.4416"><vh>aClass</vh>
<v t="ekr.20140111164124.4417"><vh>before</vh></v>
<v t="ekr.20140111164124.4418"><vh>child11</vh></v>
<v t="ekr.20140111164124.4419"><vh>child12</vh></v>
<v t="ekr.20140111164124.4420"><vh>middle</vh></v>
<v t="ekr.20140111164124.4421"><vh>child21</vh></v>
<v t="ekr.20140111164124.4422"><vh>child22</vh></v>
<v t="ekr.20140111164124.4423"><vh>after</vh></v>
<v t="ekr.20140111164124.4424"><vh>last1</vh></v>
</v>
<v t="ekr.20140111164124.4425"><vh>top1</vh></v>
<v t="ekr.20140111164124.4426"><vh>top2</vh></v>
</v>
<v t="ekr.20140111164124.4427"><vh>root_before</vh>
<v t="ekr.20140111164124.4428"><vh>aClass</vh>
<v t="ekr.20140111164124.4429"><vh>before</vh></v>
<v t="ekr.20140111164124.4430"><vh>organizer node</vh>
<v t="ekr.20140111164124.4431"><vh>inner org1</vh>
<v t="ekr.20140111164124.4432"><vh>child11</vh></v>
<v t="ekr.20140111164124.4433"><vh>child12</vh></v>
</v>
<v t="ekr.20140111164124.4434"><vh>middle</vh></v>
<v t="ekr.20140111164124.4435"><vh>inner org2</vh>
<v t="ekr.20140111164124.4436"><vh>child21</vh></v>
<v t="ekr.20140111164124.4437"><vh>child22</vh></v>
</v>
</v>
<v t="ekr.20140111164124.4438"><vh>after</vh></v>
<v t="ekr.20140111164124.4439"><vh>last organizer</vh>
<v t="ekr.20140111164124.4440"><vh>last1</vh></v>
</v>
</v>
<v t="ekr.20140111164124.4441"><vh>top-level</vh>
<v t="ekr.20140111164124.4442"><vh>top1</vh></v>
<v t="ekr.20140111164124.4443"><vh>top2</vh></v>
</v>
</v>
<v t="ekr.20140211090146.4545"><vh>root_after</vh>
<v t="ekr.20140211090146.4546"><vh>aClass</vh>
<v t="ekr.20140211090146.4547"><vh>before</vh></v>
<v t="ekr.20140211090146.4567"><vh>organizer node</vh>
<v t="ekr.20140211090146.4569"><vh>inner org1</vh>
<v t="ekr.20140211090146.4577"><vh>child11</vh></v>
<v t="ekr.20140211090146.4578"><vh>child12</vh></v>
</v>
<v t="ekr.20140211090146.4576"><vh>middle</vh></v>
<v t="ekr.20140211090146.4571"><vh>inner org2</vh>
<v t="ekr.20140211090146.4579"><vh>child21</vh></v>
<v t="ekr.20140211090146.4580"><vh>child22</vh></v>
</v>
</v>
<v t="ekr.20140211090146.4553"><vh>after</vh></v>
<v t="ekr.20140211090146.4573"><vh>last organizer</vh>
<v t="ekr.20140211090146.4581"><vh>last1</vh></v>
</v>
</v>
</v>
</v>
</v>
<v t="ekr.20131111160618.4261"><vh>@ignore leoVim</vh>
<v t="ekr.20131111162157.4276"><vh>Unused</vh>
<v t="ekr.20131111162157.4270"><vh>@@test command regex</vh></v>
<v t="ekr.20131111162157.4272"><vh>@@test motion regex</vh></v>
<v t="ekr.20131111162157.4271"><vh>@@test vim motion</vh></v>
</v>
<v t="ekr.20131111155107.4239"><vh>@test h middle of line</vh>
<v t="ekr.20131111155107.4240"><vh>work</vh></v>
<v t="ekr.20131111155107.4241"><vh>before sel=1.5,1.5</vh></v>
<v t="ekr.20131111155107.4242"><vh>after sel=1.4,1.4</vh></v>
</v>
<v t="ekr.20131111162157.4275"><vh>@test vr.exec_</vh></v>
<v t="ekr.20131113071911.4281"><vh>@test vr.scan</vh>
<v t="ekr.20131113071911.4282"><vh>&lt;&lt; define test tables &gt;&gt;</vh></v>
</v>
</v>
<v t="ekr.20080703104536.1"><vh>@ignore mini tests</vh>
<v t="ekr.20100203163606.5365"><vh>2to3 script</vh></v>
<v t="ekr.20100127162342.5123"><vh>Import all plugins script</vh></v>
<v t="ekr.20051104081502.99"><vh>Manual tests...</vh>
<v t="ekr.20051104081502.101"><vh>Other Reformat Paragraph tests</vh></v>
<v t="ekr.20051104081502.102"><vh>Test of @tabwidth</vh></v>
<v t="ekr.20051104081502.103"><vh>Test of pasting into big node</vh></v>
<v t="ekr.20051104081502.104"><vh>Test of Remove sentinels</vh></v>
<v t="ekr.20051104081502.105"><vh>Test new docutils stull</vh></v>
<v t="ekr.20040712101754.221"><vh>Manual test of TM.replaceOutline</vh>
<v t="ekr.20040712101754.222"><vh>outline1</vh>
<v t="ekr.20040712101754.223"><vh>a</vh></v>
</v>
<v t="ekr.20040712101754.224"><vh>outline2</vh>
<v t="ekr.20040712101754.225"><vh>b</vh></v>
</v>
</v>
</v>
<v t="ekr.20051104081502.220"><vh>Mini test arguments to hooks</vh>
<v t="ekr.20051104081502.221"><vh>&lt;&lt; imports &gt;&gt;</vh></v>
<v t="ekr.20051104081502.222"><vh>&lt;&lt; define hookData &gt;&gt;</vh></v>
<v t="ekr.20051104081502.223"><vh>&lt;&lt; define typeData &gt;&gt;</vh></v>
<v t="ekr.20051104081502.224"><vh>&lt;&lt; defineCheckHook &gt;&gt;</vh></v>
<v t="ekr.20051104081502.225"><vh>checkOneHook</vh></v>
</v>
<v t="ekr.20111121113227.4035"><vh>Mini test of add-editor</vh></v>
<v t="ekr.20051104081502.312"><vh>Mini test of g.es_exception</vh></v>
<v t="ekr.20051104081502.311"><vh>Mini test of g.pdb</vh></v>
<v t="ekr.20111108170253.3968"><vh>Mini test of unicode stuff</vh></v>
<v t="ekr.20111121081052.3909"><vh>Mini test that g.es leaves focus unchanged</vh></v>
<v t="ekr.20111121090700.3914"><vh>mini test that print-bindings puts results in Bindings tab</vh></v>
<v t="ekr.20051104081502.106"><vh>Mini tests of script buttons</vh>
<v t="ekr.20051104081502.107"><vh>Redundant: @suite run all doctests in @file nodes</vh></v>
<v t="ekr.20051104081502.108"><vh>runProfile button mini-test</vh></v>
<v t="ekr.20051104081502.109"><vh>runTimeit mini-test</vh></v>
<v t="ekr.20051104081502.110"><vh>profile redraws</vh></v>
</v>
<v t="ekr.20051104081502"><vh>Other tests</vh>
<v t="ekr.20051104081502.542"><vh>@@nosent test-niceNosent</vh>
<v t="ekr.20051104081502.543"><vh>part 1</vh></v>
<v t="ekr.20051104081502.544"><vh>part 2</vh></v>
<v t="ekr.20051104081502.545"><vh>part 3</vh></v>
</v>
<v t="ekr.20051104081502.320"><vh>@nowrap tests</vh></v>
<v t="ekr.20051104081502.22"><vh>Experiments</vh>
<v t="ekr.20051104081502.23"><vh>Test of moving positions</vh></v>
<v t="ekr.20051104081502.24"><vh>Test of using an iterator inside a list comprehension</vh></v>
<v t="ekr.20051104081502.25"><vh>Test of using c.allNodes_iter to create a list of all positions</vh></v>
<v t="ekr.20051104081502.26"><vh>Creating a list of distinct vnodes</vh></v>
<v t="ekr.20051104081502.28"><vh>test of list comparisons</vh></v>
<v t="ekr.20051104081502.29"><vh>test that childIndex doesn't mess with p</vh></v>
<v t="ekr.20051104081502.30"><vh>Test of __cmp__ vrs equal</vh></v>
<v t="ekr.20051104081502.31"><vh>Test print</vh></v>
<v t="ekr.20051104081502.32"><vh>String-based imports...</vh>
<v t="ekr.20051104081502.33"><vh>import from string</vh>
<v t="ekr.20051104081502.34"><vh>@@test import from string</vh></v>
</v>
<v t="ekr.20051104081502.35"><vh>Subclass the file type for use with imp module</vh></v>
<v t="ekr.20051104081502.36"><vh>Use parser module to simulate import from string</vh>
<v t="ekr.20051104081502.37"><vh>test1</vh></v>
</v>
</v>
</v>
<v t="ekr.20051104081502.209"><vh>Make sure openWith changes are benign</vh></v>
<v t="ekr.20051104081502.111"><vh>Perfect import stuff...</vh>
<v t="ekr.20051104081502.112"><vh>Mulder Update script</vh>
<v t="ekr.20051104081502.113"><vh>sync</vh>
<v t="ekr.20051104081502.114"><vh>&lt;&lt; compute sourcetime and targettime &gt;&gt;</vh></v>
<v t="ekr.20051104081502.115"><vh>&lt;&lt; compute operation &gt;&gt;</vh></v>
</v>
</v>
<v t="ekr.20051104081502.116"><vh>Perfect Import Script</vh></v>
</v>
<v t="ekr.20051104081502.117"><vh>Printing tests...</vh>
<v t="ekr.20051104081502.118"><vh>Print findAllPotentiallyDirtyNodes</vh></v>
<v t="ekr.20051104081502.119"><vh>Print iterations: do not delete</vh>
<v t="ekr.20051104081502.120"><vh>b</vh>
<v t="ekr.20051104081502.121"><vh>c</vh>
<v t="ekr.20051104081502.122"><vh>c2</vh>
<v t="ekr.20051104081502.123"><vh>c3</vh></v>
<v t="ekr.20051104081502.124"><vh>c4</vh></v>
</v>
</v>
</v>
<v t="ekr.20051104081502.125"><vh>Clone test data</vh>
<v t="ekr.20051104081502.126"><vh>aa</vh></v>
<v t="ekr.20051104081502.127"><vh>a</vh>
<v t="ekr.20051104081502.120"></v>
</v>
<v t="ekr.20051104081502.128"><vh>d</vh>
<v t="ekr.20051104081502.127"></v>
</v>
<v t="ekr.20051104081502.129"><vh>e</vh></v>
<v t="ekr.20051104081502.130"><vh>z</vh></v>
</v>
<v t="ekr.20051104081502.131"><vh>last node</vh></v>
</v>
<v t="ekr.20051104081502.145"><vh>Print isAnyAtFileNode</vh></v>
<v t="ekr.20051104081502.146"><vh>Print fundChildrenOf and</vh></v>
<v t="ekr.20051104081502.147"><vh>Tests of pickle &amp; hexlify</vh></v>
<v t="ekr.20051104081502.148"><vh>Test of undo registration</vh></v>
<v t="ekr.20051104081502.149"><vh>Test of unknownAttributes</vh></v>
<v t="ekr.20051104081502.150"><vh>Test of "end1" hook</vh></v>
<v t="ekr.20051104081502.151"><vh>Print timestamps of all nodes</vh></v>
<v t="ekr.20051104081502.152"><vh>test of focus</vh></v>
<v t="ekr.20051104081502.153"><vh>Using a generator instead of readLinesClass</vh></v>
<v t="ekr.20051104081502.154"><vh>Test of better error messages in Execute Script command</vh>
<v t="ekr.20051104081502.155"><vh>Contains error</vh></v>
</v>
<v t="ekr.20051104081502.157"><vh>print all docstrings from a module</vh>
<v t="ekr.20051104081502.158"><vh>&lt;&lt; print names sorted by type &gt;&gt;</vh></v>
</v>
</v>
<v t="ekr.20051104081502.216"><vh>Registering &amp; unregistering the "new" drawing hooks</vh>
<v t="ekr.20051104081502.217"><vh>Register all new hooks</vh></v>
<v t="ekr.20051104081502.218"><vh>Unregister all new hooks</vh></v>
<v t="ekr.20051104081502.219"><vh>Print all new hooks</vh></v>
</v>
<v t="ekr.20051104081502.538"><vh>ReportLab sample scripts</vh>
<v t="ekr.20051104081502.539"><vh>text</vh></v>
<v t="ekr.20051104081502.540"><vh>pencil</vh></v>
<v t="ekr.20051104081502.541"><vh>penciltip</vh></v>
</v>
<v t="ekr.20051104081502.272"><vh>Standalone imports</vh>
<v t="ekr.20051104081502.273"><vh>test that of standalone imports of leo files</vh></v>
<v t="ekr.20051104081502.274"><vh>Script to run in Idle</vh></v>
</v>
<v t="ekr.20051104081502.307"><vh>test local settings (c.redirect_execute_script_output_to_log_pane)</vh></v>
<v t="ekr.20051104081502.164"><vh>test of 4.3 str_ attributes</vh>
<v t="ekr.20051104081502.165"><vh>set</vh></v>
<v t="ekr.20051104081502.166"><vh>get</vh></v>
</v>
<v t="ekr.20051104081502.316"><vh>test of an exception in another module</vh></v>
<v t="ekr.20051104081502.210"><vh>Test of autocompleter</vh></v>
<v t="ekr.20051104081502.322"><vh>Test of g.getScript with forcePythonSentinels = False</vh>
<v t="ekr.20051104081502.323"><vh>g.getScript</vh></v>
<v t="ekr.20051104081502.324"><vh>html stuff</vh>
<v t="ekr.20051104081502.325"><vh>body</vh></v>
</v>
</v>
<v t="ekr.20051104081502.315"><vh>test of NameError traceback</vh></v>
<v t="ekr.20051104081502.318"><vh>Test of os.spawnv calls to c.openWith</vh></v>
<v t="ekr.20051104081502.321"><vh>Test of redirected scipt with error</vh></v>
<v t="ekr.20051104081502.183"><vh>Test of reportBadChars</vh></v>
<v t="ekr.20051104081502.234"><vh>test of tab_width &amp; tab_width ivars</vh></v>
<v t="ekr.20051104081502.211"><vh>Test of template plugin</vh>
<v t="ekr.20051104081502.213"><vh>A node that uses the template</vh></v>
</v>
<v t="ekr.20051104081502.214"><vh>test of using changes to Go To Line number to handle scripts</vh>
<v t="ekr.20051104081502.215"><vh>node that throws exception</vh></v>
</v>
<v t="ekr.20051104081502.547"><vh>Test of warnings of conflicting shortcuts</vh></v>
<v t="ekr.20051104081502.551"><vh>test k.registerCommand</vh></v>
<v t="ekr.20051104081502.226"><vh>Tests of leoGlobals</vh>
<v t="ekr.20051104081502.227"><vh>@test g.rawPrint</vh></v>
<v t="ekr.20051104081502.232"><vh>test of g.pdb</vh></v>
<v t="ekr.20051104081502.233"><vh>Test of g.app.debugSwitch</vh></v>
</v>
<v t="ekr.20051104081502.326"><vh>Tests of rst3 plugin</vh>
<v t="ekr.20051104081502.327"><vh>@rst ../doc/ListManagerDocs.html</vh>
<v t="ekr.20051104081502.328"><vh>wxListManager.py</vh>
<v t="ekr.20051104081502.329"><vh>Initial stuff</vh>
<v t="ekr.20051104081502.330"><vh>Module Imports</vh>
<v t="ekr.20051104081502.331"><vh>@rst-no-head About imports</vh></v>
</v>
<v t="ekr.20051104081502.332"><vh>Constants</vh></v>
<v t="ekr.20051104081502.333"><vh>Menu IDs</vh></v>
<v t="ekr.20051104081502.334"><vh>Read Config File</vh>
<v t="ekr.20051104081502.335"><vh>@rst-no-head About configuration files</vh></v>
</v>
</v>
<v t="ekr.20051104081502.336"><vh>class ListManager</vh>
<v t="ekr.20051104081502.337"><vh>Instantiation</vh>
<v t="ekr.20051104081502.338"><vh>def __init__</vh>
<v t="ekr.20051104081502.339"><vh>@rst-no-head About the ctor</vh></v>
<v t="ekr.20051104081502.340"><vh>&lt;&lt; List Manager Attributes &gt;&gt;</vh>
<v t="ekr.20051104081502.341"><vh>@rst</vh></v>
</v>
<v t="ekr.20051104081502.342"><vh>&lt;&lt; Menu Setup &gt;&gt;</vh>
<v t="ekr.20051104081502.343"><vh>@rst</vh></v>
</v>
<v t="ekr.20051104081502.344"><vh>&lt;&lt; Toolbar Setup &gt;&gt;</vh></v>
<v t="ekr.20051104081502.346"><vh>&lt;&lt; Menu/Toolbar Events &gt;&gt;</vh></v>
<v t="ekr.20051104081502.348"><vh>&lt;&lt; Create Controls&gt;&gt;</vh></v>
<v t="ekr.20051104081502.350"><vh>&lt;&lt; Other Events &gt;&gt;</vh></v>
<v t="ekr.20051104081502.352"><vh>&lt;&lt; Layout Stuff &gt;&gt;</vh></v>
<v t="ekr.20051104081502.354"><vh>&lt;&lt; GUI Instance Objects &gt;&gt;</vh></v>
<v t="ekr.20051104081502.356"><vh>&lt;&lt; Create Socket &gt;&gt;</vh></v>
<v t="ekr.20051104081502.358"><vh>&lt;&lt; Load Recent Files &gt;&gt;</vh></v>
<v t="ekr.20051104081502.360"><vh>&lt;&lt; Idle Timer &gt;&gt;</vh></v>
</v>
</v>
<v t="ekr.20051104081502.362"><vh>Ownerlist creation methods (used by thread)</vh>
<v t="ekr.20051104081502.364"><vh>def createownerlist</vh></v>
<v t="ekr.20051104081502.366"><vh>def createownerdialog</vh></v>
</v>
<v t="ekr.20051104081502.368"><vh>Notebook methods</vh>
<v t="ekr.20051104081502.370"><vh>def CreateNewNotebookPage</vh>
<v t="ekr.20051104081502.372"><vh>&lt;&lt; Fill OwnerListBox &gt;&gt;</vh></v>
<v t="ekr.20051104081502.374"><vh>&lt;&lt; ListControl Events &gt;&gt;</vh></v>
</v>
<v t="ekr.20051104081502.376"><vh>def OnPageChange</vh>
<v t="ekr.20051104081502.378"><vh>&lt;&lt; Find Highlighted Row &gt;&gt;</vh></v>
<v t="ekr.20051104081502.380"><vh>&lt;&lt; Update Title &gt;&gt;</vh></v>
</v>
</v>
<v t="ekr.20051104081502.382"><vh>Tickler methods</vh>
<v t="ekr.20051104081502.383"><vh>def OnShowTickler</vh></v>
<v t="ekr.20051104081502.384"><vh>def OnActivateTickler</vh></v>
</v>
<v t="ekr.20051104081502.385"><vh>Email methods</vh>
<v t="ekr.20051104081502.386"><vh>OnMailItem</vh></v>
<v t="ekr.20051104081502.387"><vh>OnMailView</vh></v>
</v>
<v t="ekr.20051104081502.388"><vh>Cut/Copy/Paste methods</vh>
<v t="ekr.20051104081502.389"><vh>OnCopyItems</vh>
<v t="ekr.20051104081502.390"><vh>&lt;&lt; Find Highlighted Items &gt;&gt;</vh></v>
</v>
<v t="ekr.20051104081502.391"><vh>OnPasteItems</vh></v>
<v t="ekr.20051104081502.392"><vh>OnDeleteItems</vh></v>
</v>
<v t="ekr.20051104081502.393"><vh>MouseDown methods</vh>
<v t="ekr.20051104081502.394"><vh>OnLeftDown (Action depends on x coordinate)</vh></v>
<v t="ekr.20051104081502.395"><vh>OnRightDown (Display popup sendto menu)</vh></v>
</v>
<v t="ekr.20051104081502.396"><vh>Move/Combine items methods</vh>
<v t="ekr.20051104081502.397"><vh>OnCombineItems</vh></v>
<v t="ekr.20051104081502.398"><vh>OnMoveToList</vh></v>
<v t="ekr.20051104081502.399"><vh>OnMoveToSpecificList</vh></v>
</v>
<v t="ekr.20051104081502.400"><vh>Change/update items methods</vh>
<v t="ekr.20051104081502.401"><vh>OnToggleFinished</vh>
<v t="ekr.20051104081502.402"><vh>&lt;&lt; draw item &gt;&gt;</vh></v>
</v>
<v t="ekr.20051104081502.403"><vh>OnPriority</vh>
<v t="ekr.20051104081502.404"><vh>&lt;&lt; draw item &gt;&gt;</vh></v>
</v>
<v t="ekr.20051104081502.405"><vh>Inplace Edit Methods</vh>
<v t="ekr.20051104081502.406"><vh>OnDisplayInPlaceEditor</vh></v>
<v t="ekr.20051104081502.407"><vh>OnCloseInPlaceEditor</vh></v>
</v>
<v t="ekr.20051104081502.408"><vh>OnDueDate</vh></v>
<v t="ekr.20051104081502.409"><vh>OnEditOwner</vh>
<v t="ekr.20051104081502.410"><vh>&lt;&lt; Common Owner Code &gt;&gt;</vh></v>
</v>
<v t="ekr.20051104081502.411"><vh>OnUpdate</vh>
<v t="ekr.20051104081502.412"><vh>&lt;&lt; Common Owner Code &gt;&gt;</vh></v>
</v>
<v t="ekr.20051104081502.413"><vh>OnNewItem</vh>
<v t="ekr.20051104081502.414"><vh>&lt;&lt; Clear data fields &gt;&gt;</vh></v>
</v>
<v t="ekr.20051104081502.415"><vh>Conflict (not in use)</vh></v>
<v t="ekr.20051104081502.416"><vh>OnEditNote</vh></v>
</v>
<v t="ekr.20051104081502.417"><vh>File menu methods</vh>
<v t="ekr.20051104081502.418"><vh>OnNewList</vh></v>
<v t="ekr.20051104081502.419"><vh>OnFileList</vh></v>
<v t="ekr.20051104081502.420"><vh>OnOpenList</vh></v>
<v t="ekr.20051104081502.421"><vh>OnDeleteList</vh></v>
<v t="ekr.20051104081502.422"><vh>OnCloseList</vh></v>
<v t="ekr.20051104081502.423"><vh>OnCloseAll</vh></v>
<v t="ekr.20051104081502.424"><vh>OnSaveAsText</vh></v>
<v t="ekr.20051104081502.425"><vh>OnArchive</vh></v>
<v t="ekr.20051104081502.426"><vh>OnWorkOffline</vh></v>
</v>
<v t="ekr.20051104081502.428"><vh>Display methods</vh>
<v t="ekr.20051104081502.429"><vh>OnItemSelected</vh></v>
<v t="ekr.20051104081502.430"><vh>OnItemActivated</vh></v>
<v t="ekr.20051104081502.431"><vh>OnShowAll</vh></v>
<v t="ekr.20051104081502.432"><vh>OnRefresh</vh></v>
<v t="ekr.20051104081502.433"><vh>OnFilterOwners</vh></v>
<v t="ekr.20051104081502.434"><vh>OnColumnClick (to sort columns)</vh></v>
<v t="ekr.20051104081502.435"><vh>OnShowFinished</vh></v>
<v t="ekr.20051104081502.436"><vh>OnColumnRightClick (popup to change date displayed)</vh></v>
<v t="ekr.20051104081502.437"><vh>OnDisplayDateCategory</vh></v>
<v t="ekr.20051104081502.438"><vh>ChangeDateDisplayed</vh></v>
<v t="ekr.20051104081502.439"><vh>DisplayList</vh>
<v t="ekr.20051104081502.440"><vh>&lt;&lt; draw item &gt;&gt;</vh></v>
</v>
</v>
<v t="ekr.20051104081502.441"><vh>Printing methods</vh>
<v t="ekr.20051104081502.442"><vh>OnPageSetup</vh></v>
<v t="ekr.20051104081502.443"><vh>OnPrint</vh></v>
</v>
<v t="ekr.20051104081502.444"><vh>Exiting methods</vh>
<v t="ekr.20051104081502.445"><vh>OnWindowExit</vh></v>
<v t="ekr.20051104081502.446"><vh>OnExit</vh>
<v t="ekr.20051104081502.447"><vh>&lt;&lt;save configuration file&gt;&gt;</vh></v>
</v>
</v>
<v t="ekr.20051104081502.448"><vh>Find methods</vh>
<v t="ekr.20051104081502.449"><vh>OnFind</vh></v>
<v t="ekr.20051104081502.450"><vh>FindString</vh></v>
<v t="ekr.20051104081502.451"><vh>FindNode</vh></v>
</v>
<v t="ekr.20051104081502.452"><vh>Database-related methods</vh>
<v t="ekr.20051104081502.453"><vh>GetCursor</vh></v>
<v t="ekr.20051104081502.454"><vh>GetNote</vh></v>
<v t="ekr.20051104081502.455"><vh>CreateTable</vh></v>
<v t="ekr.20051104081502.456"><vh>ReadFromDB (returns db results)</vh></v>
<v t="ekr.20051104081502.457"><vh>CreateAndDisplayList (returns Item List)</vh>
<v t="ekr.20051104081502.458"><vh>&lt;&lt; assign item attributes &gt;&gt;</vh></v>
<v t="ekr.20051104081502.459"><vh>&lt;&lt; draw item &gt;&gt;</vh></v>
</v>
<v t="ekr.20051104081502.460"><vh>OnSync</vh></v>
<v t="ekr.20051104081502.461"><vh>TimeStamper</vh></v>
</v>
<v t="ekr.20051104081502.462"><vh>Evaluate methods</vh>
<v t="ekr.20051104081502.463"><vh>OnShowEvaluate</vh></v>
<v t="ekr.20051104081502.464"><vh>OnEvaluate</vh></v>
</v>
<v t="ekr.20051104081502.465"><vh>Help menu methods</vh>
<v t="ekr.20051104081502.466"><vh>OnShowAbout</vh></v>
<v t="ekr.20051104081502.467"><vh>OnShowHelp</vh></v>
</v>
<v t="ekr.20051104081502.468"><vh>GetUID</vh></v>
<v t="ekr.20051104081502.469"><vh>OnIdle</vh>
<v t="ekr.20051104081502.471"><vh>&lt;&lt; Check for Transfers From Outlook &gt;&gt;</vh></v>
<v t="ekr.20051104081502.473"><vh>&lt;&lt; Check if Edited File has Changed &gt;&gt;</vh></v>
</v>
</v>
<v t="ekr.20051104081502.475"><vh>class ListCtrl</vh>
<v t="ekr.20051104081502.476"><vh>__init__</vh></v>
<v t="ekr.20051104081502.477"><vh>SetUpColumns</vh></v>
<v t="ekr.20051104081502.478"><vh>OnColBeginDrag</vh></v>
</v>
<v t="ekr.20051104081502.479"><vh>class MyApp</vh>
<v t="ekr.20051104081502.480"><vh>OnInit</vh></v>
</v>
<v t="ekr.20051104081502.481"><vh>class Logger</vh></v>
<v t="ekr.20051104081502.482"><vh>run</vh></v>
</v>
<v t="ekr.20051104081502.483"><vh>LMDialogs.py</vh>
<v t="ekr.20051104081502.484"><vh>class PopDialog</vh>
<v t="ekr.20051104081502.485"><vh>__init__</vh></v>
<v t="ekr.20051104081502.486"><vh>OnLeftDown</vh></v>
<v t="ekr.20051104081502.487"><vh>OnForward</vh></v>
<v t="ekr.20051104081502.488"><vh>OnMail</vh></v>
</v>
<v t="ekr.20051104081502.489"><vh>class StartupDialog</vh>
<v t="ekr.20051104081502.490"><vh>__init__</vh></v>
<v t="ekr.20051104081502.491"><vh>OnSelection</vh></v>
</v>
<v t="ekr.20051104081502.492"><vh>class ModifierDialog</vh>
<v t="ekr.20051104081502.493"><vh>__init__</vh></v>
<v t="ekr.20051104081502.494"><vh>GetUserInput</vh></v>
<v t="ekr.20051104081502.495"><vh>SelectCurrent</vh></v>
<v t="ekr.20051104081502.496"><vh>ClearSelections</vh></v>
</v>
<v t="ekr.20051104081502.497"><vh>class MailDialog</vh>
<v t="ekr.20051104081502.498"><vh>__init__</vh></v>
</v>
<v t="ekr.20051104081502.499"><vh>class CalendarDialog</vh>
<v t="ekr.20051104081502.500"><vh>__init__</vh></v>
<v t="ekr.20051104081502.501"><vh>OnCalSelected</vh></v>
<v t="ekr.20051104081502.502"><vh>OnChangeMonth</vh></v>
<v t="ekr.20051104081502.503"><vh>OnCloseWindow</vh></v>
<v t="ekr.20051104081502.504"><vh>GetDate</vh></v>
</v>
<v t="ekr.20051104081502.505"><vh>class FindDialog</vh>
<v t="ekr.20051104081502.506"><vh>__init__</vh></v>
</v>
<v t="ekr.20051104081502.507"><vh>class EvalDialog</vh>
<v t="ekr.20051104081502.508"><vh>__init__</vh></v>
<v t="ekr.20051104081502.509"><vh>PostOKEvent</vh></v>
</v>
<v t="ekr.20051104081502.510"><vh>class LoggerDialog</vh>
<v t="ekr.20051104081502.511"><vh>__init__</vh></v>
<v t="ekr.20051104081502.512"><vh>OnSave</vh></v>
</v>
<v t="ekr.20051104081502.513"><vh>class FinishedDialog</vh>
<v t="ekr.20051104081502.514"><vh>__init__</vh></v>
<v t="ekr.20051104081502.515"><vh>OnSpin</vh></v>
<v t="ekr.20051104081502.516"><vh>OnCheck</vh></v>
</v>
<v t="ekr.20051104081502.517"><vh>class TreeDialog</vh>
<v t="ekr.20051104081502.518"><vh>__init__</vh></v>
<v t="ekr.20051104081502.519"><vh>OnLeftDClick:</vh></v>
</v>
</v>
<v t="ekr.20051104081502.520"><vh>outlookAddin.py</vh>
<v t="ekr.20051104081502.521"><vh>&lt;&lt; outlookAddin declarations &gt;&gt;</vh></v>
<v t="ekr.20051104081502.522"><vh>class ButtonEvent</vh>
<v t="ekr.20051104081502.523"><vh>OnClick</vh></v>
</v>
<v t="ekr.20051104081502.524"><vh>class FolderEvent</vh>
<v t="ekr.20051104081502.525"><vh>OnItemAdd</vh></v>
</v>
<v t="ekr.20051104081502.526"><vh>class OutlookAddin</vh>
<v t="ekr.20051104081502.527"><vh>&lt;&lt; class OutlookAddin declarations &gt;&gt;</vh></v>
<v t="ekr.20051104081502.528"><vh>OnConnection</vh></v>
<v t="ekr.20051104081502.529"><vh>OnDisconnection</vh></v>
<v t="ekr.20051104081502.530"><vh>OnAddInsUpdate</vh></v>
<v t="ekr.20051104081502.531"><vh>OnStartupComplete</vh></v>
<v t="ekr.20051104081502.532"><vh>OnBeginShutdown</vh></v>
</v>
<v t="ekr.20051104081502.533"><vh>RegisterAddin</vh></v>
<v t="ekr.20051104081502.534"><vh>UnregisterAddin</vh></v>
</v>
</v>
<v t="ekr.20051104081502.535"><vh>@rst ../doc/pdfTest.pdf</vh>
<v t="ekr.20051104081502.536"><vh>child node</vh>
<v t="ekr.20051104081502.537"><vh>@rst</vh></v>
</v>
</v>
</v>
<v t="ekr.20051104081502.546"><vh>Tests of settings when opened from another .leo file</vh></v>
<v t="ekr.20051104081502.159"><vh>Tk bindtags test</vh></v>
<v t="ekr.20051104081502.305"><vh>Unicode stuff</vh></v>
<v t="ekr.20051104081502.549"><vh>Write to log tab</vh></v>
<v t="ekr.20051104081502.548"><vh>Write to test tab</vh></v>
</v>
<v t="ekr.20100125180231.5120"><vh>Print a unicode character</vh></v>
<v t="ekr.20051104081502.108"></v>
<v t="ekr.20051104081502.109"></v>
<v t="ekr.20080821123427.2"><vh>Standard print test</vh></v>
<v t="ekr.20051104081502.160"><vh>User Icon tests</vh>
<v t="ekr.20051104081502.161"><vh>Delete user icons</vh></v>
<v t="ekr.20051104081502.162"><vh>Test of user icons</vh>
<v t="ekr.20051104081502.163"><vh>&lt;&lt; define event callbacks &gt;&gt;</vh></v>
</v>
</v>
</v>
<v t="ekr.20140906072925.5224"><vh>@ignore Scintilla fails</vh>
<v t="ekr.20100223123103.5382"><vh>@test expand/contract-pane</vh></v>
<v t="ekr.20111112171235.3854"><vh>@test add/delete html comments</vh>
<v t="ekr.20111112171235.3855"><vh>html</vh></v>
</v>
<v t="ekr.20111112171235.3858"><vh>@test add/delete python comments</vh>
<v t="ekr.20111112171235.3859"><vh>python</vh></v>
</v>
<v t="ekr.20061101121602.126"><vh>@test backward-kill-paragraph</vh>
<v t="ekr.20061101121602.127"><vh>work</vh></v>
<v t="ekr.20061101121602.128"><vh>before sel=9.0,9.0</vh></v>
<v t="ekr.20061101121602.129"><vh>after sel=7.0,7.0</vh></v>
</v>
<v t="ekr.20061101121602.154"><vh>@test center-region</vh>
<v t="ekr.20061101121602.155"><vh>work</vh></v>
<v t="ekr.20061101121602.156"><vh>before sel=1.0,7.0</vh></v>
<v t="ekr.20061101121602.157"><vh>after sel=1.0,7.0</vh></v>
</v>
<v t="ekr.20061101121602.174"><vh>@test downcase-region</vh>
<v t="ekr.20061101121602.175"><vh>work</vh></v>
<v t="ekr.20061101121602.176"><vh>before sel=3.0,4.0</vh></v>
<v t="ekr.20061101121602.177"><vh>after sel=3.0,4.0</vh></v>
</v>
<v t="ekr.20061101121602.282"><vh>@test kill-paragraph</vh>
<v t="ekr.20061101121602.283"><vh>work</vh></v>
<v t="ekr.20061101121602.285"><vh>before sel=9.0,9.0</vh></v>
<v t="ekr.20061101121602.284"><vh>after sel=8.0,8.0</vh></v>
</v>
<v t="ekr.20071113145804.4"><vh>@test selfInsertCommand-1</vh></v>
<v t="ekr.20061101121602.350"><vh>@test upcase-region</vh>
<v t="ekr.20061101121602.351"><vh>work</vh></v>
<v t="ekr.20061101121602.352"><vh>before sel=3.0,4.0</vh></v>
<v t="ekr.20061101121602.353"><vh>after sel=3.0,4.0</vh></v>
</v>
<v t="ekr.20110118082508.3766"><vh>@test reformat-paragraph paragraph 1 of 3</vh>
<v t="ekr.20110118082508.3772"><vh>work</vh></v>
<v t="ekr.20110118082508.3773"><vh>before sel=1.0,1.0</vh></v>
<v t="ekr.20110118082508.3792"><vh>after sel=11.14,11.14</vh></v>
</v>
<v t="ekr.20110118082508.3779"><vh>@test reformat-paragraph paragraph 2 of 3</vh>
<v t="ekr.20110118082508.3780"><vh>work</vh></v>
<v t="ekr.20110118082508.3781"><vh>before sel=13.0,13.0</vh></v>
<v t="ekr.20110118082508.3782"><vh>after sel=23.33,23.33</vh></v>
</v>
<v t="ekr.20110118082508.3787"><vh>@test reformat-paragraph paragraph 3 of 3</vh>
<v t="ekr.20110118082508.3788"><vh>work</vh></v>
<v t="ekr.20110118082508.3789"><vh>before sel=25.10,25.10</vh></v>
<v t="ekr.20110118082508.3790"><vh>after sel=32.11,32.11</vh></v>
</v>
<v t="ekr.20100204165850.5373"><vh>@test most toggle commands</vh></v>
<v t="ekr.20040712101754.37"><vh>@suite Edit body tests</vh>
<v t="ekr.20040712101754.38"><vh>editBodyTests</vh>
<v t="ekr.20060127120604"><vh>tempNode</vh></v>
<v t="ekr.20050417202713"><vh>addComments</vh>
<v t="ekr.20050417202713.1"><vh>before</vh></v>
<v t="ekr.20050417202713.2"><vh>after</vh></v>
<v t="ekr.20050417202713.3"><vh>selection</vh></v>
</v>
<v t="ekr.20050417204940"><vh>convertAllBlanks</vh>
<v t="ekr.20050417204940.1"><vh>before</vh></v>
<v t="ekr.20050417204940.2"><vh>after</vh></v>
<v t="ekr.20050417204940.3"><vh>selection</vh></v>
</v>
<v t="ekr.20050417205012"><vh>convertAllTabs</vh>
<v t="ekr.20050417205012.1"><vh>before</vh></v>
<v t="ekr.20050417205012.2"><vh>after</vh></v>
<v t="ekr.20050417205012.3"><vh>selection</vh></v>
</v>
<v t="ekr.20050417203114"><vh>convertBlanks</vh>
<v t="ekr.20050417203310"><vh>before</vh></v>
<v t="ekr.20050417203310.1"><vh>after</vh></v>
<v t="ekr.20050417203336"><vh>selection</vh></v>
</v>
<v t="ekr.20050417203114.1"><vh>convertTabs</vh>
<v t="ekr.20050417204834"><vh>before</vh></v>
<v t="ekr.20050417204830"><vh>after</vh></v>
<v t="ekr.20050417204901"><vh>selection</vh></v>
</v>
<v t="ekr.20040712101754.49"><vh>dedentBody</vh>
<v t="ekr.20040712101754.50"><vh>before</vh></v>
<v t="ekr.20040712101754.51"><vh>after</vh></v>
<v t="ekr.20040712101754.52"><vh>selection</vh></v>
</v>
<v t="ekr.20050417202817"><vh>deleteComments</vh>
<v t="ekr.20050417202817.1"><vh>before</vh></v>
<v t="ekr.20050417202817.2"><vh>after</vh></v>
<v t="ekr.20050417202817.3"><vh>selection</vh></v>
</v>
<v t="ekr.20111112211307.3910"><vh>deleteComments</vh>
<v t="ekr.20111112211307.3911"><vh>before</vh></v>
<v t="ekr.20111112211307.3912"><vh>after</vh></v>
<v t="ekr.20111112211307.3913"><vh>selection</vh></v>
</v>
<v t="ekr.20050417201845"><vh>extract test1</vh>
<v t="ekr.20050417201845.1"><vh>before</vh></v>
<v t="ekr.20050417201845.2"><vh>after</vh>
<v t="ekr.20050417201845.3"><vh>&lt;&lt; section &gt;&gt; @nonl</vh></v>
</v>
<v t="ekr.20050417201845.4"><vh>selection</vh></v>
</v>
<v t="ekr.20050518070540"><vh>extract test2</vh>
<v t="ekr.20050518070540.1"><vh>before</vh></v>
<v t="ekr.20050518070545"><vh>after</vh></v>
<v t="ekr.20050518070540.4"><vh>selection</vh></v>
</v>
<v t="ekr.20050518070927"><vh>extractSection test1</vh>
<v t="ekr.20050518070927.1"><vh>before</vh></v>
<v t="ekr.20050518070927.2"><vh>after</vh>
<v t="ekr.20050518070927.3"><vh>&lt;&lt; section &gt;&gt; @nonl</vh></v>
</v>
<v t="ekr.20050518070927.4"><vh>selection</vh></v>
</v>
<v t="ekr.20050518071251"><vh>extractSection test2</vh>
<v t="ekr.20050518071251.1"><vh>before</vh></v>
<v t="ekr.20050518071258"><vh>after</vh></v>
<v t="ekr.20050518071251.4"><vh>selection</vh></v>
</v>
</v>
</v>
</v>
<v t="ekr.20130503061511.4175"><vh>@ignore Unit tests for settings</vh>
<v t="ekr.20130503061511.4176"><vh>print dicts unit tests</vh>
<v t="ekr.20130503061511.4177"><vh>@test printMenusList</vh></v>
<v t="ekr.20130503061511.4178"><vh>@test printInverseBindingDict</vh></v>
<v t="ekr.20130503061511.4179"><vh>@test printBindingsDict</vh></v>
<v t="ekr.20130503061511.4180"><vh>@test printMasterBindingsDict</vh></v>
</v>
<v t="ekr.20130503061511.4181"><vh>passed</vh>
<v t="ekr.20130503061511.4182"><vh>@test mode-related info</vh></v>
<v t="ekr.20130503061511.4183"><vh>@test types of contents of settings dicts</vh>
<v t="ekr.20130503061511.4184"><vh>test_dict_of_dicts</vh></v>
<v t="ekr.20130503061511.4185"><vh>test_dict_of_lists</vh></v>
<v t="ekr.20130503061511.4186"><vh>test_dict_of_objects</vh></v>
<v t="ekr.20130503061511.4187"><vh>Unused</vh></v>
</v>
<v t="ekr.20130503061511.4188"><vh>@test merge_settings_dicts</vh>
<v t="ekr.20130503061511.4189"><vh>dump &amp; dump_dict (@test merge_settings_dicts)</vh></v>
<v t="ekr.20130503061511.4190"><vh>test (@test merge_settings_dicts)</vh></v>
</v>
<v t="ekr.20130503061511.4191"><vh>@test KeyStroke</vh></v>
<v t="ekr.20130503061511.4192"><vh>@test g.TypedDict</vh></v>
</v>
</v>
<v t="ekr.20111107113442.3849"><vh>@ignore unused tests</vh>
<v t="ekr.20111112193817.3908"><vh>@@test delete-body-editor 3 times</vh></v>
<v t="ekr.20100225094004.5405"><vh>@@test loading .leo file with @file nodes</vh></v>
<v t="ekr.20061104172236.23"><vh>@@test tkBody.onClick</vh></v>
<v t="ekr.20051107115231.25"><vh>@@test typing in headline recomputes width</vh></v>
<v t="ekr.20061008162912"><vh>@@test write .leo file with @ignore node</vh>
<v t="ekr.20061008162912.1"><vh>child</vh></v>
</v>
<v t="ekr.20101021205258.6013"><vh>general file stuff</vh>
<v t="ekr.20100204153116.5369"><vh>@@test raw file copy</vh></v>
<v t="ekr.20080806211453.5"><vh>@@test round-trip-uAs for @shadow</vh>
<v t="ekr.20080806211453.1"><vh>@@shadow uA_test_shadow_file.py</vh>
<v t="ekr.20080822160527.1"><vh>uA_test_shadow_file declarations</vh></v>
</v>
</v>
<v t="ekr.20080806095923.2"><vh>@@test round-trip-uAs for @thin</vh>
<v t="ekr.20080806084924.2"><vh>@@thin uA_test_file.py</vh>
<v t="ekr.20080806084924.3"><vh>child1</vh>
<v t="ekr.20080806084924.4"><vh>grandChild1</vh>
<v t="ekr.20080806084924.5"><vh>greatGrandChild1</vh></v>
</v>
</v>
</v>
</v>
</v>
<v t="ekr.20100223094723.5375"><vh>New import tests</vh>
<v t="ekr.20100223094723.5376"><vh>@test skipToTheNextClassOrFunction (a class next)</vh></v>
<v t="ekr.20100223094723.5377"><vh>@test skipToTheNextClassOrFunction (a function next)</vh></v>
<v t="ekr.20100223094723.5378"><vh>@test skipToTheNextClassOrFunction (nothing next)</vh></v>
<v t="ekr.20100223094723.5379"><vh>@test skipToTheNextClassOrFunction (indented def next)</vh></v>
</v>
<v t="ekr.20110610122533.3388"><vh>Old Tests with @auto as the root</vh>
<v t="ekr.20110610122533.3389"><vh>@test goto-line-number @auto 1</vh></v>
<v t="ekr.20110610122533.3390"><vh>@test goto-global-line @auto 2</vh></v>
<v t="ekr.20110610122533.3391"><vh>@test goto-global-line @auto 3</vh></v>
<v t="ekr.20110610122533.3392"><vh>@test goto-global-line @auto 4</vh></v>
<v t="ekr.20110610122533.3406"><vh>@test goto-global-line @auto 5</vh></v>
<v t="ekr.20110610122533.3401"><vh>@test GoToLineNumber.find_root 1</vh></v>
</v>
</v>
<v t="ekr.20100208230953.5383"><vh>Cache tests</vh>
<v t="ekr.20100208095817.5387"><vh>@@test leoCache</vh></v>
</v>
<v t="ekr.20040712101754.2"><vh>Load tests for .leo files</vh>
<v t="ekr.20040712101754.3"><vh>@test test.leo</vh></v>
<v t="ekr.20040803090901"><vh>@test leoDist.leo</vh></v>
<v t="ekr.20081121164135.1"><vh>@test leoGuiPluginsRef.leo</vh></v>
<v t="ekr.20040712101754.4"><vh>@test LeoPyRef.leo</vh></v>
<v t="ekr.20040712101754.5"><vh>@test leoPluginsRef.leo</vh></v>
<v t="ekr.20040712101754.6"><vh>@test LeoDocs.leo</vh></v>
<v t="ekr.20040730181601"><vh>@test minimalLeoFile.leo</vh></v>
<v t="ekr.20040730181610"><vh>@test minimalLeoFile2.leo</vh></v>
<v t="ekr.20040831104758"><vh>@test minimalLeoFile3.leo</vh></v>
</v>
<v t="ekr.20080405085247.1"><vh>slow tests</vh>
<v t="ekr.20060208195054"><vh>@@test k.inverseCommandsDict is inverse of c.commandsDict</vh>
<v t="ekr.20070926095117"><vh>mungeKey</vh></v>
</v>
<v t="ekr.20110728154927.3324"><vh>@@test position &gt; operator</vh></v>
</v>
</v>
</v>
<v t="ekr.20071113203234"><vh>Test files</vh>
<v t="ekr.20110615130436.3317"><vh>@@file nonexistent-directory/orphan-bit-test.txt</vh></v>
<v t="ekr.20080907122804.1"><vh>@@shadow unittest/at-shadow-line-number-test.py</vh>
<v t="ekr.20150208213643.15"><vh>spam</vh></v>
<v t="ekr.20150208213643.16"><vh>eggs</vh></v>
</v>
<v t="ekr.20090704085350.5014"><vh>@@shadow unittest/at-shadow-test.py</vh>
<v t="ekr.20150208213643.12"><vh>spam</vh></v>
<v t="ekr.20150208213643.13"><vh>eggs</vh></v>
</v>
<v t="ekr.20111213122041.3930"><vh>@@shadow unittest/at-shadow-unlink-clones.py</vh>
<v t="ekr.20150208213643.18"><vh>Node 1</vh></v>
<v t="ekr.20150208213643.19"><vh>Node 2</vh></v>
</v>
<v t="ekr.20090704085350.5028"><vh>@asis unittest/at-asis-test.py</vh>
<v t="ekr.20090704085350.5029"><vh>spam</vh></v>
<v t="ekr.20090704085350.5030"><vh>eggs</vh></v>
</v>
<v t="ekr.20080904084223.1"><vh>@auto unittest/at-auto-line-number-test.py</vh></v>
<v t="ekr.20150626101842.1"><vh>@auto unittest/at-auto-md-line-number-test.md</vh></v>
<v t="ekr.20111214104615.3942"><vh>@auto unittest/at-auto-section-ref-test.py</vh></v>
<v t="ekr.20090704085350.5056"><vh>@auto unittest/at-auto-test.py</vh></v>
<v t="ekr.20110610122533.3407"><vh>@auto unittest/at-auto-unit-test.py</vh></v>
<v t="ekr.20150626101627.1"><vh>@auto-org unittest/at-auto-org-line-number-test.py</vh></v>
<v t="ekr.20150626100719.1"><vh>@auto-otl unittest/at-auto-otl-line-number-test.py</vh></v>
<v t="ekr.20150626093745.1"><vh>@auto-rst unittest/at-auto-rst-line-number-test.py</vh></v>
<v t="ekr.20160403143048.1"><vh>@clean unittest/at-clean-line-number-test.c</vh>
<v t="ekr.20160403143048.2"><vh>spam</vh></v>
<v t="ekr.20160403150121.1"><vh>eggs</vh></v>
</v>
<v t="ekr.20160403143130.1"><vh>@clean unittest/at-clean-line-number-test.py</vh>
<v t="ekr.20160403150216.1"><vh>spam</vh></v>
<v t="ekr.20160403150222.1"><vh>eggs</vh></v>
</v>
<v t="ekr.20160403123754.1"><vh>@file unittest/at-file-line-number-test.c</vh></v>
<v t="ekr.20080904102243.2"><vh>@file unittest/at-file-line-number-test.py</vh></v>
<v t="ekr.20111021115306.3697"><vh>@file unittest/tex-error.tex</vh></v>
<v t="ekr.20130912092638.4150"><vh>@file unittest/utf-16-test.txt</vh></v>
<v t="ekr.20080907123324.2"><vh>@nosent unittest/at-nosent-line-number-test.py</vh>
<v t="ekr.20080907123324.3"><vh>spam</vh></v>
<v t="ekr.20160403152507.1"><vh>eggs</vh></v>
</v>
<v t="ekr.20090704085350.5034"><vh>@nosent unittest/at-nosent-test.py</vh>
<v t="ekr.20090704085350.5035"><vh>spam</vh></v>
<v t="ekr.20090704085350.5036"><vh>eggs</vh></v>
</v>
<v t="ekr.20100731163237.5782"><vh>@thin unittest/at-thin-html-test.html</vh></v>
<v t="ekr.20080905130723.3"><vh>@thin unittest/at-thin-line-number-test.py</vh></v>
<v t="ekr.20090704085350.5022"><vh>@thin unittest/at-thin-test.py</vh></v>
<v t="ekr.20070627082044.811"><vh>@thin unittest/batchTest.py</vh></v>
<v t="ekr.20070627082044.808"><vh>@thin unittest/errorTest.py</vh></v>
</v>
<v t="ekr.20101220161557.6016"><vh>Active Unit Tests</vh>
<v t="edward.20160314170027.56" descendentVnodeUnknownAttributes="7d7100285808000000302e362e31382e3771017d71025808000000616e6e6f7461746571037d7104735808000000302e362e31322e3971057d71065809000000756e69745f7465737471075804000000616263647108735809000000302e362e31392e333971097d710a58090000006d795f706c7567696e710b580300000076616c710c735808000000302e362e31362e33710d7d710e5808000000616e6e6f74617465710f7d7110735808000000302e362e32372e3771117d71125808000000616e6e6f7461746571137d711473580a000000302e362e31372e352e3171157d7116580a0000007273742d696d706f727471177d711828580b000000756e6465726c696e657331711958030000002d7e2e711a580b000000756e6465726c696e657332711b58010000003d711c7573752e"><vh>@file activeUnitTests.txt</vh></v>
</v>
<v t="ekr.20160330182418.1"><vh>Recent failures</vh>
<v t="ekr.20160410152100.1"><vh> Tests of @auto-md</vh>
<v t="ekr.20160410152100.2"><vh>@test md-import-test</vh>
<v t="ekr.20160411034540.1"><vh>&lt;&lt; define s &gt;&gt; (md-import-test)</vh></v>
</v>
<v t="ekr.20160411033840.1"><vh>@test md-import-test-rst-style</vh>
<v t="ekr.20160411044042.1"><vh>&lt;&lt; define s &gt;&gt; (md-import-test-rst-style)</vh></v>
</v>
<v t="ekr.20141111092038.12"><vh>@test markdown</vh></v>
</v>
<v t="ekr.20120310121839.3949"><vh>@test c.hoist @chapter node</vh></v>
<v t="ekr.20080917151620.9"><vh>@test c.scanAllDirectives</vh></v>
<v t="ekr.20160327132053.1"><vh>@test g.compute_directives_re</vh></v>
<v t="ekr.20071113090055.5"><vh>@test g.get_directives_dict</vh></v>
<v t="ekr.20100131180007.5434"><vh>@test g.get_directives_dict 2</vh></v>
<v t="ekr.20100131171342.5608"><vh>@test k.strokeFromSetting</vh></v>
<v t="ekr.20100205235740.5392"><vh>@test syntax of all files</vh></v>
<v t="ekr.20110610122533.3369"><vh>goto-global-line tests</vh>
<v t="ekr.20110610122533.3405"><vh>@@test zz restore the screen</vh></v>
<v t="ekr.20100212072149.5341"><vh>@test c.goToScriptLineNumber</vh>
<v t="ekr.20100212072149.5342"><vh>syntax-error</vh></v>
</v>
<v t="ekr.20150626101920.1"><vh>@test find_file_line: @auto-md</vh></v>
<v t="ekr.20150626101643.1"><vh>@test find_file_line: @auto-org</vh></v>
<v t="ekr.20150626100652.1"><vh>@test find_file_line: @auto-otl</vh></v>
<v t="ekr.20150625101047.1"><vh>@test find_file_line: @auto-py</vh></v>
<v t="ekr.20150626093653.1"><vh>@test find_file_line: @auto-rst</vh></v>
<v t="ekr.20160403143643.1"><vh>@test find_file_line: @clean-c</vh></v>
<v t="ekr.20160403143655.1"><vh>@test find_file_line: @clean-python</vh></v>
<v t="ekr.20160403123650.1"><vh>@test find_file_line: @file-c</vh></v>
<v t="ekr.20110610122533.3395"><vh>@test find_file_line: @file-python</vh></v>
<v t="ekr.20110610122533.3399"><vh>@test find_file_line: @nosent-python</vh></v>
<v t="ekr.20110610122533.3394"><vh>@test find_gnx @file</vh></v>
<v t="ekr.20110610122533.3404"><vh>@test goto_show_results not found</vh></v>
</v>
<v t="ekr.20100131171342.5483"><vh>@test batch mode</vh>
<v t="ekr.20100131171342.5484"><vh>removeFile</vh></v>
</v>
<v t="ekr.20100131171342.5508"><vh>leoBridge</vh>
<v t="ekr.20100131171342.5509"><vh>@test leoBridge init logic</vh></v>
</v>
<v t="ekr.20160419061017.1"><vh>@test event classes</vh></v>
<v t="ekr.20160318094009.1"><vh>@test Python3 features</vh></v>
<v t="ekr.20100223123103.5382"></v>
</v>
<v t="ekr.20111006064419.3493"><vh>@test move-marked-nodes</vh></v>
</vnodes>
<tnodes>
<t tx="bwmulder.20050108100437.1">@killcolor

Running unit tests from test.leo is easy, provided you have enabled the
Scripting plugin. When this plugin is enabled Leo will create a blue 'script
button' in the icon bar called 'unit test'. 

- To run all unit tests, select the node in test.leo called 'Unit tests...',
then do &lt;alt-4&gt; 

- To run a single test, select an @test node and do &lt;alt-4&gt;.

- To run a suite of tests, select an @suite node and do &lt;alt-4&gt;.

- To run any other collection of tests, create an outline containing those @test
or @suite nodes, select the root of that tree and do &lt;alt-4&gt; .

Several nodes in the tree @thin ../src/leoTest.py (in test.leo) contain support
code for @test, @suite, etc. so if you want all the gory details you can read
the code. It's not complicated: Leo creates UnitTest classes automatically whose
run method is the body of the @suite or @test node.
</t>
<t tx="edward.20150612083734.1">gnx: ekr.20090627070131.4975
</t>
<t tx="edward.20150612083734.2">gnx: ekr.20090627070131.4975
</t>
<t tx="edward.20150612083734.3">gnx: ekr.20090627070131.4976
unl: spam
gnx: ekr.20090627070131.4977
unl: cheese
</t>
<t tx="edward.20150612083734.4">gnx: ekr.20100801125533.5788
</t>
<t tx="edward.20150612083734.5">gnx: ekr.20100801125533.5788
</t>
<t tx="edward.20150612083734.6">gnx: ekr.20100801125533.5789
unl: spam
gnx: ekr.20100801125533.5790
unl: cheese
</t>
<t tx="ekr.20040712101754.2">@language python
@tabwidth -4

# These work well with the qttabs gui.
</t>
<t tx="ekr.20040712101754.221">outline1 = p.firstChild()
outline2 = outline1.next()
assert(outline1.h=="outline1")
assert(outline2.h=="outline2")

c.testManager.replaceOutline(outline1,outline2)
c.redraw()
c.checkOutline()
</t>
<t tx="ekr.20040712101754.222"></t>
<t tx="ekr.20040712101754.223"></t>
<t tx="ekr.20040712101754.224"></t>
<t tx="ekr.20040712101754.225"></t>
<t tx="ekr.20040712101754.3">path = g.os_path_join(g.app.loadDir,"..","test","test.leo")
c.testManager.runLeoTest(path)
</t>
<t tx="ekr.20040712101754.37"># Create unit tests in g.app.scriptDict["suite"]

suite = c.testManager.makeEditBodySuite(p)

# g.app.scriptDict['suite'] = suite
</t>
<t tx="ekr.20040712101754.38">@language plain
@

The names of child nodes are the names of commander methods to be called to do the test.

Each child node will in turn have two or more children:

- a "before" node
- an "after" node
- an optional selection node containing two lines giving the selection range in Tk coordinates.
- An optional insert node containing one line giving the insert point in Tk coordinates.
</t>
<t tx="ekr.20040712101754.4">path = g.os_path_join(g.app.loadDir,"..","core","LeoPyRef.leo")
c.testManager.runLeoTest(path)
</t>
<t tx="ekr.20040712101754.49"></t>
<t tx="ekr.20040712101754.5">path = g.os_path_join(g.app.loadDir,"..","plugins","leoPluginsRef.leo")
c.testManager.runLeoTest(path)
</t>
<t tx="ekr.20040712101754.50">line 1
    line 2
    line 3
line 4
</t>
<t tx="ekr.20040712101754.51">line 1
line 2
line 3
line 4
</t>
<t tx="ekr.20040712101754.52">2.0
3.5
</t>
<t tx="ekr.20040712101754.6">path = g.os_path_join(g.app.loadDir,"..","doc","LeoDocs.leo")
c.testManager.runLeoTest(path)
</t>
<t tx="ekr.20040730181601">path = g.os_path_join(g.app.loadDir,"..","test","unittest","minimalLeoFile.leo")
c.testManager.runLeoTest(path)
</t>
<t tx="ekr.20040730181610">path = g.os_path_join(g.app.loadDir,"..","test","unittest","minimalLeoFile2.leo")
c.testManager.runLeoTest(path)
</t>
<t tx="ekr.20040803090901">path = g.os_path_join(g.app.loadDir,"..","dist","leoDist.leo")
c.testManager.runLeoTest(path)
</t>
<t tx="ekr.20040831104758">path = g.os_path_join(g.app.loadDir,"..","test","unittest","minimalLeoFile3.leo")
c.testManager.runLeoTest(path)
</t>
<t tx="ekr.20041121151002"></t>
<t tx="ekr.20050328101834"></t>
<t tx="ekr.20050328101834.1"></t>
<t tx="ekr.20050328101834.2"></t>
<t tx="ekr.20050328101834.3"></t>
<t tx="ekr.20050417201845"></t>
<t tx="ekr.20050417201845.1">before
    &lt;&lt; section &gt;&gt;
    sec line 1
        sec line 2 indented
sec line 3
after
</t>
<t tx="ekr.20050417201845.2">before
    &lt;&lt; section &gt;&gt;
after
</t>
<t tx="ekr.20050417201845.3">sec line 1
    sec line 2 indented
sec line 3
</t>
<t tx="ekr.20050417201845.4">2.0
5.10
</t>
<t tx="ekr.20050417202713"></t>
<t tx="ekr.20050417202713.1">@language python

def addCommentTest():

    if 1:
        a = 2
        b = 3

    pass
</t>
<t tx="ekr.20050417202713.2">@language python

def addCommentTest():

    # if 1:
        # a = 2
        # b = 3

    pass
</t>
<t tx="ekr.20050417202713.3">5.0
7.8
</t>
<t tx="ekr.20050417202817"># created by new add-comments
</t>
<t tx="ekr.20050417202817.1">@language python

def deleteCommentTest():

#     if 1:
#         a = 2
#         b = 3

    pass
</t>
<t tx="ekr.20050417202817.2">@language python

def deleteCommentTest():

    if 1:
        a = 2
        b = 3

    pass
</t>
<t tx="ekr.20050417202817.3">5.0
7.8
</t>
<t tx="ekr.20050417203114"></t>
<t tx="ekr.20050417203114.1"></t>
<t tx="ekr.20050417203310">@tabwidth -4

line 1
    line 2
      line 3
line4
</t>
<t tx="ekr.20050417203310.1">@tabwidth -4

line 1
	line 2
	  line 3
line4
</t>
<t tx="ekr.20050417203336">1.0
6.5
</t>
<t tx="ekr.20050417204830">@tabwidth -4

line 1
    line 2
      line 3
line4
</t>
<t tx="ekr.20050417204834">@tabwidth -4

line 1
	line 2
	  line 3
line4
</t>
<t tx="ekr.20050417204901">1.0
6.5
</t>
<t tx="ekr.20050417204940"></t>
<t tx="ekr.20050417204940.1">@tabwidth -4

line 1
    line 2
      line 3
line4
</t>
<t tx="ekr.20050417204940.2">@tabwidth -4

line 1
	line 2
	  line 3
line4
</t>
<t tx="ekr.20050417204940.3">1.0
6.5
</t>
<t tx="ekr.20050417205012"></t>
<t tx="ekr.20050417205012.1">@tabwidth -4

line 1
	line 2
	  line 3
line4
</t>
<t tx="ekr.20050417205012.2">@tabwidth -4

line 1
    line 2
      line 3
line4
</t>
<t tx="ekr.20050417205012.3">1.0
6.5
</t>
<t tx="ekr.20050518070540"></t>
<t tx="ekr.20050518070540.1">before
    &lt;&lt; section &gt;&gt;
    sec line 1
        sec line 2 indented
sec line 3
after
</t>
<t tx="ekr.20050518070540.4">2.0
2.16
</t>
<t tx="ekr.20050518070545">before
    &lt;&lt; section &gt;&gt;
    sec line 1
        sec line 2 indented
sec line 3
after
</t>
<t tx="ekr.20050518070927"></t>
<t tx="ekr.20050518070927.1">before
    &lt;&lt; section &gt;&gt;
    sec line 1
        sec line 2 indented
sec line 3
after
</t>
<t tx="ekr.20050518070927.2">before
    &lt;&lt; section &gt;&gt;
after
</t>
<t tx="ekr.20050518070927.3">sec line 1
    sec line 2 indented
sec line 3
</t>
<t tx="ekr.20050518070927.4">2.0
5.10
</t>
<t tx="ekr.20050518071251"></t>
<t tx="ekr.20050518071251.1">before
    &lt;&lt; section &gt;&gt;
    sec line 1
        sec line 2 indented
sec line 3
after
</t>
<t tx="ekr.20050518071251.4">2.0
2.16
</t>
<t tx="ekr.20050518071258">before
    &lt;&lt; section &gt;&gt;
    sec line 1
        sec line 2 indented
sec line 3
after
</t>
<t tx="ekr.20050618061835">@killcolor

Here is a tutorial written by Roger Erens.

Version Date        LeoID       Remarks
------- ----        -----       -------
0.1     20050519    rogererens  Initial version</t>
<t tx="ekr.20050618061835.1">So you think "Well, since I've written this piece of funky Python software, and everybody keeps saying how useful unit testing is, I really ought to start using unit tests." And since Leo's creator has said countless times in the Leo forums how easy unit testing in Leo is, a few uncomplicated examples might help convince you that he's not spamming.

Beware: this How-To should be the last time that you write tests AFTER having written your funky software! Test Driven Development dictates that tests have to be prepared BEFORE you get down to writing your actual code. See a nice tutorial on O'Reilly's website (url given in the descendant node).</t>
<t tx="ekr.20050618061835.10">Start of Do @test
F
======================================================================
FAIL: @test my second Leo test

----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\Documents and Settings\re1705\My Documents\PythonStuff\leo\src\leoTes
t.py", line 148, in runTest
    exec script + '\n' in {'c':c,'g':g,'p':p}
  File "&lt;string&gt;", line 3, in ?
AssertionError

----------------------------------------------------------------------
Ran 1 test in 0.010s

FAILED (failures=1)
End of Do @test</t>
<t tx="ekr.20050618061835.11">A real fun feature of Leo is that Leo saves you from having to select each and single @test node and press the 'Do @test' button to obtain testing results. Just collecting the @test nodes under an organizing node, selecting that organizing node, and pressing the 'Do @test' button will suffice.
Of course, this was one of the key ideas of unit testing, but it's nice to see it being implemented by Leo so smoothly!

So, press the button while having this node selected, and see if your console's output matches the third child node more or less. </t>
<t tx="ekr.20050618061835.12">Start of Do @test
.F
======================================================================
FAIL: @test my second Leo test

----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\leo\src\leoTest.py", line 148, in runTest
    exec script + '\n' in {'c':c,'g':g,'p':p}
  File "&lt;string&gt;", line 3, in ?
AssertionError

----------------------------------------------------------------------
Ran 2 tests in 0.040s

FAILED (failures=1)
End of Do @test</t>
<t tx="ekr.20050618061835.13">Okay: so you've seen now some simple stand-alone tests to get your toes wet.
Now, we get to the 'grande finale' and see real-life usage of the @test nodes.

The @test child node below illustrates the following points:

1.  The node imports the module to test (and keeps it up to date by reloading it).
2.  It also obtains data to use as input and referral. This is what you might call
    the setUp methods in traditional unit tests. If more tests need the same data,
    you can put the nodes in a central place where all the @test nodes can find
    them. Likewise, common code for several unit tests might be collected in a
    central place.
3.  Comparable with the traditional unit tests' tearDown method, some statements
    can follow the test itself, if neccessary. You might also consider using a
    try/finally construct.
4.  I have used g.es() statements instead of print statements, since the latter
    clutter the console. Try replacing the g.es() statements by corresponding
    print statements to see what I mean. With more than one @test node being tested,
    this will give quite a dreadful look.</t>
<t tx="ekr.20050618061835.14">@color

try:
    # SETUP
    import koekiemonster # this module defines a function want() which we want to test
    reload(koekiemonster) # changes in koekiemonster need to propagate to the test

    # obtaining the input parameter for the function
    inputNode = p.firstChild()
    inputData = inputNode.b
    
    # obtaining the expected result from the function with above input parameter
    expectedResultNode = inputNode.next()
    expected = expectedResultNode.b
    
    # execute the function with above input parameter
    result = koekiemonster.wants(inputData)
    
    # TEST
    assert(result == expected)
    
    # TEARDOWN
    g.es("Now it's time to clean up")

except AssertionError:
    # TEARDOWN
    g.es("Oh oh! %s failed:" % p.h.strip())
    g.es("koekiemonster.wants(%s)==%s" % (inputData, result))
    g.es("Expected: %s" % expected)
    raise # pass the exception on to the unit test machinery</t>
<t tx="ekr.20050618061835.15">vegetables</t>
<t tx="ekr.20050618061835.16">Yuck!</t>
<t tx="ekr.20050618061835.17">Start of Do @test
F
======================================================================
FAIL: @test koekiemonster.wants()

----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\leo\src\leoTest.py", line 148, in runTest
    exec script + '\n' in {'c':c,'g':g,'p':p}
  File "&lt;string&gt;", line 22, in ?
AssertionError

----------------------------------------------------------------------
Ran 1 test in 0.070s

FAILED (failures=1)
End of Do @test</t>
<t tx="ekr.20050618061835.18">Start of Do @test
Oh oh: @test koekiemonster.wants() failed:
koekiemonster.wants(vegetables)=Yack!
Expected: Yuck!
F
======================================================================
FAIL: @test koekiemonster.wants()

----------------------------------------------------------------------
Traceback (most recent call last):
  File "C:\leo\src\leoTest.py", line 148, in runTest
    exec script + '\n' in {'c':c,'g':g,'p':p}
  File "&lt;string&gt;", line 22, in ?
AssertionError

----------------------------------------------------------------------
Ran 1 test in 0.051s

FAILED (failures=1)
End of Do @test</t>
<t tx="ekr.20050618061835.19">With the aforementioned possibilities of running all @test nodes in a subtree
with a single click on a button, the sharing of input/expected data, and the
sharing of setUp/tearDown code, there hardly seems a need for the @suite nodes.

On Leo's website
(http://webpages.charter.net/edreamleo/scripting.html#unit-testing-with-test-and-suite)
I could still find some extra info on @suite nodes, not found in LeoDocs.leo:

&lt;quote&gt;

Using @suite nodes

Such nodes create a suite of tests. Leo executes the script in these nodes similar to @test nodes, but Leo assumes that the script in an @suite node will do the following:

    * Create a suite of unit tests
    * Put the suite in g.app.scriptDict["suite"]

The difference between @test and @suite is:

    * Leo creates a unit test from script in an @test node by creating an instance of generalTestCase, a subclass of unittest.TestCase.
    * The script in an @suite node creates the test suite.

An @suite nodes allows us to create "legacy" unit tests simply. For example,
rather than rewriting all the reformatParagraph unit tests to use @test nodes, I
simply wrote an @suite node with the following body.

    suite = c.testManager.makeReformatParagraphSuite()
    g.app.scriptDict['suite'] = suite

&lt;/quote&gt;

Well, that's almost, but not quite completely, totally incomprehensible to me.
Fortunately, since Leo's creator removed most of this quote from LeoDocs.leo and
test.leo, this information appears to be outdated
.</t>
<t tx="ekr.20050618061835.2"></t>
<t tx="ekr.20050618061835.20">Don't forget to read the node
Users Guide--&gt;Chapter 7: Scripting Leo with Python--&gt;Unit testing with @test, @suite
in LeoDocs.leo, especially the final notes. Also investigate a little further in test.leo to see some heavy weight lifting.

This concludes my How-To on using @test. It was not written by an expert on (unit) testing;
it is more or less the result of keeping notes on my way to find out how I could get started
with unit tests in Leo. Maybe it's useful for other newbies as well.

Please post any remarks on one of the Leo Fora, and if deemed helpful, I'll be glad to incorporate them into a next version.

Happy testing!</t>
<t tx="ekr.20050618061835.3">Comment by EKR: There is no need to do this if you use test.leo for your unit tests:  just use the unit test button.

From the console, start up a Leo instance. On MS Windows: go to the folder in which you installed Leo 4.3, open up the 'src' folder and double click the 'leo.py' file. Opening a command window, and typing "python leo.py" may be another way.

Use the File--&gt;Open... menu item to open the outline containing your code.

Choose a good-looking position to insert a new node called 'Test zone'. Copy the child node of the node you're reading right now, and paste it as a child node of 'Test zone'. The code it contains is essentially the same as found in the node
Unit tests...--&gt;Do @test
in the file 'test.leo' in the 'test' folder. I just added my 0.2 cents by adding some starting and finishing remarks. Remove them if they clutter your console too much.

Also, make sure that you have an entry 'Scripting' in the 'Plugins' menu (enable the plugin if neccessary). Now is a good time to save your leo file.

With the 'Scripting' plugin (also known as the 'mod_scripting' plugin) enabled, the net effect will be that the next time you open your outline, a blue button with the caption 'Do @test' shows up in the tool bar of Leo, if your screen is wide enough.
To get the button right away in the tool bar, I have to assume that you started Leo with the scripting plugin enabled. In this case, a yellow button with the caption 'script Button' can be pressed while having the node '@button Do @test' selected. Note: the resulting button will not be blue, but pink. Removing a button from the tool bar can be done by right-clicking it.

We'll see the use of this added button soon, but before that, read up on the 'assert' function in the Python manuals, since it is used a lot in testing. It won't be long before you're back here!</t>
<t tx="ekr.20050618061835.4">@color

g.pr("\nStart of Do @test")
c.testManager.doTests(all=False)
g.pr("End of Do @test")</t>
<t tx="ekr.20050618061835.5">The first child node of the node you're reading right now, contains the simplest succeeding test possible.
Select it, and press the button 'Do @test'.
You can find the verbatim result as it got sent to my console in the second child node.

A few things are worth noting here:

1.  The node containing the test must have its headline start with '@test'.
2.  Whenever the 'assert' statement finds out that the expression given to it
    is 'True', a test passes successfully. There are more ways to pass a test, but
    for now, let us stick to the use of assert functions.
3.  A passed test is denoted with a single dot in the output. See the line between
    'Start of Do @test' and the line filled with dashes. This is compatible with the
    way traditional unit testing shows its progress.
4.  Below the dashed line in the output, a summary is printed. This one surely gives
    us a reason to lean back for a moment, and congratualate ourselves with another
    piece of robust, funky code!</t>
<t tx="ekr.20050618061835.6">@color
assert(True)</t>
<t tx="ekr.20050618061835.7">Start of Do @test
.
----------------------------------------------------------------------
Ran 1 test in 0.010s

OK
End of Do @test</t>
<t tx="ekr.20050618061835.8">Now that you've seen a passing test, it should be obvious to imagine how a failing test would look like. See the first child node, and then run it by pressing the 'Do @test' button as before.

Instead of a dot denoting success, we get an 'F' denoting a failure on the line following 'Start of Do @test'. When running a lot of tests, the next part, following the lines filled with '='s, helps to identify which test failed.
It also includes a trace back, but for AssertionErrors, it does not seem to offer much added value to me right now. On second thought: when you have multiple asserts in a test, the trace back can tell you which assert function failed. Still, I would choose for only one assert function per test and get rid of this trace back altogether. This would keep the console much cleaner, IMHO.</t>
<t tx="ekr.20050618061835.9">@color
assert('Spam' == 'Ham')</t>
<t tx="ekr.20051012104957"></t>
<t tx="ekr.20051013162226"></t>
<t tx="ekr.20051104081502">@language python
@tabwidth -4
</t>
<t tx="ekr.20051104081502.101">@language plain
@pagewidth 40

A one-line paragraph one two three four five six seven eight nine ten...

An @rawfile tree is a tree whose root headline starts with
@rawfile &lt;filename&gt;. Similarly, an @silentfile tree is a
tree whose root headline starts with an @silentfile
&lt;filename&gt; directive.

    Leo creates derived files from @rawfile and @silentfile trees by writing the body text of all nodes of the tree in outline order.  Leo writes the body text _as is_, without recognizing section definitions, without expanding section references, and without treating directives specially in any way.  In particular, Leo copies all directives, including @space or @c directives, to the derived file as text. Exception: Leo recognizes the @ignore directive in @rawfile or @silentfile nodes, so you may use the @ignore directive as usual to prevent Leo from writing @rawfile and @silentfile trees.

There are several difference between @rawfile and @silentfile trees:

  This
  is
  a
  test.

  1. This is the first line and it is really really really long. And it has
     a hanging indentation.
     and another line.

  2. This is a lllllllllllllllllllllllllllllllllllloooooooooooooooooong
     next item.
     And it too has a hanging indentation.

  3. This is an exxxxxxxxxxxxxxxxxxxxxxxxtrrrrrrrrrrrrrrreeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeemlylong
     word.
And it too has a hanging indentation.
</t>
<t tx="ekr.20051104081502.102">@tabwidth -4
@language plain


    a   b   c
a   b   c   d
aa  b   c   d
aaa b   c   d
end
</t>
<t tx="ekr.20051104081502.103">@killcolor
@language plain

Note: Previously, one could crash Leo by pasting a large text into a headline.  Leo now truncates that text, and furthermore Leo no longer makes all headline text into one gigantic line.  Therefore, we don't have to test Tk's ability to handle super-long lines.

The test:  Copy the following and paste it into a headline.  Leo should give 2 truncation messages:

- Truncating headline to one line.
- Truncating headline to 250 characters.

About a year ago I found the website at www.literateprogamming.com and was immediately convinced that the basic idea of Literate Programming is an important breakthrough. At the time I was working on a contract trying to decipher a true masterpiece of over-engineering, and if at any time during the construction of this masterpiece the perpetrators had been required to explain themselves in English, my client would have saved millions of dollars.

I never did try CWEB or NOWEB though, because on the literate programming site I read about a tool named “Leo” that combined outlines with Literate Programming techniques. Since I’ve always found outlining tools very useful I downloaded and tried this. I found that using this tool completely changed my programming practice and brought out all of the power inherent in the original Literate Programming idea as I understood it.
</t>
<t tx="ekr.20051104081502.104">import os

g.pr(os.getcwd())
name = g.os_path_join("test","removeSentTest.txt")
c.importCommands.removeSentinelsCommand(name)
</t>
<t tx="ekr.20051104081502.105">import glob

g.pr('-' * 40)

tm = c.testManager

if 0:
    g.pr("modules in test.leo...")
    paths = tm.findAllAtFileNodes(c)
    modules = tm.importAllModulesInPathList(paths)
    for module in modules:
        g.pr(module)

if 1:
    g.pr("modules in leo/src...")
    path = g.os_path_join(g.app.loadDir,"..","src")
    modules = tm.importAllModulesInPath(path)
    for module in modules:
        g.pr(module)

if 0:
    directory = g.os_path_join(g.app.loadDir,"..","src")
    glob_path = g.os_path_join(directory,"leo*.py")
    files = glob.glob(glob_path)
    modules = tm.importAllModulesInPathList(files)
    for module in modules:
        g.pr(module)
</t>
<t tx="ekr.20051104081502.106"></t>
<t tx="ekr.20051104081502.107">import doctest
import unittest

tm = c.testManager

createUnitTest = True

if createUnitTest:
    suite = unittest.makeSuite(unittest.TestCase)
else:
    suite = None

paths   = tm.findAllAtFileNodes(c)
modules = tm.importAllModulesInPathList(paths)

if createUnitTest:
    suite = tm.createUnitTestsFromDoctests(modules)
else:
    for module in modules:
        doctest.testmod(module,verbose=True,report=False)

if suite:
    g.app.scriptDict['suite'] = suite
</t>
<t tx="ekr.20051104081502.108">for i in range(10000):
    if i and (i % 1000) == 0:
        g.pr(i)
</t>
<t tx="ekr.20051104081502.109">i = 0
for i in range(100000):
    i += 1
    i -= 1
</t>
<t tx="ekr.20051104081502.110"># c.redraw just schedules the actual drawing.
# We want to profile the actual idle-time drawing.

c.frame.tree.idle_redraw()
</t>
<t tx="ekr.20051104081502.111">@language python
@tabwidth -4
</t>
<t tx="ekr.20051104081502.112"># EKR: I don't remember the status of this.

@language python

import shutil

testing = True
sourcedir=r"c:/prog/test/perfectImport"
targetdir=r"c:/prog/test/perfectImport/leo"
s1 = g.os_path_join(sourcedir,"leoAtFile.py")
t1 = g.os_path_join(targetdir,"leoAtFile.py")
files = [(s1,t1)]

@others

g.pr('\n' + '-' * 20)
sync(files) # push or pull, depending on date.
</t>
<t tx="ekr.20051104081502.113">def sync(files):

    """Do a pull or a push, depending on the date of the files."""

    none, push, pull = 'None', 'push', 'pull'
    mu = g.mulderUpdateAlgorithm()

    for sourcefilename, targetfilename in files:
        &lt;&lt; compute sourcetime and targettime &gt;&gt;
        &lt;&lt; compute operation &gt;&gt;
        if operation == push:
            if testing: g.pr(push, sourcefilename, targetfilename)
            strippedLines = mu.removeSentinelsFromFile(sourcefilename)
            mu.write_if_changed(strippedLines,sourcefilename,targetfilename)
            mu.copy_time(sourcefilename,targetfilename)
        elif operation == pull:
            if testing: g.pr(pull, sourcefilename, targetfilename)
            if sourcetime:
                mu.propagateDiffsToSentinelsFile(sourcefilename,targetfilename)
                mu.copy_time(targetfilename,sourcefilename)
            else:
                shutil.copy2(targetfilename,sourcefilename)
</t>
<t tx="ekr.20051104081502.114">sourcetime = targettime = None

if g.os_path_exists(sourcefilename):
    sourcetime = g.os_path_getmtime(sourcefilename)

if g.os_path_exists(targetfilename):
    targettime = g.os_path_getmtime(targetfilename)
</t>
<t tx="ekr.20051104081502.115">operation = None
if sourcetime:
    if targettime:
        if sourcetime &gt; targettime:
            operation = push
        elif sourcetime &lt; targettime:
            operation = pull
    else:
        operation = push
elif targettime:
    operation = pull
</t>
<t tx="ekr.20051104081502.116"># Run this script to import a file.
# This is undoable because the Import @file command is undoable.

path = r"c:\prog\test\perfectImport"

# Two files from Python23/Lib
name1 = g.os_path_join(path,"formatter.py")
name2 = g.os_path_join(path,"SimpleHTTPServer.py")
names = [name1]

c.importCommands.importFilesCommand (names,"@file",
    perfectImport=True,testing=False,verbose=True)
</t>
<t tx="ekr.20051104081502.117"></t>
<t tx="ekr.20051104081502.118">g.pr('-'*20)

for p in c.allNodes_iter():
    if p.isDirty():
        vnodes = p.findAllPotentiallyDirtyNodes()
        g.pr('-'*5, p)
        for v in vnodes:
            g.pr(v)

g.pr("done")
</t>
<t tx="ekr.20051104081502.119">import leoNodes

position = leoNodes.position

@others

current = pos = c.p
child1 = current.firstChild()
child2 = child1.firstChild()

if 0:
    g.pr('-'*10, "parents")
    for p in child2.parents_iter(): g.pr(p)
if 0:
    g.pr('-'*10, "subtree")
    for p in pos.subtree_iter(): g.pr(p)
if 0:
    g.pr('-'*10, "children")
    for p in child1.children_iter(): g.pr(p)
if 0:
    g.pr('-'*10, "siblings")
    for p in pos.siblings_iter(): g.pr(p)
if 1:
    g.pr('-'*10, "all nodes")
    for p in c.allNodes_iter():
        g.pr(p.isCloned(),p)
</t>
<t tx="ekr.20051104081502.120"></t>
<t tx="ekr.20051104081502.121"></t>
<t tx="ekr.20051104081502.122"></t>
<t tx="ekr.20051104081502.123"></t>
<t tx="ekr.20051104081502.124"></t>
<t tx="ekr.20051104081502.125"></t>
<t tx="ekr.20051104081502.126"></t>
<t tx="ekr.20051104081502.127"></t>
<t tx="ekr.20051104081502.128"></t>
<t tx="ekr.20051104081502.129"></t>
<t tx="ekr.20051104081502.130"></t>
<t tx="ekr.20051104081502.131"></t>
<t tx="ekr.20051104081502.145">g.pr('-'*20)

for p in c.allNodes_iter():
    if p.isAnyAtFileNode():
        g.pr(p)

g.pr("done")
</t>
<t tx="ekr.20051104081502.146">tm = c.testManager

g.pr("children", '-' * 20)
children = tm.findChildrenOf(p)
for child in children: g.pr(child.h)

g.pr("subtree", '-' * 20)
descendants = tm.findSubnodesOf(p)
for descendant in descendants: g.pr(descendant.h)
</t>
<t tx="ekr.20051104081502.147">import binascii
import pickle

d = { "a":True }

g.pr('-' * 40)

s = pickle.dumps(d,bin=True)
s2 = binascii.hexlify(s)
g.pr(`s`,s2)

s3 = binascii.unhexlify(s2)
d2 = cPickle.loads(s3)

g.pr(`d2`)
g.pr(d == d2, d is d2)
</t>
<t tx="ekr.20051104081502.148">def redoBletch(self):
    g.trace()

def undoBletch(self):
    g.trace()

u = c.undoer

if 0:
    # bad functions
    u.registerUndoHandlers("Bletch","abc","xyz")
else:
    u.registerUndoHandlers("Bletch",undoBletch,redoBletch)

# "Execute" the Bletch command :-)  The Edit command should contain "Undo Bletch"
u.setUndoParams("Bletch",p)

# Selecting "Undo Bletch" will enable "Redo Bletch", etc.
</t>
<t tx="ekr.20051104081502.149">d = { "a":True }

if 1:
    # Warning: executing this in the a2 code base will cause any save operation to fail.
    p.v.unknownAttributes = { "myPlugin" : d }

g.pr(repr(p.v.unknownAttributes))
</t>
<t tx="ekr.20051104081502.150">import leoPlugins

def onEnd (tag,keys):
    g.pr("onEnd",tag,keys)

count = 0

def onIdle (tag,keys):
    global count ; count += 1
    if count % 10 == 0:
        g.pr("onIdle",count,keys.get("c"))

leoPlugins.registerHandler("end1", onEnd)
g.pr("onEnd registered as end1 hook")

leoPlugins.registerHandler("idle", onIdle)
g.pr("onIdle registered as idle hook")
</t>
<t tx="ekr.20051104081502.151">for p in c.all_positions_iter():
    g.pr(p.v.t.fileIndex)
</t>
<t tx="ekr.20051104081502.152">g.pr(c.frame.bodyCtrl.focus())
</t>
<t tx="ekr.20051104081502.153"># This kind of code is used in the prototypes of new commands.

from __future__ import generators

@others

lines = "a\nb\nc\nd"

if 1: # Both work
    readline = g.readLinesGenerator(lines).next
else:
    readline = g.readLinesClass(lines).next

g.pr('-' * 20)

if 1: # Both work
    for s in g.readLinesGenerator(lines):
        g.pr(s,)
else:
    while 1:
        s = readline()
        if s: g.pr(s,)
        else: break

g.pr('\n' + '-' * 20)
</t>
<t tx="ekr.20051104081502.154"># Test
@others
# Last
</t>
<t tx="ekr.20051104081502.155">a = 1
g.pr("hello")
c = b
</t>
<t tx="ekr.20051104081502.157">import leoTest
import types

specialDictNames = ('__builtins__','__doc__','__name__','__file__','__module__')

def printDoc(x,s):
    if hasattr(x,"__doc__") and x.__doc__:
        g.pr("%4d %s" % (len(x.__doc__),s))
    else:
        g.pr("%4s %s" % (' ',s))

g.pr('-' * 60)
g.pr("%4d %s" % (len(leoTest.__doc__),"leoTest"))

if 1:
    for s in leoTest.__dict__:
        if s not in specialDictNames:
            x = getattr(leoTest,s)
            if type(x) != types.ModuleType:
                printDoc(x,s)
                if type(x) == types.ClassType:
                    for s2 in x.__dict__:
                        x2 = getattr(x,s2)
                        if s2 not in specialDictNames:
                            g.pr(' '*4,)
                            printDoc(x2,s2)
else:
    &lt;&lt; print names sorted by type &gt;&gt;
</t>
<t tx="ekr.20051104081502.158">for theType,typeName in (
    (types.ModuleType,"modules"),
    (types.ClassType,"classes"),
    (types.FunctionType,"functions"),
):

    g.pr("\n%s..." % typeName)
    for s in leoTest.__dict__:

        if s not in specialDictNames:
            x = getattr(leoTest,s)
            if type(x) == theType:
                printDoc(x,s)
                if theType == types.ClassType:
                    g.pr("\tmethods...")
                    for s2 in x.__dict__:
                        x2 = getattr(x,s2)
                        if s2 not in specialDictNames:
                            g.pr("\t",newline=False)
                            printDoc(x2,s2)
</t>
<t tx="ekr.20051104081502.159">import Tkinter as Tk

root = Tk.Tk()
c = Tk.Canvas(root,background='white')
g.pr(c.bindtags())

if 0:
    c.pack(expand=1,fill='both')
    f = Tk.Frame(c)
    c.create_window(0,0,window=f,anchor='nw')
    f.pack_configure(fill='both',expand=1)
    body = olCreateControl(self,frame,f)
    c.on = False 
    sel = lambda event, c = c, body = body:select(event,c,body)
    ai = lambda event, c = c, body = body, colorizer = frame.body:add_item(event,c,body,colorizer.getColorizer())
    c.bind("&lt;Key&gt;",watcher,'+')
    c.bind("&lt;Key&gt;",sel,'+')
    c.bind("&lt;Key&gt;",ai,'+')
    ctags = c.bindtags()
    btags = body.bindtags()
    btags =(ctags[0],btags[0],btags[1],btags[2],btags[3])
    body.bindtags(btags)
</t>
<t tx="ekr.20051104081502.160"></t>
<t tx="ekr.20051104081502.161">for p in c.allNodes_iter():

    if hasattr(p.v.t,"unknownAttributes"):
        a = p.v.t.unknownAttributes
        iconsList = a.get("icons")
        if dict:
            a["icons"] = []
            a["lineYOffset"] = 0

c.redraw()
</t>
<t tx="ekr.20051104081502.162">p.v.t.unknownAttributes = {}
a = p.v.t.unknownAttributes

&lt;&lt; define event callbacks &gt;&gt;

path = g.os_path_join(g.app.loadDir,"..","Icons")
icon1 = g.os_path_join(path,"lt_arrow_enabled.gif")
icon2 = g.os_path_join(path,"rt_arrow_enabled.gif")

d1 = {
    "type" : "file", "file" : icon1,
    "where" : "beforeIcon",
    "yoffset" : -3,
    # "yoffset" : 5, "ypad" : -5,
    # "height" : 40, # automatically adjust headline y position.
    "xpad": 2
}

# Classes and functions can only be pickled if they are at the top level of a module.
    #"onClick" : onClick,
    #"onRightClick" : onRightClick,
    #"onDoubleClick" : onDoubleClick }

d2 = {
    "type" : "file", "file" : icon2,
    "where" : "beforeHeadline",
    "yoffset" : -3,
    "xoffset" : 2, "xpad" : -2 }

a["icons"] = [d1,d2] # [d1,d2]
a["lineYOffset"] = 3

c.redraw()
</t>
<t tx="ekr.20051104081502.163">def onClick(p=p):

    g.trace(p)

def onRightClick(p=p):

    g.trace(p)

def onDoubleClick(p=p):

    g.trace(p)
</t>
<t tx="ekr.20051104081502.164"></t>
<t tx="ekr.20051104081502.165"># Set the attribute.
d = {'str_ekr_attribute': 'abc'}
p.v.t.unknownAttributes = d
</t>
<t tx="ekr.20051104081502.166">for p in c.allNodes_iter():
    h = p.h
    if hasattr(p.v.t,'unknownAttributes'):
        d = p.v.t.unknownAttributes
        val = d.get('str_ekr_attribute')
        if val:
           g.es('str_ekr_attribute is: %s' % val)
</t>
<t tx="ekr.20051104081502.183">s = u"ß"

g.reportBadChars(s,"latin_1")

g.pr(g.toEncodedString(s,"latin_1"))
</t>
<t tx="ekr.20051104081502.209">arg = "arg" ; filename = "fileName"
path = "path" ; shortPath = "shortPath"
vtuple = "vtuple"

def test(a,b):
    assert(a==b)

test(
    "os.system("+arg+shortPath+")",
    "os.system(%s)" % (arg+shortPath))
test(
    "os.startfile("+arg+shortPath+")",
    "os.startfile(%s)" % (arg+shortPath))
# test(
    # "exec("+arg+shortPath+")",
    # "exec(%s)" % (arg+shortPath))
test(
    "os.spawnl("+arg+","+filename+','+ shortPath+")",
    "os.spawnl(%s,%s,%s)" % (arg,filename,shortPath))
test(
    "os.spawnv("+arg[0]+","+repr(vtuple)+")",
    "os.spawnv(%s,%s)" % (arg[0],repr(vtuple)))
</t>
<t tx="ekr.20051104081502.210">@language python

# Type a period to autocomplete
leoTest

# Type an open paren to bring up calltip.
c.testManager.findAllAtFileNodes
</t>
<t tx="ekr.20051104081502.211"></t>
<t tx="ekr.20051104081502.213"></t>
<t tx="ekr.20051104081502.214"># Go To Line number now assumes that selected node is
# the root of a script if there is no ancestor @file node.

@others

# last line
</t>
<t tx="ekr.20051104081502.215"># We should also be able to use the goto line number command to get to the erroneous line.

a = 1/0 # ZeroDivisionError

b = 2
</t>
<t tx="ekr.20051104081502.216"></t>
<t tx="ekr.20051104081502.217">import leoPlugins as plugins

def traceHook(tag,event):
    g.trace(tag)

tags = (
    "boxclick1","boxclick2",
    "drag1","drag2",
    "dragging1","dragging2",
    "enddrag1","enddrag2",
    "iconclick1","iconclick2"  , 
    "iconrclick1","iconrclick2",
    "icondclick1","icondclick2",
)

plugins.registerHandler(tags,traceHook)

handlers = plugins.getHandlersForTag(tags)
if handlers:
    g.pr("-" * 20)
    for h in handlers:
        g.pr(h)
</t>
<t tx="ekr.20051104081502.218">import leoPlugins as plugins

tags = (
    "boxclick1","boxclick2",
    "drag1","drag2",
    "dragging1","dragging2",
    "enddrag1","enddrag2",
    "iconclick1","iconclick2"  , 
    "iconrclick1","iconrclick2",
    "icondclick1","icondclick2",
)

for tag in tags:
    handlers = plugins.getHandlersForTag(tag)
    if handlers:
        g.pr(handlers)
        for f in handlers:
            plugins.unregisterHandler(tag,f)

handlers = plugins.getHandlersForTag(tags)
if handlers:
    g.pr("-" * 20)
    for h in handlers:
        g.pr(h)
</t>
<t tx="ekr.20051104081502.219">import leoPlugins as plugins

tags = (
    "boxclick1","boxclick2",
    "drag1","drag2",
    "dragging1","dragging2",
    "enddrag1","enddrag2",
    "iconclick1","iconclick2"  , 
    "iconrclick1","iconrclick2",
    "icondclick1","icondclick2",
)

handlers = plugins.getHandlersForTag(tags)
if handlers:
    g.pr("-" * 20)
    for h in handlers:
        g.pr(h)
</t>
<t tx="ekr.20051104081502.22"></t>
<t tx="ekr.20051104081502.220">"""Mini test that documentation of hooks in leoDocs.leo is correct.

hookData should match that documentation for this test to be effective.

This is not a complete unit test:  it does not force executions of all hooks.
"""

&lt;&lt; imports &gt;&gt;
&lt;&lt; define hookData &gt;&gt;
&lt;&lt; define typeData &gt;&gt;
checked = [] # List of all hooks that have been checked.

@others

tags = [] 
for name,args in hookData:
    tags.append(name)
    &lt;&lt; define checkHook &gt;&gt;
    leoPlugins.registerHandler(name,checkHook)

if 0: # print all hooks.
    handlers = leoPlugins.getHandlersForTag(tags)
    if handlers:
        g.pr("-" * 20)
        for h in handlers:
            g.pr(h)
</t>
<t tx="ekr.20051104081502.221">import leoColor
import leoCommands
import leoNodes
import leoPlugins
import leoTkinterTree

import types
import Tkinter as Tk
</t>
<t tx="ekr.20051104081502.222">hookData = (
    ("bodyclick1",   ("c","p","v","event")),
    ("bodyclick2",   ("c","p","v","event")),
    ("bodydclick1",  ("c","p","v","event")),
    ("bodydclick2",  ("c","p","v","event")),
    ("bodykey1",     ("c","p","v","ch","oldSel","undoType")),
    ("bodykey2",     ("c","p","v","ch","oldSel","undoType")),
    ("bodyrclick1",  ("c","p","v","event")),
    ("bodyrclick2",  ("c","p","v","event")),
    ("boxclick1",    ("c","p","v","event")),
    ("boxclick2",    ("c","p","v","event")),
    ("command1",     ("c","p","v","label")),
    ("command2",     ("c","p","v","label")),
    ("drag1",        ("c","p","v","event")),
    ("drag2",        ("c","p","v","event")),
    ("dragging1",    ("c","p","v","event")),
    ("dragging2",    ("c","p","v","event")),
    ("end1",         None),
    ("enddrag1",     ("c","p","v","event")),
    ("enddrag2",     ("c","p","v","event")),
    ("headclick1",   ("c","p","v","event")),
    ("headclick2",   ("c","p","v","event")),
    ("headrclick1",  ("c","p","v","event")),
    ("headrclick2",  ("c","p","v","event")),
    ("headkey1",     ("c","p","v","ch")),
    ("headkey2",     ("c","p","v","ch")),
    ("hypercclick1", ("c","p","v","event")),
    ("hypercclick2", ("c","p","v","event")),
    ("hyperenter1",  ("c","p","v","event")),
    ("hyperenter2",  ("c","p","v","event")),
    ("hyperleave1",  ("c","p","v","event")),
    ("hyperleave2",  ("c","p","v","event")),
    ("iconclick1",   ("c","p","v","event")),
    ("iconclick2",   ("c","p","v","event")),
    ("iconrclick1",  ("c","p","v","event")),
    ("iconrclick2",  ("c","p","v","event")),
    ("icondclick1",  ("c","p","v","event")),
    ("icondclick2",  ("c","p","v","event")),
    ("idle",         ("c",)),
    ("menu1",        ("c","p","v")),
    ("menu2",        ("c","p","v")),
    ("open1",        ("old_c","new_c","fileName")),
    ("open2",        ("old_c","new_c","fileName")),
    ("openwith1",    ("c","p","v","openType","arg","ext")),
    ("openwith2",    ("c","p","v","openType","arg,ext" )),
    ("recentfiles1", ("c","p","v","fileName","closeFlag")),
    ("recentfiles2", ("c","p","v","fileName","closeFlag")),
    ("save1",        ("c","p","v","fileName" )),
    ("save2",        ("c","p","v","fileName" )),
    ("select1",      ("c","new_p","old_p","new_v","old_v")),
    ("select2",      ("c","new_p","old_p","new_v","old_v")),
    ("select3",      ("c","new_p","old_p","new_v","old_v")),
    ("set-mark",     ("c","p","v")),
    ("start1",       None),
    ("start2",       ("c","p","v","fileName" )),
    ("unselect1",    ("c","new_p","old_p","new_v","old_v")),
    ("unselect2",    ("c","new_p","old_p","new_v","old_v")),
    ("@url1",        ("c","p","v")),
    ("@url2",        ("c","p","v")),
    # Stub hooks.
    ("after-redraw-outline",         ("c",)),
    ("clear-mark",                   ("c","p","v")),
    ("close-frame",                  ("c",)),
    ("color-optional-markup",        ("colorer","p","v","s","i","j","colortag")),
    ("create-optional-menus",        ("c",)),
    ("destroy-all-global-windows",   None),
    ("draw-outline-box",             ("tree","p","v","x","y")), #
    ("draw-outline-icon",            ("tree","p","v","x","y")), #
    ("draw-outline-node",            ("tree","p","v","x","y")), #
    ("draw-outline-text-box",        ("tree","p","v","x","y")), #
    ("create-popup-menu-items",      ("c","p","v","event")),
    ("enable-popup-menu-items",      ("c","p","v","event")),
    ("init-color-markup",            ("colorer","p","v")),
    ("new",                          ("old_c","new_c")),
    ("redraw-entire-outline",        ("c",)),
    ("scan-directives",              ("c","p","v","s","old_dict","dict","pluginsList")),
    ("set-mark",                     ("c","p","v" )),
    ("show-popup-menu",              ("c","p","v","event")),
)
</t>
<t tx="ekr.20051104081502.223">typeData = {
    "arg":      types.StringType,
    "c":        leoCommands.Commands,
    "ch":       types.StringType,
    "closeFlag":types.StringType,
    "colorer":  leoColor.colorizer,
    "colortag": types.StringType,
    "dict":     types.DictType,
    "event":    Tk.Event,
    "ext":      types.StringType,
    "fileName": types.StringType,
    "i":        types.IntType,
    "j":        types.IntType,
    "label":    types.StringType,
    "new_c":    leoCommands.Commands,
    "new_p":    leoNodes.position,
    "newSel":   types.TupleType,
    "new_v":    leoNodes.position,
    "old_c":    leoCommands.Commands,
    "old_dict": types.DictType,
    "old_p":    leoNodes.position,
    "oldSel":   types.TupleType,
    "old_v":    leoNodes.position,
    "openType": types.StringType,
    "p":        leoNodes.position,
    "pluginsList": types.ListType,
    "s":        types.UnicodeType,
    "tree":     leoTkinterTree.leoTkinterTree,
    "v":        leoNodes.position,
    "undoType": types.StringType,
    "x":        types.IntType,
    "y":        types.IntType,
}
</t>
<t tx="ekr.20051104081502.224">def checkHook (tag,keywords,args=args):

    """Check to see that the keywords passed to the hook are as described in args.
    Each arg is a list of strings whose type is defined in typeData."""

    global checked, verbose
    if tag in checked: return
    ok = True
    checked.append(tag)
    if args is None: args = []
    args = list(args)
    args.sort()
    keys = list(keywords.keys())
    keys.sort()

    if len(args) != len(keys):
        g.pr("%25s expected:" % (tag),args)
        g.pr("%25s      got:" % (tag),keys)
        ok = False
    else:
        for arg,key in zip(args,keys):
            arg_type = typeData.get(arg)
            val = keywords.get(key)
            if not checkOneHook(arg_type,val):
                g.pr("%25s      arg:" % (tag), arg)
                g.pr("%25s expected:" % (tag), arg_type)
                g.pr("%25s      got:" % (tag), type(val))
                ok = False
    if ok:
        g.pr(tag)
</t>
<t tx="ekr.20051104081502.225">def checkOneHook (arg_type, val):

    if 0:
        if arg_type != type(val):
            g.trace(arg,key,arg_type,type(val))

    return (
        (arg_type is type(val)) or
        (arg_type == types.StringType and type(val) is types.UnicodeType) or
        (type(arg_type) == types.ClassType and isinstance(val,arg_type)))
</t>
<t tx="ekr.20051104081502.226"></t>
<t tx="ekr.20051104081502.227">g.rawPrint("Test of g.rawPrint")
g.redirectStdout()
g.rawPrint("Test of g.rawPrint")
g.restoreStdout()
</t>
<t tx="ekr.20051104081502.23">class position:
    def __init__(self):
        self.v = "a"
    def move(self):
        self.v = "b"

p = position()
v = p.v
g.pr("before", v, p.v, v is p.v)
p.move()
g.pr("after ", v, p.v, v is p.v)
</t>
<t tx="ekr.20051104081502.232">g.pdb()
</t>
<t tx="ekr.20051104081502.233">g.pr(g.app.debugSwitch)

g.app.debugSwitch = 0 # 2: drop into pdb

zerodivide = 1 / 0
</t>
<t tx="ekr.20051104081502.234">g.pr(c)
g.pr('use_plugins',c.use_plugins)
g.pr('tab_width',c.tab_width)
g.pr('page_width',c.page_width)
</t>
<t tx="ekr.20051104081502.24">class test_iter_class:
    def __init__ (self):
        self.vals = ("a","b","c")
        self.n = 0
    def __iter__(self):
        return self
    def next(self):
        if self.n &lt; len(self.vals):
            val = self.vals[self.n]
            self.n += 1
            return val
        else:
            raise StopIteration

def test_iter(): return test_iter_class()

vals = [val for val in test_iter()]

g.pr(vals)
</t>
<t tx="ekr.20051104081502.25">g.pr('-'*20)

# These are equivalent.
positions1 = [p for p in c.allNodes_iter(copy=True)]
positions2 = [p.copy() for p in c.allNodes_iter()]

assert(len(positions1) == len(positions2))
for i in range(len(positions1)):
    assert(positions1[i] == positions2[i])

if 0:
    for p in positions1:
        g.pr(p)
g.pr("done")
</t>
<t tx="ekr.20051104081502.26">g.pr('-'*20)

positions = [p.copy() for p in c.allNodes_iter()]

tnodes = {} ; vnodes = []
for p in c.allNodes_iter():
    t = p.v.t
    if tnodes.get(t) is None:
        tnodes[t]=t
        vnodes.append(p.v)

g.pr(len(positions),len(vnodes))

for v in vnodes:
    g.pr(v)
</t>
<t tx="ekr.20051104081502.272"></t>
<t tx="ekr.20051104081502.273">import glob,sys,traceback

def printModules():
    mods = sys.modules.keys()
    mods.sort()
    for mod in mods: g.pr(mod)

def leoModules():
    files = glob.glob(r'%s\*.py' % g.app.loadDir)
    modules = []
    for file in files:
        path,file = g.os_path_split(file)
        module,ext = g.os_path_splitext(file)
        if g.match(module,0,'leo'):
            modules.append(module)
    return modules

def delLeoModules():
    for module in leoModules():
        if module in sys.modules:
            del sys.modules[module]

def test():
    for module in leoModules():
        g.pr(module)
        exec 'import %s' % module in {},{}
        del sys.modules[module]

delLeoModules()        
test()
# printModules()
</t>
<t tx="ekr.20051104081502.274">def test():
    '''Tests whether all files can be imported.'''
    import glob, os, sys, traceback
    dir = r'c:\prog\leoCVS\leo\src'
    files = glob.glob(r'%s\*.py' % dir)
    modules = []
    for file in files:
        path,file = os.path.split(file)
        module,ext = os.path.splitext(file)
        if module[:3] == 'leo':
            modules.append(module)
    for module in modules:
        g.pr(module)
        try:
            exec 'import %s' % module in {},{}
            del sys.modules[module]
        except:
            traceback.print_exc()

def printModules():
    import sys
    mods = sys.modules.keys()
    mods.sort()
    for mod in mods: g.pr(mod)

</t>
<t tx="ekr.20051104081502.28">stack1 = ["a","b","c"]
stack2 = ["a","b","c"]
stack3 = ["a","b","d"]
stack4 = ["a","b"]
g.pr(stack1 == stack2)
g.pr(stack1 == stack3)
g.pr(stack1 == stack4)
</t>
<t tx="ekr.20051104081502.29">g.pr(p.h)
g.pr(p.childIndex())
g.pr(p.h)
</t>
<t tx="ekr.20051104081502.30">import timeit

s1 = '''\
class test(object):
    def __cmp__(self,p2):   return 0
    def equal(self,p2):     return 0
p1 = test() ; p2 = test()'''

s2 = '''\
class test:
    def __cmp__(self,p2):   return 0
    def equal(self,p2):     return 0
p1 = test() ; p2 = test()'''

s3 = '''\
import leoNodes
p1 = leoNodes.position(None,[])
p2 = leoNodes.position(None,[])'''

for s in (s1,s2,s3):
    t1 = timeit.Timer(stmt='p1==p2',setup=s).timeit()
    t2 = timeit.Timer(stmt='p1.equal(p2)',setup=s).timeit()
    g.pr("%2.2f,%2.2f,%0.2f" % (t1,t2,t1/t2))
</t>
<t tx="ekr.20051104081502.305">stuff = g.toEncodedString(u'∑','utf-8')
g.pr(type(stuff))
g.pr('*' * 10)
for ch in stuff:
    g.pr(ch, ord(ch),newline=False)
g.pr()
</t>
<t tx="ekr.20051104081502.307">g.es(c.redirect_execute_script_output_to_log_pane)
g.es(c.config.redirect_execute_script_output_to_log_pane)
g.pr('hello')

#assert c.redirect_execute_script_output_to_log_pane is True
#assert c.config.redirect_execute_script_output_to_log_pane is True
</t>
<t tx="ekr.20051104081502.31"># "LPT1:", "PRN:" and "PRN" all freeze

s = 'stuff\n'
port = 'USB002'

try:
    f = file(port,'w')
    f.write(s)
    f.flush()
    f.close()
    g.pr("done")
except IOError:
    g.pr("Can not open",port)
</t>
<t tx="ekr.20051104081502.311"># Running this as a unit test would hang the unit tests!
g.pdb()
</t>
<t tx="ekr.20051104081502.312">try:
    assert False, 'Assert False'
except AssertionError:
    g.es_exception()
</t>
<t tx="ekr.20051104081502.315"># Comment

g.pr(z)
</t>
<t tx="ekr.20051104081502.316">c.testManager.throwAssertionError()
</t>
<t tx="ekr.20051104081502.318">table = ('spawnv',None,(
    'os.spawnv',[
    r'c:\vim\vim63\gvim.exe',
    ' --servername LEO ',
    ' --remote-silent ',
    ],
    ".py")),

c.frame.menu.createOpenWithMenuFromTable(table)
</t>
<t tx="ekr.20051104081502.32">@ By far the simplest way is just to write the string to a temp file, then import the temp files.

All other approaches quickly get deeply involved with Leo's internals...
</t>
<t tx="ekr.20051104081502.320">@nowrap
aaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbb cccccccccccccccccccc ddddddddddddddd eeeeeeeeeeeeeee ffffffffffffffff 
</t>
<t tx="ekr.20051104081502.321"># To run this test, set @bool redirect_execute_script_output_to_log_pane = True in the @settings tree.

g.pr('hi')
g.pr(c.config.redirect_execute_script_output_to_log_pane)
g.pr(c.xyzzy)
</t>
<t tx="ekr.20051104081502.322">@language html
</t>
<t tx="ekr.20051104081502.323">g.pr('-'*20)
g.pr(g.getScript(c,p,forcePythonSentinels=False))
</t>
<t tx="ekr.20051104081502.324">&lt;body&gt;
@others
&lt;/body&gt;
</t>
<t tx="ekr.20051104081502.325">This is a body
</t>
<t tx="ekr.20051104081502.326">@nocolor
@pagewidth 100
@language python
</t>
<t tx="ekr.20051104081502.327">@language python

@ @rst-options
code_mode = False
show_leo_directives = True
number_code_lines = False
@c

#########################
ListManager Documentation
#########################

:Author: Steven Zatz, Modified by EKR.
:Contact: slzatz@hotmail.com
:Date: $Date: 2008/02/14 14:59:04 $
:Status: This is a "work in progress"
:Revision: $Revision: 1.247 $
:Copyright: Application and documentation use the Python license which is compatible with the GPL. 

This is experimental documentation of a program called ListManager, written in
Python and wxPython using Leo to create both the application code and the
associated reST documentation.

ListManager is an application that allows a group of people working on a joint
project to maintain a common list of todos and related items that have owners,
due dates and associated notes. The application uses mysql as its database for
group use and also uses sqlite for locally resident databases for personal
lists. It works in conjunction with Outlook to allow email messages to be sent
to ListManager for inclusion in lists and uses Outlook to mail messages to
users.

.. contents:: Table of Contents
</t>
<t tx="ekr.20051104081502.328">@language python
@color
@others

@ @rst-options
code_mode = True
@c
</t>
<t tx="ekr.20051104081502.329">@ @rst-markup

Nothing unusual in what follows:  we start with the module imports, setting some global constants including Menu Ids and read the ListManager.ini file.
</t>
<t tx="ekr.20051104081502.33">@language plain

The first idea was to use Python's imp module to simulate an import from a file.  This does not work well because imp expects a file, not a StringIO object.

The second idea was to use Python's parser module.  But this returns an instance type, not a module.

A third idea would be to subclass the file type to fool the imp module.

A fourth idea would be to use the ihooks module.  Apparently this module was designed to do something like what I am trying to do!  However, there doesn't seem to be docs for it, so I have imported the code...

@color
</t>
<t tx="ekr.20051104081502.330">from wxPython.wx import *
from wxPython.lib.mixins.listctrl import wxListCtrlAutoWidthMixin

import os
import time
import pickle
import socket
import select
import random
import ConfigParser
import threading
import re
import sys

from pywintypes import CreateGuid
from win32com.client import Dispatch
#import win32pdh
import win32api
#from win32com.client import constants #--&gt; just needed two constants...

import MySQLdb
import sqlite
import mx.DateTime

from LMDialogs import CalendarDialog, ModifierDialog, TicklerDialog, MailDialog,LoggerDialog, FinishedDialog, FindDialog, EvalDialog, TreeDialog, StartupDialog
#from wxTreeCtrl import TreeDialog

from printout import PrintTable
</t>
<t tx="ekr.20051104081502.331">@nocolor

os
    uses ``os.getcwd``, ``os.path.split``, ``os.chdir``, ``os.path.join``, ``os.path.getmtime``, ``os.startfile``, ``os.environ``

time
    uses ``time.sleep``, ``time.asctime``

pickle
    used to serialize data that is moved from Outlook to ListManager via sockets.  

socket
    as noted above, a socket is opened between Outlook and ListManager to move messages back and forth

select
    ListManager selects on the socket to see if there is a message that has been queued by Outlook

random
    used by the reminder popup to select messages

ConfigParser
    not surprisingly, using ConfiParser to parse the ListManager.ini file.  

threading
    more for fun than absolute necessity, a thread is opened on starting the program that constructs the list of owners for items.  In theory, if the datasize and number of Lists were large enough it could delay the appearance of the GUI and its initial responsiveness if we didn't construct the ownerlist in a thread.  On the other hand, it really let me play with threads and with creating a custom event that signalled the construction of the owner list to the main thread by posting a custom event.

re
    mainly using ``re.sub('[\\/:*"&lt;&gt;|\?]','-',f)`` to make sure that files are constructed only with legal characters.  Also searching the body text of nodes using re because it allows case insensitive searches through ``re.compile(pat, re.I)``.

pywintypes.CreateGuid
    probably should use pure python GUID that is in ASPN cookbook but it was easiest to just use the Windows GUID function.  Thank you Mark Hammond for win32all.

win32com.client.Dispatch
    used when launching Outlook to send email messages

win32api
    using win32api.GetUserName() in case there is no user name in the ini file or no ini file

MySQLdb
    using Andy Dustman's python extension module to connect to mysql back-end.

sqlite
    using  D. Richard Hipp's python extension to connect to local sqlite databases

import mx.DateTime
    using Marc-André Lemburg's mx.DateTime for dealing with datetime stuff in the databases

CalendarDialog, ModifierDialog, TicklerDialog, MailDialog,LoggerDialog, FinishedDialog, FindDialog, EvalDialog, TreeDialog, StartupDialog
   should just import LMDialogs and then access each dialog class by LM.WhateverDialog

printout.PrintTable
    There was an existing wxPython print module for printing from tables that I have modified to print Lists.

*#from win32com.client import constants*
    probably not wise but since the app only needs two constants from this module, just set the directly.  If MSFT decides to change the api, this is not good.
</t>
<t tx="ekr.20051104081502.332">cwd = os.getcwd()
DIRECTORY = os.path.split(cwd)[0]
os.chdir(DIRECTORY)
del cwd

#Outlook Constants
olMailItem = 0x0
olFlagMarked = 0x2

OFFLINE_ONLY = False #False-&gt; Online only  ; True-&gt; Online and Offline possible; REMOTE_HOST = None -&gt; Offline only

VERSION = '1.02'

@ @rst-markup

The following two global constants are needed to create emails through Outlook via COM::

    olMailItem = 0x0
    olFlagMarked = 0x2

For some reason, it seemed easier to just include them explicitly rather than worrying about generating all the Outlook constants in order to use early binding.  I supppose if MSFT changes the api, that would be a problem.
</t>
<t tx="ekr.20051104081502.333">@ @rst-markup
Menu Ids -- not much more to say although there should be something to say.
@c

#File Menu-----------------#
idNEWLIST = 1000
idOPENLIST = 1010
idCLOSELIST = 1015
idCLOSEALL = 1017
idSAVEAS = 1020
idDELETELIST = 1025
idPAGESETUP = 1030
idPRINT = 1035
idPRINTPREV = 1040
idMAILLIST = 1045
idOFFLINE = 1048
idEXIT = 1050

#Edit Menu-----------------
idCUT = 1055
idCOPY = 1060
idPASTE = 1065
idDELETEITEMS = 1070
idCOMBINEITEMS = 1075
idFIND = 1080

#Item Menu-------------------
idNEWITEM = 1085
idTOGGLEFINISHED = 1090
idEDITOWNER = 1095
idDUEDATE = 1100
idEDITNOTE = 1105
idMAILITEM =1110

#Diplay Menu---------------------
idSHOWFINISHED = 1115
idSHOWALL = 1120
idREFRESH = 1125
idDISPLAYDATE = 1130

#Tool Menu------------------------
idTICKLERACTIVE = 1135
idSHOWNEXT = 1140
idSYNC = 1145
idARCHIVE = 1150
idEVALUATE = 1155
idTOOLPRINT = 1165
idSENDTO = 1170

#Help Menu-------------------------
idABOUT = 1175
idHELP = 1180


</t>
<t tx="ekr.20051104081502.334">config_file = os.path.join(DIRECTORY, "List Manager.ini")
defaults = dict(pw='python', db='listmanager', ext='txt', local='wxLMDB:sqlite', x='700', y='400')
cp = ConfigParser.ConfigParser(defaults=defaults)
cp.read(config_file) #ConfigParser closes the file

USER = cp.has_option('User','user') and cp.get('User','user') or win32api.GetUserName()

# the following all have default values provided in the constructor
PW = cp.get('User','pw')
DB = cp.get('Database','db')
NOTE_EXT = cp.get('Note','ext')
LOCAL_HOST = cp.get('Hosts','local')
X = cp.getint('Configuration','x')
Y = cp.getint('Configuration','y')

# the folloowing default to None
MAIL_LIST_PATH = cp.has_option('Mail','path') and cp.get('Mail','path') or None
QUICK_LIST = cp.has_option('User','quicklist') and cp.get('User','quicklist') or None

# the following default to False
STARTUP_DIALOG = cp.has_option('User','startup_dialog') and cp.getboolean('User','startup_dialog')
DELETE_LIST = cp.has_option('User','delete_list') and cp.getboolean('User','delete_list')
OUTLOOK = cp.has_option('Mail','outlook') and cp.getboolean('Mail','outlook')

if cp.has_option('Hosts','remote'):
    REMOTE_HOST = cp.get('Hosts','remote')
else:
    REMOTE_HOST = None
    OFFLINE_ONLY = True

# reading it again because of the way defaults are handled
cp = ConfigParser.ConfigParser()
cp.read(config_file) #ConfigParser closes the file

if cp.has_section('Synchronization'):
    SYNC_TABLES = [t[1] for t in cp.items('Synchronization')]
else:
    SYNC_TABLES = ['follow_ups']

</t>
<t tx="ekr.20051104081502.335">@nocolor

.. sidebar:: A typical *List Manager.ini* file:

    ::

        [Files]
        path0 = wxLMDB:sqlite:mine
        path1 = nycpsszatzsql:mysql:follow_ups

        [Database]
        db = listmanager

        [Note]
        ext = txt

        [Synchronization]
        sync2 = follow_ups
	sync1 = test

        [Hosts]
        remote = nycpsszatzsql:mysql
        local = wxLMDB:sqlite

        [User]
        startup_dialog = true
        user = szatz
        pw = python

        [Mail]
	outlook = true
	path = wxLMDB:sqlite:mail_transfer

        [Configuration]
        y = 642
        x = 975

Application uses the ``ConfigParser`` module ito parse the ini file.  Unfortunately, ``ConfigParser`` doesn't work exactly like I think it should although it has been improved in 2.3.  My main issue is in the handling of default options.  The default options specified through the constructor show up in every section.  For example, if you use the items(*section*) method
then in addition to returning a list of tuples with whatever option/value pairs exist in the section, the list will include all the default option/value pairs, which does not make a whole lot of sense to me.  At the least, there should be a 'nodefaults' argument whose default was *False* but which could be set to *True*.  The following methods should have this option:

- items
- options
- has_option

In any event, because a nodefaults option does not exist, I create the ConfigParser object twice -- once with default options and once without them.  

The application will work fine if there is no ini file. In an effort to save some typing but not be too obscure, many of the options are read such that they default to the correct value either through explicit defaults in the constructor or statements that evaluate to *None* or *False*.

    ``QUICK_LIST = cp.has_option('User','quicklist') and cp.get('User','quicklist') or None``

    ``OUTLOOK = cp.has_option('Mail','outlook') and cp.getboolean('Mail,'outlook')``
</t>
<t tx="ekr.20051104081502.336">class ListManager(wxFrame):
    @others

@ @rst-markup

ListManager is the main class in the application and is a sublass of ``wxFrame``, which is typical for a wxPython application.  From a GUI standpoint, the main child window of the ListManager object is a ``wxNoteBook`` object that holds one ``wxListCtrl`` per notebook page and one ``wxListBox``.  The ``wxListCtrl``\s display item information (e.g., name of the item, owners of the item, etc.) for a particular List and the ``wxListBox``\es displays a list of owners that is used to filter the items displayed by the ``wxListCtrl`` object.

Each ``wxListCtrl`` object has its own set of events that it is hooked to (see CreateNewNotebookPage`&lt;&lt; ListControl Events &gt;&gt;`_.
</t>
<t tx="ekr.20051104081502.337"></t>
<t tx="ekr.20051104081502.338">def __init__(self, parent, id, title, size):
    wxFrame.__init__(self, parent, id, title, size = size)

    self.SetIcon(wxIcon('bitmaps//wxpdemo.ico', wxBITMAP_TYPE_ICO))
    self.CreateStatusBar()

    &lt;&lt; ListManager Attributes &gt;&gt;
    &lt;&lt; Menu Setup &gt;&gt;
    &lt;&lt; Toolbar Setup &gt;&gt;
    &lt;&lt; Menu/Toolbar Events &gt;&gt;
    &lt;&lt; Create Controls&gt;&gt;
    &lt;&lt; Layout Stuff &gt;&gt;
    &lt;&lt; Other Events &gt;&gt;
    &lt;&lt; GUI Instance Objects &gt;&gt;
    &lt;&lt; Create Socket &gt;&gt;
    &lt;&lt; Load Recent Files &gt;&gt;
    &lt;&lt; Idle Timer &gt;&gt;

    ownerthread = threading.Thread(target=self.createownerlist)
    ownerthread.start()
    self.ModifierDialog = None

</t>
<t tx="ekr.20051104081502.339">@nocolor

The ListManager ``__init__`` method is pretty straightforward.  The ``__init__`` arguments are the ones that need to be passed to ``wxFrame __init__`` method. The wxFrame class has the following form:

    ``wxFrame(parent, id, title, pos=wxDefaultPosition, size=wxDefaultSize, style=wxDEFAULT_FRAME_STYLE, name="frame")``

The default style (``wxDEFAULT_FRAME_STYLE``) includes ``wxMINIMIZE_BOX``, ``wxMAXIMIZE_BOX``, ``wxRESIZE_BORDER``, ``wxSYSTEM_MENU``, ``wxCAPTION`` (the latter is the text that appears in the title bar).

``SetIcon`` is a method of ``wxFrame`` that sets the icon in the upper left of the title bar of the frame.  The wxIcon class has the following form:

    ``wxIcon(filename, type, desiredWidth=-1, desiredHeight=-1)``

``CreateStatusBar`` is a method of ``wxFrame``. The wxPython form is:

        ``CreateStatusBar(number=1, style=0, id=-1)``

*number* --&gt;
    number of fields to create. Specify a value greater than 1 to create a multi-field status bar.

``CreateStatusBar`` needs to be called before &lt;&lt; Load Recent Files &gt;&gt;.

The various sections of ``__init__`` are explained in their corresponding section::

    &lt;&lt; ListManager Attributes &gt;&gt;
    &lt;&lt; Menu Setup &gt;&gt;
    &lt;&lt; Toolbar Setup &gt;&gt;
    &lt;&lt; Menu/Toolbar Events &gt;&gt;
    &lt;&lt; Create Controls&gt;&gt;
    &lt;&lt; Layout Stuff &gt;&gt;
    &lt;&lt; Other Events &gt;&gt;
    &lt;&lt; GUI Instance Objects &gt;&gt;
    &lt;&lt; Create Socket &gt;&gt;
    &lt;&lt; Load Recent Files &gt;&gt;
</t>
<t tx="ekr.20051104081502.34">import imp
import StringIO

@
load_module( name, file, filename, description) 

Load a module that was previously found by find_module() (or by an otherwise conducted search yielding compatible results). This function does more than importing the module: if the module was already imported, it is equivalent to a reload()! The name argument indicates the full module name (including the package name, if this is a submodule of a package). The file argument is an open file, and filename is the corresponding file name; these can be None and '', respectively, when the module is not being loaded from a file. The description argument is a tuple, as would be returned by get_suffixes(), describing what kind of module must be loaded. 
If the load is successful, the return value is the module object; otherwise, an exception (usually ImportError) is raised. 

Important: the caller is responsible for closing the file argument, if it was not None, even when an exception is raised. This is best done using a try ... finally statement.
@c

s = """

def foobar(): pass

"""

@ get_suffixes( ) 

Return a list of triples, each describing a particular type of module. Each triple has the form (suffix, mode, type), where suffix is a string to be appended to the module name to form the filename to search for, mode is the mode string to pass to the built-in open() function to open the file (this can be 'r' for text files or 'rb' for binary files), and type is the file type, which has one of the values PY_SOURCE, PY_COMPILED, or C_EXTENSION, described below.
@c

g.pr('-' * 20)
description = (".py","r",imp.PY_SOURCE)
theFile = StringIO.StringIO(s) # Create a file-like object
g.pr(repr(theFile))
try:
    imp.load_module("myModule",theFile,"myFileName",description)
except:
    g.es_exception()



</t>
<t tx="ekr.20051104081502.340">self.PropertyDicts = []
self.ItemLists = []
self.ListCtrls = []
self.OwnerLBoxes = []

self.L = -1
self.curIdx = -1

self.printdata = wxPrintData()
self.printdata.SetPaperId(wxPAPER_LETTER)
self.printdata.SetOrientation(wxPORTRAIT)

#self._options = {} #would be used in loadconfig

self.copyitems = []    
self.modified = {}
self.tickler_active = False

#there is a wxPanel in the AddListControl method so each wxListCtrl has a different panel as parent
#there is a nb_sizer = wxNotebookSizer(nb) class but doesn't seem to make any difference

self.editor = []

self.Cursors = {}
self.sqlite_connections = []
self.popupvisible = False
self.in_place_editor = None
self.showrecentcompleted = 0

self.LC_font = wxFont(9, wxSWISS, wxNORMAL, wxNORMAL)

self.date_titles = {'createdate':"Create Date",'duedate':"Due Date",'timestamp':"Last Modified",'finisheddate':"Completion Date"}
self.attr2col_num = {'priority':0, 'name':1,'owners':2, 'date':3}

self.FindDialog = FindDialog(self, "Find...", "")
self.EvalDialog = EvalDialog(self, "Evaluate...", "")
</t>
<t tx="ekr.20051104081502.341">@nocolor

self.PropertyDicts
    list of dictionaries that describe properties of each ListManager List (note that when referring to a collection of ListManager items a capital *L* List and table are used interchangeably).

self.ItemLists
    list of lists that consist of instance objects of class ``Item``.  Each of the lists contained in self.ItemLists correspond to the items that are being displayed in the ListCtrl.  So ``self.Itemlist[2]`` corresponds to the 2nd tab of the notebook and to the items in self.ListCtrls[2].

The class ``Item`` is just an empty class being used as a convenience to hold item attributes::

    class Item:
        pass

The purpose of the class is just to create an object that can have various attributes as follows:

+-----------------+----------------------------------------------------+
|item.id          |GUID                                                |
+-----------------+----------------------------------------------------+
|item.name        |string that describes the item                      |
+-----------------+----------------------------------------------------+
|item.priority    |integer ranging from 1 (high) to 3 (low)            |
+-----------------+----------------------------------------------------+
|item.owners      |list of the form ["Zatz, Steve", "Hoffman, Steve"]  |
+-----------------+----------------------------------------------------+
|item.note        |string that provides additional info on item        |
+-----------------+----------------------------------------------------+
|item.timestamp   |timestamp indicating when an item was last modified |
+-----------------+----------------------------------------------------+
|item.duedate     |default is None; mx.DateTime date                   |
+-----------------+----------------------------------------------------+
|item.createdate  |mx.DateTime.now() mx.DateTime timestamp             |
+-----------------+----------------------------------------------------+
|item.finisheddate|efaut is None; mx.DateTime date                     |
+-----------------+----------------------------------------------------+

self.ListCtrls
    list of of instance objects of class ListCtrls, which are a subclass of wxPython class wxListCtrl.

self.OwnerLBoxes
    list of of instance objects of wxPython class wxListBox, which is a simple one column List Control.

The wxPython constructor for a wxListBox is:

    ``wxListBox(parent, id, pos=wxDefaultPosition, size=wxDefaultSize, choices=[], style=0)``

self.L
    index of the currently active notebook tab.  If there are any tabs in the notebook then one of them is always selected.  If there are no tabs then this is indicated by setting ``self.L = -1``.

self.curIdx
    currently selected row in the active ``ListCtrl``.  There are times like after a row is deleted in which there may be rows visible but no row is selected.

The following lines set the default printer data::

    self.printdata = wxPrintData()
    self.printdata.SetPaperId(wxPAPER_LETTER)
    self.printdata.SetOrientation(wxPORTRAIT)


The wxPython class ``wxPrintData`` holds a variety of information related to printers and printer device contexts. This class is used to create a wxPrinterDC and a wxPostScriptDC. It is also used as a data member of wxPrintDialogData and wxPageSetupDialogData, as part of the mechanism for transferring data between the print dialogs and the application.

self.copyitems
    list that contains item instance objects that have been copied from one list to be moved to another list.

self.modified
    dictionary that contains the information concerning whether any of several elements have been changed.  Chose a dictionary more to test the idea that I could create a simple method that would update the dictionary and here is an example:

    ``EVT_TEXT(self, self.name.GetId(), lambda e: self.modified.update({'name':1}))``

So this lambda function means that if an ``EVT_TEXT`` event occurs then update the dictionary by adding the key to the dictionary (the value is not used and arbitrarily set to 1).  The wxPython form for the macro ``EVT_TEXT`` is:

    ``EVT_TEXT(window, id, func)``

A ``wxEVT_COMMAND_TEXT_UPDATED`` event is generated when the text in a ``wxTextCtrl`` changes and that is what ``EVT_TEXT`` catches. Note that this event will always be sent when the text control’s content changes - whether this is due to user input or comes programmatically (for example, if ``SetValue()`` is called)

self.Cursors
    dictionary that holds the database cursor objects.  For example, it will look like:  ``{'sqlite':&lt;sqlite cursor object&gt;,'nycpsltszatz':&lt;mysql cursor object&gt;}``

self.tickler_active
    booean determines whether the tickler capabililty is active; can be shut off by unchecking Tickler menu item

self.editor
    list that holds the dictionaries that describe the notes that are edited by the external text editor::

        [
        {
        'table': 'mine',
        'host': 'wxLMDB:sqlite',
        'path': 'C:\\DOCUME~1\\STEVEN~1\\LOCALS~1\\Temp\\Journal Scan schedule.txt',
        'id': '1AB34FB9-9EE6-4AFC-8AF0-FFCA50103BF3',
        'time': 1070850894
        }, 
        {
        'table': 'factoids',
        'host': 'wxLMDB:sqlite',
        'path': 'C:\\DOCUME~1\\STEVEN~1\\LOCALS~1\\Temp\\How many cme programs are sponsored- - 91%.txt', 
        'id': '9CAC4D18-DE1C-4535-B9A5-4CDB1AD3F304', 
        'time': 1070850908
        }
        ]

The method that uses self.editor is `&lt;&lt; Check if Edited File has Changed &gt;&gt;`_.

There is a ``wxPanel`` in the ``AddListControl`` method so each ``wxListCtrl`` has a different panel as parent.

There is a nb_sizer = wxNotebookSizer(nb) class but doesn't seem to make any difference.

self.sqlite_connections
    Here because the sqlite connection has a weakreference that deletes it when you want it around

self.popupvisible
    boolean that is used to ensure that two reminder popups aren't visible at the same time.

self.in_place_editor 
    boolean that indicates whether the inplace item name text editor is active or not.

self.showrecentcompleted
    integer that determines the number of days in the past to retain completed items in the display.

self.LC_font
    default font for all of the ``ListCtrls``:  ``self.LC_font = wxFont(9, wxSWISS, wxNORMAL, wxNORMAL)``

The wxPython ``wxFont`` constructor is:

    ``wxFont(pointSize, family, style, weight, underline=False, faceName="", wencoding=wxFONTENCODING_DEFAULT)``

self.date_titles
    dictionary that holds the various dates that are associated with each item and which can be displayed in the date column.  The dictionary is not modified.  We use one column of each ``ListCtrl`` to display any one of the four dates that that the application tracks. This dictionary associates the item attribute with the text that will be displayed in both the column header for the date and in the dropdown that allows you to change the date:  ``self.date_titles = {'createdate':"Create Date",'duedate':"Due Date",'timestamp':"Last Modified",'finisheddate':"Completion Date"}``

self.attr2col_num
    dictionary that associates the item attribute with the column that attribute is displayed in in the ``ListCtrl``:  ``self.attr2col_num = {'priority':0, 'name':1,'owners':2, 'date':3}``

The following lines construct the Find Dialog and the Dialog that catches errors and shows expressions for debugging::

    self.FindDialog = FindDialog(self, "Find...", "")
    self.EvalDialog = EvalDialog(self, "Evaluate...", "")
</t>
<t tx="ekr.20051104081502.342">filemenu = wxMenu()
filemenu.Append(idNEWLIST, "New List...", "Create a new List")
filemenu.Append(idOPENLIST, "Open List...", "Open a List")
filemenu.Append(idCLOSELIST, "Close", "Close the current List")
filemenu.Append(idCLOSEALL, "Close All", "Close all open Lists")
filemenu.Append(idSAVEAS, "Save As Text File...", "Save the current List")
filemenu.AppendSeparator()
filemenu.Append(idDELETELIST, "Delete List...", "Select a list to delete")
filemenu.AppendSeparator()
filemenu.Append(idPAGESETUP, "Page Setup...")
filemenu.Append(idPRINT, "Print...", "Print the current view")
filemenu.Append(idPRINTPREV, "Print Preview")
filemenu.AppendSeparator()
filemenu.Append(idMAILLIST, "Mail...", "Mail the current view")
filemenu.AppendSeparator()
filemenu.AppendCheckItem(idOFFLINE, "Work Offline")
filemenu.AppendSeparator()
filemenu.Append(idEXIT, "Exit", "Exit the program")

editmenu = wxMenu()
editmenu.Append(idCUT, "Cut\tCtrl+X")
editmenu.Append(idCOPY, "Copy\tCtrl+C")
editmenu.Append(idPASTE, "Paste\tCtrl+V")
editmenu.AppendSeparator()
editmenu.Append(idDELETEITEMS, "Delete")
editmenu.AppendSeparator()
editmenu.Append(idCOMBINEITEMS, "Combine Items...")
editmenu.AppendSeparator()
editmenu.Append(idFIND, "Find...")

itemmenu = wxMenu()
itemmenu.Append(idNEWITEM, "New Item")
itemmenu.AppendSeparator()
itemmenu.Append(idTOGGLEFINISHED, "Toggle Finished")
itemmenu.Append(idEDITOWNER, "Owner...")
itemmenu.Append(idDUEDATE, "Due Date...")
itemmenu.Append(idEDITNOTE, "Note...")
itemmenu.AppendSeparator()
itemmenu.Append(idMAILITEM, "Mail...")

displaymenu = wxMenu()
displaymenu.Append(idSHOWFINISHED, "Show/Hide Finished...")
displaymenu.AppendSeparator()
displaymenu.Append(idSHOWALL, "Show All", "Show all items in the current list")
displaymenu.AppendSeparator()
displaymenu.Append(idREFRESH, "Refresh Display", "Refresh the Display")
displaymenu.Append(idDISPLAYDATE, "Select Date to Display")

toolmenu = wxMenu()
toolmenu.AppendCheckItem(idTICKLERACTIVE, "Tickler Active")
toolmenu.Check(idTICKLERACTIVE,False)
toolmenu.Append(idSHOWNEXT, "Show Next Reminder")
toolmenu.Append(idSYNC, "Synchronize local and remote DBs")
toolmenu.Append(idARCHIVE, "Archive completed items in list...")
toolmenu.Append(idEVALUATE, "Evaluate an expression...")

helpmenu = wxMenu()
helpmenu.Append(idABOUT, "About ListManager")
helpmenu.Append(idHELP, "Help")

menubar = wxMenuBar()
menubar.Append(filemenu, '&amp;File')
menubar.Append(editmenu, 'Edit')
menubar.Append(itemmenu, 'Item')
menubar.Append(displaymenu, 'Display')
menubar.Append(toolmenu, 'Tools')
menubar.Append(helpmenu, 'Help')
self.SetMenuBar(menubar)
toolmenu.Enable(idSHOWNEXT,self.tickler_active)
filemenu.Enable(idDELETELIST,DELETE_LIST)
filemenu.Check(idOFFLINE,OFFLINE_ONLY)

#file history
self.filehistory = wxFileHistory()
self.filehistory.UseMenu(filemenu)

</t>
<t tx="ekr.20051104081502.343">@nocolor

+------------------------+------------------------------------------------+
|**File Menu**           |                                                |
+------------------------+------------------------------------------------+
| "New List... "         ||nl| ``self.OnNewList``                         |
+------------------------+------------------------------------------------+
| "Open List..."         ||ol| ``self.OnOpenList``                        |
+------------------------+------------------------------------------------+
| "Close"                |``self.OnCloseList``                            |
+------------------------+------------------------------------------------+
| "Close All"            |``self.OnCloseAll``                             |
+------------------------+------------------------------------------------+
| "Save As Text File..." |``self.OnSaveAsText``                           |
+------------------------+------------------------------------------------+
| "Delete List..."       ||de| ``self.OnDeleteList``                      |
+------------------------+------------------------------------------------+
| "Page Setup..."        ||ps| ``self.OnPageSetup``                       |
+------------------------+------------------------------------------------+
| "Print..."             ||pt| ``self.OnPrint``                           |
+------------------------+------------------------------------------------+
| "Print Preview"        ||pp| ``lambda e: self.OnPrint(e, prev=True)``   |
+------------------------+------------------------------------------------+
| "Mail..."              |``self.OnMailView``                             |
+------------------------+------------------------------------------------+
| "Work Offline"         |``self.OnWorkOffline``                          |
+------------------------+------------------------------------------------+
| "Exit"                 |``self.OnExit``                                 |
+------------------------+------------------------------------------------+
| **Edit Menu**          |                                                |
+------------------------+------------------------------------------------+
| "Cut" [Ctrl+X ]        ||ec| ``lambda e: self.OnCopyItems(e, cut=True)``|
+------------------------+------------------------------------------------+
| "Copy" [Ctrl+C]        ||ey| ``self.OnCopyItems``                       |
+------------------------+------------------------------------------------+
| "Paste" [Ctrl+V]       ||ep| ``self.OnPasteItems``                      |
+------------------------+------------------------------------------------+
| "Delete"               ||de| ``self.OnDeleteItems``                     |
+------------------------+------------------------------------------------+
| "Combine Items..."     |``self.OnCombineItems``                         |
+------------------------+------------------------------------------------+
| "Find..."              ||fi| ``self.OnFind``                            |
+------------------------+------------------------------------------------+
| **Item Menu**          |                                                |
+------------------------+------------------------------------------------+
| "New Item"             ||ni| ``self.OnNewItem``                         |
+------------------------+------------------------------------------------+
| "Toggle Finished"      ||co| ``self.OnToggleFinished``                  |
+------------------------+------------------------------------------------+
| "Owner..."             ||ow| ``self.OnEditOwner``                       |
+------------------------+------------------------------------------------+
| "Due Date..."          ||dd| ``self.OnDueDate``                         |
+------------------------+------------------------------------------------+
| "Note..."              ||en| ``self.OnEditNote``                        |
+------------------------+------------------------------------------------+
| "Mail..."              ||mi| ``self.OnMailItem``                        |
+------------------------+------------------------------------------------+
| **Display Menu**       |                                                |
+------------------------+------------------------------------------------+
| "Show/Hide Finished..."|``self.OnShowFinished``                         |
+------------------------+------------------------------------------------+
| "Show All"             |``self.OnShowAll``                              |
+------------------------+------------------------------------------------+
| "Refresh Display"      ||re| ``self.OnRefresh``                         |
+------------------------+------------------------------------------------+
|"Select Date to Display"|``self.OnDisplayDateCategory``                  |
+------------------------+------------------------------------------------+
| **Tool Menu**          |                                                |
+------------------------+------------------------------------------------+
| "Tickler Active"       |``self.OnActivateTickler``                      |
+------------------------+------------------------------------------------+
| "Show Next Reminder"   |``self.OnShowTickler``                          |
+------------------------+------------------------------------------------+
| "Synchronize ..."      |``self.OnSync``                                 |
+------------------------+------------------------------------------------+
| "Archive completed..." |``self.OnArchive``                              |
+------------------------+------------------------------------------------+
| "Evaluate expression"  |``self.OnShowEvaluate``                         |
+------------------------+------------------------------------------------+
| **Help Menu**          |                                                |
+------------------------+------------------------------------------------+
| "About ListManager"    |``self.OnShowAbout``                            |
+------------------------+------------------------------------------------+
| "Help"                 |``self.OnShowHelp``                             |
+------------------------+------------------------------------------------+




</t>
<t tx="ekr.20051104081502.344">tb = self.CreateToolBar(wxTB_HORIZONTAL|wxTB_FLAT)

tb.AddLabelTool(idNEWLIST, "New (local) List", wxBitmap('bitmaps\\new.bmp'), shortHelp="Create New List")
tb.AddLabelTool(idOPENLIST, "Open", wxBitmap('bitmaps\\open.bmp'), shortHelp="Open List")
tb.AddSeparator()
tb.AddLabelTool(idTOOLPRINT, "Print", wxBitmap('bitmaps\\print.bmp'), shortHelp="Print List")
tb.AddLabelTool(idPRINTPREV, "Preview", wxBitmap('bitmaps\\preview.bmp'), shortHelp="Print Preview")
tb.AddLabelTool(idPAGESETUP, "Setup", wxBitmap('bitmaps\\setup.bmp'), shortHelp="Page Setup")
tb.AddSeparator()
tb.AddLabelTool(idNEWITEM, "New Item", wxBitmap('bitmaps\\new_item.bmp'), shortHelp="Create New Item")
tb.AddSeparator()
tb.AddLabelTool(idREFRESH, "Refresh", wxBitmap('bitmaps\\refresh.bmp'), shortHelp="Refresh Display")     
tb.AddSeparator()
tb.AddLabelTool(idEDITNOTE, "Edit Note", wxBitmap('bitmaps\\edit_doc.bmp'), shortHelp="Edit Note")
tb.AddSeparator()
tb.AddLabelTool(idFIND, "Find", wxBitmap('bitmaps\\find.bmp'), shortHelp = "Find Item")        
tb.AddSeparator()
tb.AddLabelTool(idCUT, "Cut", wxBitmap('bitmaps\\editcut.bmp'), shortHelp ="Cut Item")        
tb.AddLabelTool(idCOPY, "Copy", wxBitmap('bitmaps\\copy.bmp'), shortHelp ="Copy Item")
tb.AddLabelTool(idPASTE, "Paste", wxBitmap('bitmaps\\paste.bmp'), shortHelp="Paste Item")
tb.AddSeparator()
tb.AddLabelTool(idTOGGLEFINISHED, "Toggle Date", wxBitmap('bitmaps\\filledbox.bmp'), shortHelp="Toggle Finished Date")
tb.AddLabelTool(idDELETEITEMS, "Delete", wxBitmap('bitmaps\\delete.bmp'), shortHelp="Delete Item")
tb.AddLabelTool(idDUEDATE, "Due Date", wxBitmap('bitmaps\\calendar.bmp'), shortHelp="Enter Due Date")
tb.AddLabelTool(idEDITOWNER,"Owner", wxBitmap('bitmaps\\owners.bmp'), shortHelp="Select Owner(s)")
tb.AddSeparator()
tb.AddLabelTool(idMAILITEM, "Mail", wxBitmap('bitmaps\\mail.bmp'), shortHelp="Mail Item")

if QUICK_LIST:
    tb.AddSeparator()
    tb.AddLabelTool(idSENDTO, "Send to", wxBitmap('bitmaps\\sendto.bmp'), shortHelp="Send to %s"%QUICK_LIST)

tb.Realize()
</t>
<t tx="ekr.20051104081502.346">#File Menu ------------------------------------
EVT_MENU(self, idNEWLIST, self.OnNewList)
EVT_MENU(self, idOPENLIST, self.OnOpenList)
EVT_MENU(self, idCLOSELIST, self.OnCloseList)
EVT_MENU(self, idCLOSEALL, self.OnCloseAll)
EVT_MENU(self, idSAVEAS, self.OnSaveAsText)
EVT_MENU(self, idDELETELIST, self.OnDeleteList)
EVT_MENU(self, idPAGESETUP, self.OnPageSetup)
EVT_MENU(self, idPRINT, self.OnPrint)
EVT_MENU(self, idPRINTPREV, lambda e: self.OnPrint(e, prev=True))
EVT_MENU(self, idOFFLINE, self.OnWorkOffline)
EVT_MENU(self, idMAILLIST, self.OnMailView)      
EVT_MENU_RANGE(self, wxID_FILE1, wxID_FILE9, self.OnFileList)
EVT_MENU(self, idEXIT, self.OnExit)
#Edit Menu ------------------------------------
EVT_MENU(self, idCUT, lambda e: self.OnCopyItems(e, cut=True))        
EVT_MENU(self, idCOPY, self.OnCopyItems)
EVT_MENU(self, idPASTE, self.OnPasteItems)
EVT_MENU(self, idDELETEITEMS, self.OnDeleteItems)
EVT_MENU(self, idCOMBINEITEMS, self.OnCombineItems)
EVT_MENU(self, idFIND, self.OnFind)
#item Menu ------------------------------------
EVT_MENU(self, idNEWITEM, self.OnNewItem)
EVT_MENU(self, idTOGGLEFINISHED, self.OnToggleFinished)             
EVT_MENU(self, idDUEDATE, self.OnDueDate)
EVT_MENU(self, idEDITOWNER, self.OnEditOwner)
EVT_MENU(self, idEDITNOTE, self.OnEditNote)
EVT_MENU(self, idMAILITEM, self.OnMailItem)
#Dips Menu ------------------------------------
EVT_MENU(self, idSHOWFINISHED, self.OnShowFinished)
EVT_MENU(self, idSHOWALL, self.OnShowAll)
EVT_MENU(self, idREFRESH, self.OnRefresh)
EVT_MENU(self, idDISPLAYDATE, self.OnDisplayDateCategory)
#Tool Menu ---------------------------------------
EVT_MENU(self, idTICKLERACTIVE, self.OnActivateTickler)
EVT_MENU(self, idSHOWNEXT, self.OnShowTickler)
EVT_MENU(self, idSYNC, self.OnSync)
EVT_MENU(self, idARCHIVE, self.OnArchive)
EVT_MENU(self, idEVALUATE, self.OnShowEvaluate)
#Help Menu -----------------------------------------
EVT_MENU(self, idABOUT, self.OnShowAbout)
EVT_MENU(self, idHELP, self.OnShowHelp)

EVT_TOOL(self, idTOOLPRINT, lambda e: self.OnPrint(e,showprtdlg=False))

if QUICK_LIST:
    EVT_TOOL(self, idSENDTO, lambda e: self.OnMoveToSpecificList(e,QUICK_LIST))
</t>
<t tx="ekr.20051104081502.348">upper_panel = wxPanel(self, -1)   #size = (900,400)
bottom_panel = wxPanel(self, -1, size = (900,150)) #900 note that 000 seems to work???

nb = wxNotebook(upper_panel, -1, size=(900,500), style=wxNB_BOTTOM)

f = wxFont(10, wxSWISS, wxNORMAL, wxNORMAL)
self.name = wxTextCtrl(bottom_panel, -1, size = (285,42), style = wxTE_MULTILINE|wxTE_RICH2)#34 #wxTE_PROCESS_ENTER
self.name.SetDefaultStyle(wxTextAttr("BLACK", font = f))

self.owners = wxTextCtrl(bottom_panel, -1, size = (250,42),style = wxTE_MULTILINE|wxTE_RICH2)
self.owners.SetDefaultStyle(wxTextAttr("BLACK", font = f))

self.note = wxTextCtrl(bottom_panel, -1, size = (400,50), style=wxTE_MULTILINE)

</t>
<t tx="ekr.20051104081502.35">if 0:
    class myFile(file):
        pass

    g.pr(myFile)
    g.pr(issubclass(myFile,file))
    g.pr(isinstance(myFile,file))
    g.pr(super(myFile))
    g.pr(__import__)

if 0:
    old_import = __import__

    def myImport(*args,**keys):
        g.pr("myImport")
        global old_import
        old_import(*args,**keys)

    __import__ = myImport

mod = __import__("leoApp")
g.pr(mod)
</t>
<t tx="ekr.20051104081502.350">EVT_TEXT(self, self.name.GetId(), lambda e: self.modified.update({'name':1}))
EVT_TEXT(self, self.note.GetId(), lambda e: self.modified.update({'note':1}))
EVT_TEXT(self, self.owners.GetId(), lambda e: self.modified.update({'owners':1}))

EVT_CLOSE(self, self.OnWindowExit)

EVT_IDLE(self, self.OnIdle)

</t>
<t tx="ekr.20051104081502.352">#Appears necessary to really get the listcontrol to size with the overall window  
#upper_panel sizer
sizer = wxBoxSizer(wxHORIZONTAL)
sizer.Add(nb,1,wxALIGN_LEFT|wxEXPAND)
upper_panel.SetSizer(sizer)        

#sizer for the row of data items
box = wxBoxSizer(wxHORIZONTAL)
box.Add(self.name,1,wxEXPAND)
box.Add(self.owners,0)

#bottom_panel sizer  
sizer = wxBoxSizer(wxVERTICAL)        
sizer.AddSizer(box, 0, wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5)
sizer.Add(self.note,1,wxALIGN_LEFT|wxEXPAND)
bottom_panel.SetSizer(sizer)

sizer = wxBoxSizer(wxVERTICAL)
sizer.Add(upper_panel,1,wxALIGN_TOP|wxEXPAND)
sizer.Add(bottom_panel,0,wxALIGN_TOP|wxEXPAND)

self.SetAutoLayout(1)
self.SetSizer(sizer)
#sizer.Fit(self) #actively does bad things to the dimensions on startup
</t>
<t tx="ekr.20051104081502.354">self.toolmenu = toolmenu
self.filemenu = filemenu
self.nb = nb
self.tb = tb
</t>
<t tx="ekr.20051104081502.356">if OUTLOOK:
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # Create a TCP socket
    s.bind(('localhost',8888)) # Bind to port 8888
    s.listen(5) # Listen, but allow no more than
    self.sock = s
</t>
<t tx="ekr.20051104081502.358">try:
    pathlist = [f[1] for f in cp.items('Files')]
except:
    pathlist = []

if pathlist:
    pathlist.sort()
    pathlist.reverse()
    for path in pathlist[1:]:
        self.OnFileList(path=path)

    #don't want to trigger the page change event until n-1 of n files are loaded
    EVT_NOTEBOOK_PAGE_CHANGED(self,nb.GetId(),self.OnPageChange)

    self.OnFileList(path=pathlist[0])
else:
    EVT_NOTEBOOK_PAGE_CHANGED(self,nb.GetId(),self.OnPageChange)



</t>
<t tx="ekr.20051104081502.36">import compiler

for child in p.children_iter():
    h = child.h
    body = child.b

    try:
        val = compiler.parse(body)
        g.pr(type(val))
        g.pr(val)
    except SyntaxError:
        g.es("Syntax error: %s" % h,color="blue")
</t>
<t tx="ekr.20051104081502.360">ID_TIMER = wxNewId()
self.timer = wxTimer(self, ID_TIMER) 
EVT_TIMER(self,  ID_TIMER, self.OnIdle)
self.timer.Start(3000)
</t>
<t tx="ekr.20051104081502.362"></t>
<t tx="ekr.20051104081502.364">def createownerlist(self):

    if REMOTE_HOST and OFFLINE_ONLY is False:
        cursor = self.GetCursor(REMOTE_HOST)
        sql = "SHOW TABLES" #sorted
    else:
        cursor = self.GetCursor(LOCAL_HOST)
        sql = "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name"

    cursor.execute(sql)
    results = cursor.fetchall()

    #excluding 'system' tables and archive tables
    excluded_tables = ['user_sync','sync','owners']
    tables = [t for (t,) in results if t.find('_archive')== -1 and t not in excluded_tables]

    sql_list = []
    for table in tables:
        sql_list.append("""SELECT owner1 FROM %s UNION SELECT owner2 FROM %s UNION SELECT owner3 FROM %s"""%((table,)*3))

    sql = " UNION ".join(sql_list)
    cursor.execute(sql)
    results = cursor.fetchall()

    _list = [x[0] for x in results]
    if '' in _list:
        _list.remove('')
    if None in _list:
        _list.remove(None)

    self._list = _list

    #posting custom event to signal that this thread is done
    evt = wxPyEvent()
    evt_id = wxNewEventType()
    evt.SetEventType(evt_id)
    self.Connect(-1, -1, evt_id, self.createownerdialog)
    wxPostEvent(self, evt)

</t>
<t tx="ekr.20051104081502.366">def createownerdialog(self, evt=None):
    self.ModifierDialog = ModifierDialog(parent=self, title="Select owner(s)", size=(180,300), style=wxCAPTION, modifierlist = self._list)
    del self._list

</t>
<t tx="ekr.20051104081502.368"></t>
<t tx="ekr.20051104081502.37">import doctest
g.pr(doctest)
</t>
<t tx="ekr.20051104081502.370">def CreateNewNotebookPage(self, host, table):

    Properties = {'owner':'*ALL',
                'LCdate':'duedate',
                'sort':{'attribute':'priority','direction':0}, #these could be set in Config
                'showfinished':0} #-1 show them all; 0 show none; integer show for that many days

    Properties['table'] = table
    Properties['host'] = host

    self.PropertyDicts.append(Properties)

    self.L = len(self.ItemLists)#could use self.ListCtrls, self.OwnerLBoxes, etc. with a -1

    results = self.ReadFromDB()
    if results is None:
        self.PropertyDicts = self.PropertyDicts[:-1]
        self.L = self.L - 1
        return

    panel = wxPanel(self.nb, -1, size = (900,400))
    LCtrl = ListCtrl(panel, -1, style=wxLC_REPORT|wxSUNKEN_BORDER|wxLC_VRULES|wxLC_HRULES)
    LCtrl.SetFont(self.LC_font)
    self.ListCtrls.append(LCtrl)

    OLBox = wxListBox(panel, -1, size = (126,550), choices = [""], style=wxLB_SORT|wxSUNKEN_BORDER)
    self.OwnerLBoxes.append(OLBox)

    sizer = wxBoxSizer(wxHORIZONTAL)
    sizer.Add(OLBox,0,wxALIGN_LEFT|wxEXPAND)
    sizer.Add(LCtrl,1,wxALIGN_LEFT|wxEXPAND)
    panel.SetSizer(sizer)

    self.ItemLists.append(self.CreateAndDisplayList(results)) 

    &lt;&lt; Fill OwnerListBox &gt;&gt;
    &lt;&lt; ListControl Events &gt;&gt;

    #img_num = LCtrl.arrows[Properties['sort']['direction']]
    #LCtrl.SetColumnImage(self.attr2col_num[Properties['sort']['attribute']], img_num)

    rdbms = host.split(':')[1]
    if rdbms == 'mysql':
        tab_title = '%s (remote)'%table
    else:
        tab_title = table

    if table in SYNC_TABLES:
        tab_title = '*'+tab_title

    self.nb.AddPage(panel,tab_title)
    self.nb.SetSelection(self.L)

    self.filehistory.AddFileToHistory('%s:%s'%(host,table))

    self.SetStatusText("Successfully loaded %s"%tab_title)

</t>
<t tx="ekr.20051104081502.372">cursor = self.GetCursor(host)
if cursor is None:
    g.pr("Couldn't get cursor to fill OwnerListBox")
    return

cursor.execute("SELECT owner1 FROM %s UNION SELECT owner2 FROM %s UNION SELECT owner3 FROM %s"%((table,)*3))

owners = [x for (x,) in cursor.fetchall()]

if None in owners:
    owners.remove(None)
if '' in owners:
    owners.remove('')

OLBox.Clear()
for name in owners: 
    OLBox.Append(name)
OLBox.Append('*ALL')
OLBox.SetSelection(0)

</t>
<t tx="ekr.20051104081502.374">LCId = LCtrl.GetId()
EVT_LIST_ITEM_SELECTED(self, LCId, self.OnItemSelected)
EVT_LIST_ITEM_ACTIVATED(self, LCId, self.OnDisplayInPlaceEditor)
EVT_LEFT_DOWN(LCtrl, self.OnLeftDown) 
EVT_LEFT_DCLICK(LCtrl, self.OnLeftDown)
EVT_RIGHT_DOWN(LCtrl, self.OnRightDown)
EVT_LIST_COL_CLICK(self, LCId, self.OnColumnClick)
EVT_LIST_COL_RIGHT_CLICK(self, LCId, self.OnColumnRightClick)

# the following is a ListBox event
EVT_LISTBOX(self, OLBox.GetId(), self.OnFilterOwners)

</t>
<t tx="ekr.20051104081502.376">def OnPageChange(self, evt=None):
    if self.modified:
        self.OnUpdate()

    self.L = L = self.nb.GetSelection()

    &lt;&lt; Find Highlighted Row &gt;&gt;
    &lt;&lt; Update Title &gt;&gt;

    evt.Skip() #051403

</t>
<t tx="ekr.20051104081502.378">idx = self.ListCtrls[L].GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)
if idx != -1:
    self.curIdx = idx
    #LCtrl.EnsureVisible(idx)
    self.OnItemSelected()
elif self.ItemLists[L]:
    self.curIdx = 0
    self.ListCtrls[L].SetItemState(0, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED)
    #the line above triggers an OnItemSelected EVT so don't need self.OnItemSelected() 092803
else:
    self.curIdx = -1

</t>
<t tx="ekr.20051104081502.380">location,rdbms = self.PropertyDicts[L]['host'].split(':')
table = self.PropertyDicts[L]['table']
self.SetTitle("List Manager:  %s:  %s:  %s"%(location,rdbms,table))

</t>
<t tx="ekr.20051104081502.382"></t>
<t tx="ekr.20051104081502.383">def OnShowTickler(self, evt=None):
    if self.popupvisible:
        return

    self.popupvisible = True

    host = 'wxLMDB:sqlite'
    cursor = self.Cursors[host]
    table = 'follow_ups'

    sql = "SELECT COUNT() FROM "+table+" WHERE finisheddate IS NULL AND priority &gt; 1"
    cursor.execute(sql)
    results = cursor.fetchone()

    num_items = int(results[0])

    if not num_items:
        return

    if self.modified: #Should decide if this should be put back or not
        self.OnUpdate()

    n = random.randint(0,num_items-1)

    sql = "SELECT priority,name,createdate,finisheddate,duedate,owner1,owner2,owner3,id,timestamp,note FROM "+table+" WHERE finisheddate IS NULL AND priority &gt; 1 LIMIT 1 OFFSET %d"%n

    try:
        cursor.execute(sql)
    except:
        g.pr("In OnShowTickler and attempt to Select an item failed")
        return

    row = cursor.fetchone()

    class Item: pass
    item = Item()

    item.priority = int(row[0]) #int(row[0]) needs int because it seems to come back as a long from MySQL
    item.name = row[1]
    item.createdate = row[2]
    item.finisheddate = row[3]
    item.duedate = row[4]
    item.owners = [z for z in row[5:7] if z is not None] #if you carry around ['tom',None,None] you have an issue when you go write it
    item.id = row[8]
    item.timestamp = row[9]
    item.note = row[10]

    dlg = TicklerDialog(self, "", "Do something about this!!!", size=(550,350))
    TC = dlg.TC

    f = wxFont(14, wxSWISS, wxITALIC, wxBOLD, False)
    TC.SetDefaultStyle(wxTextAttr("BLUE",wxNullColour, f))
    TC.AppendText("%s..."%item.name)

    if item.priority == 3:
        TC.SetDefaultStyle(wxTextAttr("RED","YELLOW",f))
    TC.AppendText("%d\n\n"%item.priority)

    f = wxFont(8, wxSWISS, wxNORMAL, wxNORMAL)
    TC.SetDefaultStyle(wxTextAttr("BLACK","WHITE", f))
    TC.AppendText("owners: %s\n"%", ".join(item.owners))
    TC.AppendText("created on: %s\n"%item.createdate.Format('%m/%d/%y'))
    if item.duedate:
        ddate = item.duedate.Format('%m/%d/%y')
    else:
        ddate = "&lt;no due date&gt;"
    TC.AppendText("due on: %s\n\n"%ddate)

    note = item.note
    if not note:
        note = "&lt;no note&gt;"
    TC.AppendText("%s\n\n"%note)
    f = wxFont(10, wxSWISS, wxITALIC, wxBOLD)
    TC.SetDefaultStyle(wxTextAttr("BLACK",wxNullColour, f))
    TC.AppendText('follow_ups')
    TC.ShowPosition(0)   #did not do anything
    TC.SetInsertionPoint(0)
    result = dlg.ShowModal()
    dlg.Destroy()
    self.popupvisible = False     

    if result in (wxID_OK, wxID_APPLY):

        for L,Properties in enumerate(self.PropertyDicts):
            if Properties['table'] == table:
                break
        else:
            g.pr("Can't find %s"%table)
            return

        self.nb.SetSelection(L) #if the page changes it sends a EVT_NOTEBOOK_PAGE_CHANGED, which calls OnPageChange
        self.L = L
        self.FindNode(item)
        if result==wxID_APPLY:
            self.OnMailItem(item)

    elif result==wxID_FORWARD:
        self.OnShowTickler()

</t>
<t tx="ekr.20051104081502.384">def OnActivateTickler(self, evt):
    self.tickler_active = not self.tickler_active
    self.toolmenu.Enable(idSHOWNEXT,self.tickler_active)


</t>
<t tx="ekr.20051104081502.385"></t>
<t tx="ekr.20051104081502.386">def OnMailItem(self, evt=None, item=None):
    if item is None:
        if self.curIdx == -1:
            return
        else:
            item = self.ItemLists[self.L][self.curIdx]

    dlg = MailDialog(self,"Mail a reminder", size=(450,500),
               recipients=item.owners,    
               subject=item.name,
               body=self.GetNote())          
    result = dlg.ShowModal()
    if result==wxID_OK:
        outlook= Dispatch("Outlook.Application")
        newMsg = outlook.CreateItem(olMailItem) #outlook.CreateItem(constants.olMailItem)
        newMsg.To = to = dlg.RTC.GetValue()
        newMsg.Subject = subject = dlg.STC.GetValue()
        newMsg.Body = body = dlg.BTC.GetValue()

        #newMsg.FlagStatus = constants.olFlagMarked

        newMsg.Display()

        dlg.Destroy()            
        #del outlook

        self.note.SetSelection(0,0)
        self.note.WriteText("**************************************************\n")
        self.note.WriteText("Email sent on %s\n"%mx.DateTime.today().Format("%m/%d/%y"))
        self.note.WriteText("To: %s\n"%to)
        self.note.WriteText("Subject: %s\n"%subject)
        self.note.WriteText("%s\n"%body)
        self.note.WriteText("**************************************************\n")

</t>
<t tx="ekr.20051104081502.387">def OnMailView(self, evt=None):
    recipients = [self.PropertyDicts[self.L]['owner']]

    body = ""
    for i,item in enumerate(self.ItemLists[self.L]):
        body = body+"%d. %s (%d)\n"%(i+1, item.name, item.priority)

    subject = "Follow-ups " + mx.DateTime.today().Format("%m/%d/%y")

    dlg = MailDialog(self,"Follow-up List", size=(450,500),
               recipients=recipients,
               subject=subject,
               body=body)

    val = dlg.ShowModal()
    dlg.Destroy()
    if val==wxID_OK:
        outlook= Dispatch("Outlook.Application")
        newMsg = outlook.CreateItem(olMailItem) #outlook.CreateItem(constants.olMailItem)
        newMsg.To = dlg.RTC.GetValue()
        newMsg.Subject = dlg.STC.GetValue()
        newMsg.Body = dlg.BTC.GetValue()

        newMsg.FlagStatus = olFlagMarked #constants.olFlagMarked
        newMsg.Categories = "Follow-up"

        newMsg.Display()

        #del outlook

</t>
<t tx="ekr.20051104081502.388"></t>
<t tx="ekr.20051104081502.389">def OnCopyItems(self, event=None, cut=False):
    if self.curIdx == -1:
        return

    L = self.L
    IList = self.ItemLists[L]
    LCtrl = self.ListCtrls[L]

    &lt;&lt; Find Highlighted Items &gt;&gt;

    self.SetStatusText("%d items copied"%len(copyitems))
    if cut:
        self.OnDeleteItems()

</t>
<t tx="ekr.20051104081502.390">copyitems = []
i = -1
while 1:
    i = LCtrl.GetNextItem(i, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)
    if i==-1:
        break
    item = IList[i]
    item.notes = self.GetNote(L,item) #handles the database situation
    copyitems.append(item)

self.copyitems = copyitems
</t>
<t tx="ekr.20051104081502.391">def OnPasteItems(self, evt=None, L=None): #noselect 051603
    #used by OnMoveToList, OnMoveToSpecificList and called directly
    if not self.copyitems:
        g.pr("Nothing was selected to be copied")
        return

    if L is None: #this is not needed by OnMoveTo or OnDragToTab but is for a straight call
        L = self.L

    Properties = self.PropertyDicts[L]
    LCtrl = self.ListCtrls[L]
    IList = self.ItemLists[L]

    items = self.copyitems
    numitems = len(items)

    for item in items:

        z = item.owners+[None,None,None]

        id = self.GetUID() #we do give it a new id
        host = Properties['host']
        cursor = self.Cursors[host]
        table = Properties['table']

        createdate = mx.DateTime.now() #need this or else it won't be seen as a new item when synching; would be seen as updated
        command = "INSERT INTO "+table+" (priority,name,createdate,finisheddate,duedate,note,owner1,owner2,owner3,id) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
        cursor.execute(command,(item.priority,item.name,createdate,item.finisheddate,item.duedate,item.notes,z[0],z[1],z[2],id))

        timestamp = self.TimeStamper(host, cursor, table, id)

        #creating a new item breaks the connection between item.x and new_item.x
        class Item: pass
        new_item = Item()
        new_item.id = id
        new_item.priority = item.priority
        new_item.owners = item.owners
        new_item.name = item.name
        new_item.timestamp = timestamp
        new_item.duedate =item.duedate
        new_item.finisheddate = item.finisheddate
        new_item.createdate = createdate
        IList.insert(0,new_item)

    self.DisplayList(IList,L)

    #If we didn't come from OnMoveToList or OnMoveToSpecificList where L != self.L
    if L==self.L:
        for i in range(numitems):
            LCtrl.SetItemState(i, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED)
        self.curIdx = numitems-1



</t>
<t tx="ekr.20051104081502.392">def OnDeleteItems(self, event=None):
    """Called directly and by OnCopyItems (cut = true)
    """
    if self.curIdx == -1: #not absolutely necessary but gets you out quickly
        return

    L = self.L
    LCtrl = self.ListCtrls[L]
    IList = self.ItemLists[L]
    Properties = self.PropertyDicts[L]

    i = -1
    while 1:
        i = LCtrl.GetNextItem(i, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)
        if i==-1:
            break
        item = IList.pop(i)
        LCtrl.DeleteItem(i)

        host = Properties['host']
        cursor = self.Cursors[host]
        table = Properties['table']

        cursor.execute("DELETE from "+table+" WHERE id = %s", (item.id,))

        #Track Deletes for Syncing ############################################
        if table in SYNC_TABLES:
            if host.split(':')[1] == 'sqlite':
                timestamp = mx.DateTime.now()
                cursor.execute("INSERT INTO sync (id,action,table_name,name,timestamp) VALUES (%s,%s,%s,%s,%s)",(item.id,'d',table,item.name,timestamp))
            else:
                cursor.execute("INSERT INTO sync (id,action,table_name,user,name) VALUES (%s,%s,%s,%s,%s)",(item.id,'d',table,USER,item.name))
        #########################################################################
        i-=1

    self.name.Clear()
    self.owners.Clear()
    self.note.Clear()
    #note that Clearing does cause self.modified --&gt;{'name':1}
    self.modified = {}
    self.curIdx = -1

</t>
<t tx="ekr.20051104081502.393"></t>
<t tx="ekr.20051104081502.394">def OnLeftDown(self, evt):
    g.pr("Here")
    if self.modified:
        #if inplace editor is open and you click anywhere (same or different row from current row) but in the editor itself then just to close editor
        flag = self.modified.has_key('inplace')
        self.OnUpdate()
        if flag:
            evt.Skip() #without Skip, EVT_LIST_ITEM_SELECTED is not generated if you click in a new row
            return

    x,y = evt.GetPosition()
    LCtrl = self.ListCtrls[self.L]

    #Using HitTest to obtain row clicked on because there was a noticable delay in the generation of an
    #EVT_LIST_ITEM_SELECTED event when you click on the already selected row
    idx,flags = LCtrl.HitTest((x,y))

    #if you are below rows of items then idx = -1 which could match self.curIdx = -1
    if idx == -1:
        return

    # only if you click on the currently selected row do the following events occur
    if idx == self.curIdx:
        if x &lt; 18:
            self.OnToggleFinished()
        elif x &lt; 33:
            self.OnPriority()
        elif x &lt; 33 + LCtrl.GetColumnWidth(1):
            self.OnDisplayInPlaceEditor()
        elif x &lt; 33 + LCtrl.GetColumnWidth(1) + LCtrl.GetColumnWidth(2): 
            self.OnEditOwner()
        else:
            self.OnDueDate
    else:
        evt.Skip() #without Skip, EVT_LIST_ITEM_SELECTED is not generated if you click in a new row



</t>
<t tx="ekr.20051104081502.395">def OnRightDown(self, evt):
    x,y = evt.GetPosition()

    sendtomenu = wxMenu()

    open_tables = []
    for page,Properties in enumerate(self.PropertyDicts):
        host,table = Properties['host'],Properties['table']
        open_tables.append((host,table))
        sendtomenu.Append(1+page,"%s (%s)"%(table,host))
        EVT_MENU(self, 1+page, lambda e,p=page: self.OnMoveToList(e,p))

    sendtomenu.Delete(self.L+1) # don't send it to the page you're already on
    sendtomenu.AppendSeparator()

    self.closed_tables = []
    for host,cursor in self.Cursors.items():

        location, rdbms = host.split(':')

        if rdbms == 'sqlite':
            cursor.execute("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name")
        elif rdbms == 'mysql':
            cursor.execute("SHOW tables")

        results = cursor.fetchall()

        page+=1
        for (table,) in results:
            if not ((host,table) in open_tables or table in ['user_sync','owners','sync']):
                self.closed_tables.append((host,table))
                sendtomenu.Append(1+page,"%s (%s)"%('*'+table,host))
                EVT_MENU(self, 1+page, lambda e,p=page: self.OnMoveToList(e,p))
                page+=1

    self.PopupMenu(sendtomenu,(x+125,y+40))
    sendtomenu.Destroy()

</t>
<t tx="ekr.20051104081502.396"></t>
<t tx="ekr.20051104081502.397">def OnCombineItems(self, evt):
    L = self.L
    idx = self.curIdx
    IList = self.ItemLists[L]
    LCtrl = self.ListCtrls[L]

    combine_list = []
    i = -1
    while 1:
        i = LCtrl.GetNextItem(i, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)
        if i==-1:
            break
        combine_list.append((IList[i].createdate,IList[i]))


    if len(combine_list) &lt; 2:
        g.pr("Fewer than two items highlighted")
        return

    combine_list.sort()
    combine_list.reverse()

    dlg = wxMessageDialog(self,
                        "Combine the %d selected items?"%len(combine_list),
                        "Combine Items?",
                        wxICON_QUESTION|wxYES_NO)

    if dlg.ShowModal() == wxID_YES:
        Properties = self.PropertyDicts[L]
        host = Properties['host']
        cursor = self.Cursors[host]
        table = Properties['table']

        t_item = combine_list[0][1]
        merge_list = combine_list[1:]
        new_note = ""

        for date,item in merge_list:
            note = self.GetNote(item=item)
            date = date.Format("%m/%d/%y")
            new_note = "%s\n%s %s\n\n%s"%(new_note, date, item.name, note)

            cursor.execute("DELETE from "+table+" WHERE id = %s", (item.id,))
            #Track Deletes for Syncing ############################################
            if table in SYNC_TABLES:
                if host.split(':')[1] == 'sqlite':
                    timestamp = mx.DateTime.now()
                    cursor.execute("INSERT INTO sync (id,action,table_name,name,timestamp) VALUES (%s,%s,%s,%s,%s)",(item.id,'d',table,item.name,timestamp))
                else:
                    cursor.execute("INSERT INTO sync (id,action,table_name,user,name) VALUES (%s,%s,%s,%s,%s)",(item.id,'d',table,USER,item.name))
            #########################################################################

        t_note = self.GetNote(item=t_item)
        t_note = "%s\n%s"%(t_note,new_note)

        #What about combining owners?######################################

        cursor.execute("UPDATE "+table+" SET name = %s, note = %s WHERE id = %s", (t_item.name+"*",t_note,t_item.id))
        t_item.timestamp = self.TimeStamper(host, cursor, table, t_item.id)

        self.OnRefresh()
        LCtrl.SetItemState(0, 0, wxLIST_STATE_SELECTED)
        IList = self.ItemLists[L]
        id = t_item.id
        idx = -1
        for item in IList:
            idx+=1
            if id == item.id:
                break
        else:
            idx = -1 

        #should never be -1
        if idx != -1:	
            LCtrl.SetItemState(idx, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED)
            LCtrl.EnsureVisible(idx)
        self.curIdx = idx

    dlg.Destroy()

</t>
<t tx="ekr.20051104081502.398">def OnMoveToList(self, evt=None, page=0):
    self.OnCopyItems(cut=True)
    pc = self.nb.GetPageCount()
    if page &lt; pc:		
        self.OnPasteItems(L=page)
    else:
        host,table = self.closed_tables[page-pc]
        cursor = self.Cursors[host]# in ini self.Cursors[host]

        for item in self.copyitems:
            z = item.owners+[None,None,None]
            id = self.GetUID() #give it a new id

            #need this or else it won't be seen as a new item when syncing; would be seen as updated
            createdate = mx.DateTime.now() 
            command = "INSERT INTO "+table+" (priority,name,createdate,finisheddate,duedate,note,owner1,owner2,owner3,id) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
            cursor.execute(command,(item.priority,item.name,createdate,item.finisheddate,item.duedate,item.notes,z[0],z[1],z[2],id))
            timestamp = self.TimeStamper(host, cursor, table, id)

    self.copyitems = []

</t>
<t tx="ekr.20051104081502.399">def OnMoveToSpecificList(self, evt=None, table='follow_ups'):
    matches = {}
    for page,Properties in enumerate(self.PropertyDicts):
        host,tble = Properties['host'],Properties['table']
        if tble == table:
            rdbms = host.split(':')[1]
            matches[rdbms] = page

    self.OnCopyItems(cut=True)

    if matches:
        if matches.get('mysql'):	
            self.OnPasteItems(L=matches['mysql'])
        else:
            self.OnPasteItems(L=matches['sqlite'])
    else:
        cursor = self.Cursors[LOCAL_HOST]

        for item in self.copyitems:
            z = item.owners+[None,None,None]
            id = self.GetUID() #give it a new id

            #need this or else it won't be seen as a new item when syncing; would be seen as updated
            createdate = mx.DateTime.now() 
            command = "INSERT INTO "+table+" (priority,name,createdate,finisheddate,duedate,note,owner1,owner2,owner3,id) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
            cursor.execute(command,(item.priority,item.name,createdate,item.finisheddate,item.duedate,item.notes,z[0],z[1],z[2],id))
            timestamp = self.TimeStamper(host, cursor, table, id)

    self.copyitems = []



</t>
<t tx="ekr.20051104081502.400"></t>
<t tx="ekr.20051104081502.401">def OnToggleFinished(self, evt=None):
    L = self.L
    LCtrl = self.ListCtrls[L]
    Properties = self.PropertyDicts[L]
    idx = self.curIdx

    item = self.ItemLists[L][idx]
    LC_Item = LCtrl.GetItem(idx)

    if not item.finisheddate:
        item.finisheddate = mx.DateTime.today()
        LC_Item.SetImage(LCtrl.idx0)
    else:
        item.finisheddate = None
        LC_Item.SetImage(LCtrl.idx1)

    &lt;&lt; draw item &gt;&gt;

    self.tb.EnableTool(30, True)

    host = Properties['host']	
    cursor = self.Cursors[host]
    table = Properties['table']

    cursor.execute("UPDATE "+table+" SET finisheddate = %s WHERE id = %s", (item.finisheddate, item.id))
    item.timestamp = self.TimeStamper(host, cursor, table, item.id)

    if Properties['LCdate'] == 'timestamp':
        LCtrl.SetStringItem(idx, self.attr2col_num['date'], item.timestamp.Format("%m/%d %H:%M:%S"))
    elif Properties['LCdate'] == 'finisheddate':
        LCtrl.SetStringItem(idx, self.attr2col_num['date'], item.finisheddate.Format('%m/%d/%y'))



</t>
<t tx="ekr.20051104081502.402">if item.finisheddate:
    #It appears that SetTextColour resets font weight to Normal but this makes no sense
    #This means that all finished items have Normal weight whether they are priority 3,2 or 1
    #May actually be that GetItem() and then SetItem() sets the weight to Normal no matter what it was originally
    LC_Item.SetTextColour(wxLIGHT_GREY)

elif item.priority==1:
    #see note above about SetTextColour apparently resetting weight
    LC_Item.SetTextColour(wxBLACK)

elif item.priority==2:
    #LC_Item.SetTextColour(wxBLACK) -- this line should be necessary but it does not appear to be
    # ? font is black so ? if have to reset it
    f = self.LC_font
    f.SetWeight(wxBOLD)
    LC_Item.SetFont(f)
    f.SetWeight(wxNORMAL) # resetting font weight

else:
    LC_Item.SetTextColour(wxRED) #appears to be the only way to set color - can't through font
    f = self.LC_font #LCtrl.font
    f.SetWeight(wxBOLD)
    LC_Item.SetFont(f)
    f.SetWeight(wxNORMAL) # resetting font weight

LCtrl.SetItem(LC_Item)
</t>
<t tx="ekr.20051104081502.403">def OnPriority(self, event=None, input=None):
    L = self.L
    idx = self.curIdx
    LCtrl = self.ListCtrls[L]
    Properties = self.PropertyDicts[L]
    item = self.ItemLists[L][idx]

    if input:
        item.priority=input

    else:
        if item.priority &lt; 3:
            item.priority+= 1
        else:
            item.priority=1

    LC_Item = LCtrl.GetItem(idx)

    &lt;&lt; draw item &gt;&gt;

    text = str(item.priority)        
    LCtrl.SetStringItem(idx, 0, text)

    host = Properties['host']
    cursor = self.Cursors[host]
    table = Properties['table']

    cursor.execute("UPDATE "+table+" SET priority = %s WHERE id = %s", (item.priority,item.id))
    item.timestamp = self.TimeStamper(host, cursor, table, item.id)

    if Properties['LCdate'] == 'timestamp':
        LCtrl.SetStringItem(idx, self.attr2col_num['date'], item.timestamp.Format('%m/%d %H:%M:%S'))

    wxCallAfter(LCtrl.SetFocus)

</t>
<t tx="ekr.20051104081502.404">if item.finisheddate:
    #It appears that SetTextColour resets font weight to Normal but this makes no sense
    #This means that all finished items have Normal weight whether they are priority 3,2 or 1
    #May actually be that GetItem() and then SetItem() sets the weight to Normal no matter what it was originally
    LC_Item.SetTextColour(wxLIGHT_GREY)

elif item.priority==1:
    #see note above about SetTextColour apparently resetting weight
    LC_Item.SetTextColour(wxBLACK)

elif item.priority==2:
    #LC_Item.SetTextColour(wxBLACK) -- this line should be necessary but it does not appear to be
    # ? font is black so ? if have to reset it
    f = self.LC_font
    f.SetWeight(wxBOLD)
    LC_Item.SetFont(f)
    f.SetWeight(wxNORMAL) # resetting font weight

else:
    LC_Item.SetTextColour(wxRED) #appears to be the only way to set color - can't through font
    f = self.LC_font #LCtrl.font
    f.SetWeight(wxBOLD)
    LC_Item.SetFont(f)
    f.SetWeight(wxNORMAL) # resetting font weight

LCtrl.SetItem(LC_Item)
</t>
<t tx="ekr.20051104081502.405"></t>
<t tx="ekr.20051104081502.406">def OnDisplayInPlaceEditor(self,evt=None):
    L = self.L
    LCtrl = self.ListCtrls[L]
    Properties = self.PropertyDicts[L]
    idx = self.curIdx
    item = self.ItemLists[L][idx]

    host = Properties['host']
    cursor = self.Cursors[host]
    table = Properties['table']

    #if self.Conflict(host, cursor, table, item): return #works -- may be overkill so i've commented it out

    TCid = wxNewId()
    y = LCtrl.GetItemPosition(idx)[1] 
    length = LCtrl.GetColumnWidth(1)

    editor = wxTextCtrl(self, TCid, pos = (167,y+28), size = (length,23), style=wxTE_PROCESS_ENTER)
    editor.SetFont(wxFont(9, wxSWISS, wxNORMAL, wxNORMAL))
    editor.SetBackgroundColour(wxColour(red=255,green=255,blue=175)) #Yellow
    editor.AppendText(item.name)
    editor.Show(True)
    editor.Raise()
    editor.SetSelection(-1,-1)
    editor.SetFocus()	

    EVT_TEXT_ENTER(self, TCid, self.OnCloseInPlaceEditor)		

    self.in_place_editor = editor
    self.modified['inplace'] = 1	





</t>
<t tx="ekr.20051104081502.407">def OnCloseInPlaceEditor(self,evt=None):
    L = self.L
    LCtrl = self.ListCtrls[L]
    Properties = self.PropertyDicts[L]
    idx = self.curIdx
    item = self.ItemLists[L][idx]

    host = Properties['host']
    cursor = self.Cursors[host]
    table = Properties['table']
    LCdate = Properties['LCdate']

    #if self.Conflict(host, cursor, table, item)...

    text = self.in_place_editor.GetValue().strip()[:150]
    item.name = text
    LCtrl.SetStringItem(idx, self.attr2col_num['name'], text)
    self.in_place_editor.Destroy()

    cursor.execute("UPDATE "+table+" SET name = %s WHERE id = %s", (text, item.id))
    item.timestamp = self.TimeStamper(host, cursor, table, item.id)

    if Properties['LCdate'] == 'timestamp':
        LCtrl.SetStringItem(idx, self.attr2col_num['date'], item.timestamp.Format('%m/%d %H:%M:%S'))

    self.name.Clear()
    self.name.AppendText(text) #this will cause self.modified['name'] = 1, which is dealt with below

    #using default in case for some reason self.modified does not have the keys
    self.modified.pop('inplace', None)
    self.modified.pop('name', None)

    wxCallAfter(LCtrl.SetFocus) #sets focus on LCtrl and current selection to be highlighted



</t>
<t tx="ekr.20051104081502.408">def OnDueDate(self, evt=None):
    idx = self.curIdx
    if idx == -1:
        return
    L = self.L
    Properties = self.PropertyDicts[L]
    item = self.ItemLists[L][idx]
    LCtrl = self.ListCtrls[L]

    if item.duedate:
        date = wxDateTime()
        date.SetTimeT(item.duedate) #I am surprised it takes a mx.DateTime object; supposed to need ticks
    else:
        date = 0
    dlg = CalendarDialog(parent=self,
                 title="Select a date",
                 size=(400,400),
                 style=wxCAPTION,
                 date = date)
    if dlg.ShowModal()==wxID_OK:
        date = dlg.cal.GetDate() # this is some date object
        #date = date.GetTicks()
        item.duedate = mx.DateTime.DateFromTicks(date.GetTicks())

        host = Properties['host']
        cursor = self.Cursors[host]
        table = Properties['table']

        cursor.execute("UPDATE "+table+" SET duedate = %s WHERE id = %s", (item.duedate,item.id))
        item.timestamp = self.TimeStamper(host, cursor, table, item.id)
        if Properties['LCdate'] == 'timestamp':
            LCtrl.SetStringItem(idx, self.attr2col_num['date'], item.timestamp.Format("%m/%d %H:%M:%S"))
        elif Properties['LCdate'] == 'duedate':
            LCtrl.SetStringItem(idx, self.attr2col_num['date'], item.duedate.Format('%m/%d/%y'))
    dlg.cal.Destroy()
    dlg.Destroy()

</t>
<t tx="ekr.20051104081502.409">def OnEditOwner(self, evt=None): #, new=False) removed Aug. 31 for simplicity
    idx = self.curIdx
    if idx == -1:
        return
    L = self.L
    Properties = self.PropertyDicts[L]
    LCtrl = self.ListCtrls[L]
    item = self.ItemLists[L][idx]
    if not self.ModifierDialog:
        g.pr("self.ModifierDialog is still being constructed")
        return
    #need to clear the current selections or you'll just be making more and more selections
    self.ModifierDialog.SelectCurrent(item.owners)
    self.ModifierDialog.tc.Clear()
    self.ModifierDialog.CenterOnParent()

    val = self.ModifierDialog.ShowModal()

    if val == wxID_OK:
        item.owners, new_names = self.ModifierDialog.GetUserInput()

        &lt;&lt; Common Owner Code &gt;&gt;

        for owner in item.owners:
            if self.OwnerLBoxes[L].FindString(owner) == -1:
                self.OwnerLBoxes[L].Append(owner)

        for owner in new_names:
            self.ModifierDialog.lb.Append(owner)

        host = Properties['host']
        cursor = self.Cursors[host]
        table = Properties['table']

        cursor.execute("UPDATE "+table+" SET owner1 = %s, owner2 = %s, owner3 = %s WHERE id = %s", (z[0],z[1],z[2],item.id))
        item.timestamp = self.TimeStamper(host, cursor, table, item.id)
        if Properties['LCdate'] == 'timestamp':
            LCtrl.SetStringItem(idx, self.attr2col_num['date'], item.timestamp.Format("%m/%d %H:%M:%S"))

        if 'owners' in self.modified:
            del self.modified['owners']

    wxCallAfter(LCtrl.SetFocus)

</t>
<t tx="ekr.20051104081502.410">owner_str = '; '.join(item.owners)
LCtrl.SetStringItem(idx, self.attr2col_num['owners'], owner_str)
self.owners.Clear()
self.owners.AppendText(owner_str)

z = item.owners+[None,None,None] #note that + creates a new list
</t>
<t tx="ekr.20051104081502.411">def OnUpdate(self, evt=None):
    if 'inplace' in self.modified:
        self.OnCloseInPlaceEditor()
        if not self.modified:
            return

    L = self.L
    LCtrl = self.ListCtrls[L]
    IList = self.ItemLists[L]
    Properties = self.PropertyDicts[L]
    OLBox = self.OwnerLBoxes[L]
    idx = self.curIdx

    # there is some chance that it is never true that idx == -1 and then this could be eliminated
    if idx != -1:
        item = IList[idx]
    else:
        msg = wxMessageDialog(self, "There is no selected item to update", "", wxICON_ERROR|wxOK)
        msg.ShowModal()
        msg.Destroy()
        self.modified = {}
        return

    host = Properties['host']
    cursor = self.Cursors[host]
    table = Properties['table']

    if 'name' in self.modified:
        item.name = self.name.GetValue().strip()[:150]
        LCtrl.SetStringItem(idx, self.attr2col_num['name'], item.name)
        cursor.execute("UPDATE "+table+" SET name =%s WHERE id = %s",(item.name,item.id))

    if 'note' in self.modified:
        note = self.note.GetValue() #a blank note starts out as None but after this it becomes '' -- ??
        cursor.execute("UPDATE "+table+" SET note =%s WHERE id = %s",(note,item.id))

    if 'owners' in self.modified:
        owner_str = self.owners.GetValue().strip()
        item.owners = []
        if owner_str:
            owner_list = [x.strip() for x in owner_str.split(';')]
            for owner in owner_list:
                owner = ", ".join([x.strip().title() for x in owner.split(',')])
                item.owners.append(owner)

        &lt;&lt; Common Owner Code &gt;&gt;

        cursor.execute("UPDATE "+table+" SET owner1 = %s, owner2 = %s, owner3 = %s WHERE id = %s", (z[0],z[1],z[2],item.id))

        for owner in item.owners:
            if self.ModifierDialog.lb.FindString(owner) == -1:
                self.ModifierDialog.lb.Append(owner)
                OLBox.Append(owner)
            elif OLBox.FindString(owner) == -1:
                OLBox.Append(owner)		

    item.timestamp = self.TimeStamper(host, cursor, table, item.id)
    if Properties['LCdate'] == 'timestamp':
        LCtrl.SetStringItem(idx, 3, item.timestamp.Format("%m/%d %H:%M:%S"))

    self.modified = {}


</t>
<t tx="ekr.20051104081502.412">owner_str = '; '.join(item.owners)
LCtrl.SetStringItem(idx, self.attr2col_num['owners'], owner_str)
self.owners.Clear()
self.owners.AppendText(owner_str)

z = item.owners+[None,None,None] #note that + creates a new list
</t>
<t tx="ekr.20051104081502.413">def OnNewItem(self, evt=None):
    L=self.L
    LCtrl = self.ListCtrls[L]
    Properties = self.PropertyDicts[L]

    if self.curIdx != -1:
        LCtrl.SetItemState(self.curIdx, 0, wxLIST_STATE_SELECTED)

    &lt;&lt; Clear data fields &gt;&gt;

    class Item: pass
    item = Item()
    item.name = '&lt;New Item&gt;'
    item.priority = 1
    item.owners = []
    item.createdate = mx.DateTime.now() #need this to be a timestamp and not just date for syncing
    item.duedate = item.finisheddate = None

    self.ItemLists[L].insert(0,item)

    host = Properties['host']
    cursor = self.Cursors[host]
    table = Properties['table']
    item.id = self.GetUID()

    cursor.execute("INSERT INTO "+table+" (priority,name,createdate,finisheddate,duedate,id) VALUES (%s,%s,%s,%s,%s,%s)",
                (item.priority,item.name,item.createdate,None,None,item.id))

    item.timestamp = self.TimeStamper(host, cursor, table, item.id)

    #tracking new item for syncing will happen in Edit Name

    LCtrl.InsertImageStringItem(0,"1", LCtrl.idx1)
    LCtrl.SetStringItem(0,1,item.name)

    if Properties['LCdate'] == 'timestamp':
        LCtrl.SetStringItem(0, self.attr2col_num['date'], item.timestamp.Format("%m/%d %H:%M:%S"))
    elif Properties['LCdate'] == 'createdate':
        LCtrl.SetStringItem(0, self.attr2col_num['date'], item.createdate.Format('%m/%d/%y'))

    self.curIdx = 0

    #if Display is being filtered we assume that is the owner of the new node
    owner = Properties['owner']	
    if owner and owner!='*ALL':
        self.ListCtrls[L].SetStringItem(0, self.attr2col_num['owners'], owner)
        item.owners = [owner]

        self.owners.Clear()
        self.owners.AppendText(owner)

        cursor.execute("UPDATE "+table+" SET owner1 = %s WHERE id = %s", (owner,item.id))
        item.timestamp = self.TimeStamper(host, cursor, table, item.id)  #not really necessary since just got a timestamp

    # decided that it was actually better not to ask for the owner on a new node	
    #else:
        #self.OnEditOwner()

    LCtrl.SetFocus() #needed for the in place editor to look right
    LCtrl.SetItemState(0, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED)

    self.OnDisplayInPlaceEditor() #(new=True)
</t>
<t tx="ekr.20051104081502.414">self.name.Clear()
self.owners.Clear()
self.note.Clear()
</t>
<t tx="ekr.20051104081502.415">@ Need to decide if we are going to have timestamp checking to be sure something hasn't changed
Note that there would not need to be timestamp checking on a new node
Also  there is no need to timestamp check on a local DB
The following code seems to work fine, however, I have just commented out the calls to it in NameEditor methods
@c
def Conflict(self, host, cursor, table, item):
    if host is 'sqlite':
        return False
    cursor.execute("Select timestamp from "+table+" WHERE id = %s", (item.id,))
    db_timestamp = cursor.fetchone()[0]
    if db_timestamp != item.timestamp:
        g.pr("There is a conflict and you should refresh display")
        return True
    else:
        return False
</t>
<t tx="ekr.20051104081502.416">def OnEditNote(self, evt=None):
    if self.modified:
        self.OnUpdate()

    idx = self.curIdx

    if idx == -1:
        return

    L = self.L

    #if self.editor:
        #machine = None
        #win32pdh.EnumObjects(None, machine, 0, 1) # resets Enum otherwise it seems to hold onto old data
        #object = "Process"
        #items, instances = win32pdh.EnumObjectItems(None,None,"Process", -1)
        #if 'TextPad' in instances:
            #g.pr("TextPad is running")
        #else:
            #self.editor = {}

    item = self.ItemLists[L][idx]
    file_name = re.sub('[\\/:*"&lt;&gt;|\?]','-',item.name) #make sure all chars are legal file name characters

    path = os.path.join(os.environ['TMP'],file_name[:50])+'.%s'%NOTE_EXT

    f = file(path,'w')
    f.write(self.GetNote())
    f.close()

    os.startfile(path)

    id = item.id
    for d in self.editor:
        if d['id'] == id:
            return

    ed = {}
    ed['time'] = os.path.getmtime(path)
    ed['host'] = self.PropertyDicts[L]['host']
    ed['table'] = self.PropertyDicts[L]['table']
    ed['path'] = path
    ed['id'] = item.id

    self.editor.append(ed)

    time.sleep(.1)
</t>
<t tx="ekr.20051104081502.417"></t>
<t tx="ekr.20051104081502.418">def OnNewList(self, event=None):
    if self.modified:
        self.OnUpdate()

    if OFFLINE_ONLY is True or REMOTE_HOST is None:
        hosts = [LOCAL_HOST]
    else:
        hosts = [LOCAL_HOST, REMOTE_HOST]

    dlg = wxSingleChoiceDialog(self, 'Databases', 'Choose a database:', hosts, wxCHOICEDLG_STYLE)
    val = dlg.ShowModal()
    dlg.Destroy()
    if val == wxID_OK:
        host = dlg.GetStringSelection()
    else:
        return

    cursor = self.GetCursor(host)
    if cursor is None:
        return

    dlg = wxTextEntryDialog(self, 'What is the name of the new table?', 'Create Table')
    val = dlg.ShowModal()
    dlg.Destroy()
    if val == wxID_OK:
        table = dlg.GetValue()
    else:
        return

    if not table:
        return

    location, rdbms = host.split(':')

    if rdbms == 'sqlite':
        cursor.execute("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name")
    else:
        cursor.execute("SHOW tables")

    if (table,) in cursor.fetchall():
        msg = wxMessageDialog(self,
                              "Table '%s' already exists"%table,
                              "Duplicate Table",
                              wxICON_ERROR|wxOK)
        msg.ShowModal()
        msg.Destroy()
        return

    dlg = wxMessageDialog(self,
          "Are you sure you want to create Table '%s'?"%table,
          "Create Table?",
          wxICON_QUESTION|wxYES_NO)

    if dlg.ShowModal() == wxID_YES:
        self.CreateTable(host,table)
        self.CreateNewNotebookPage(host,table)

        #self.AddListControl(tab_title) #add listcontrol displays the list

        #self.OnNewItem()

    dlg.Destroy()


</t>
<t tx="ekr.20051104081502.419">def OnFileList(self, evt=None, path=None):
    if self.modified:
        self.OnUpdate()

    #if there is no event, we got here through the start up loading of lists
    if evt:
        fileNum = evt.GetId() - wxID_FILE1			
        path = self.filehistory.GetHistoryFile(fileNum)
        location, rdbms, table = path.split(':')
        host = '%s:%s'%(location, rdbms)
        # only need to check if table is open if this is not at startup
        if table in [p['table'] for p in self.PropertyDicts if p['host'] == host]:
            dlg = wxMessageDialog(self,"%s (%s) is already open!"%(table,host),"List Open",wxICON_ERROR|wxOK)
            dlg.ShowModal()
            dlg.Destroy()
            return

    else:
        location, rdbms, table = path.split(':')
        host = '%s:%s'%(location, rdbms)

    cursor = self.GetCursor(host)
    if cursor is None:
        return

    if rdbms == 'sqlite':
        sql = "SELECT name FROM sqlite_master WHERE name = '%s'"%table
    else:
        sql = "SHOW TABLES LIKE '%s'"%table

    cursor.execute(sql)
    if not cursor.fetchall():
        dlg = wxMessageDialog(self,
                    "Table '%s' at host '%s' does not appear to exist!"%(table,host),
                    "Table does not exist",
                    wxICON_ERROR|wxOK)
        dlg.ShowModal()
        dlg.Destroy()
        return

    self.CreateNewNotebookPage(host,table)

</t>
<t tx="ekr.20051104081502.420">def OnOpenList(self, evt=None):
    if self.modified:
        self.OnUpdate()

    tree = {}

    if OFFLINE_ONLY is True or REMOTE_HOST is None:
        hosts = [LOCAL_HOST]
    else:
        hosts = [LOCAL_HOST, REMOTE_HOST]

    for host in hosts:
        cursor = self.GetCursor(host)
        if cursor:
            if host.split(':')[1] == 'sqlite':
                sql = "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name"
            else:
                sql = "SHOW TABLES" #sorted

            cursor.execute(sql)
            results = cursor.fetchall()

            #excluding already open tables + 'system' tables
            excluded_tables = [p['table'] for p in self.PropertyDicts if p['host'] == host]
            excluded_tables.extend(['user_sync','sync','owners'])

            tables = [t for (t,) in results if t not in excluded_tables]

            tree[host] = tables

    dlg = TreeDialog(self, "Open List", tree=tree)
    val = dlg.ShowModal()
    dlg.Destroy()
    if val == wxID_OK:
        sel = dlg.TreeCtrl.GetSelection()
        table = dlg.TreeCtrl.GetItemText(sel)
        sel = dlg.TreeCtrl.GetItemParent(sel)
        host = dlg.TreeCtrl.GetItemText(sel)

        if host in hosts: #takes care of highlighting root or hosts
            self.CreateNewNotebookPage(host,table)
</t>
<t tx="ekr.20051104081502.421">def OnDeleteList(self, evt=None):
    #ini controls whether the menu item is enabled
    Properties = self.PropertyDicts[self.L]
    host = Properties['host']
    table = Properties['table']

    #if table is in SYNC_TABLES, should we make a point of that?
    dlg = wxMessageDialog(self,
                        "Are you sure that you want to delete table %s (%s)?\n(Please note that you cannot recover it once it is deleted!)"%(table,host),
                        "Delete Table...",
                        wxICON_EXCLAMATION|wxYES_NO|wxNO_DEFAULT)

    val = dlg.ShowModal()
    dlg.Destroy()
    if val == wxID_NO:
        return

    rdbms = host.split(':')[1]

    if rdbms == 'mysql':
        dlg = wxMessageDialog(self,
                        "Are you sure really really sure you want to delete table %s (%s)?\n(You really really cannot recover it once it is deleted)"%(table,host),
                        "Delete Table...",
                        wxICON_EXCLAMATION|wxYES_NO|wxNO_DEFAULT)

        val = dlg.ShowModal()
        dlg.Destroy()
        if val == wxID_NO:
            return

    cursor = self.Cursors[host]
    cursor.execute("DROP TABLE %s"%table)

    self.OnCloseList()

</t>
<t tx="ekr.20051104081502.422">def OnCloseList(self, evt=None):
    if self.modified:
        self.OnUpdate()

    L = self.L

    del self.ItemLists[L]
    del self.PropertyDicts[L]
    del self.ListCtrls[L]
    del self.OwnerLBoxes[L]

    self.nb.DeletePage(L)        

    ln = len(self.PropertyDicts)
    if ln:
        self.nb.SetSelection(0)
        self.L = 0
    else:
        self.L = -1




</t>
<t tx="ekr.20051104081502.423">def OnCloseAll(self, evt=None):
    if self.modified:
        self.OnUpdate()

    while self.L != -1:
        self.OnCloseList()

    self.name.Clear()
    self.owners.Clear()
    self.note.Clear()
    #note that Clearing does set self.modified (eg {'name':1})
    self.modified = {}

</t>
<t tx="ekr.20051104081502.424">def OnSaveAsText(self, evt=None):
    if self.modified:
        self.OnUpdate()

    Properties = self.PropertyDicts[self.L]
    wildcard = "txt files (*.txt)|*.txt|All files (*.*)|*.*"
    #dlg = wxFileDialog(self, "Save file", "", Properties['table'], wildcard, wxSAVE|wxOVERWRITE_PROMPT|wxCHANGE_DIR)

    body = ""
    for i,item in enumerate(self.ItemLists[self.L]):
        body = body+"%d. %s (%d)\n"%(i+1, item.name, item.priority)

    table = Properties['table']
    location, rdbms = Properties['host'].split(':')
    filename = re.sub('[\\/:*"&lt;&gt;|\?]','-','%s-%s-%s'%(location,rdbms,table)) 
    filename = filename[:50]+'.txt'

    path = os.path.join(DIRECTORY,filename)

    f = file(path,'w')
    f.write(body)
    f.close()

    os.startfile(path)

    self.SetStatusText("Saved file %s"%path)

</t>
<t tx="ekr.20051104081502.425">def OnArchive(self, evt=None):
    if self.modified:
        self.OnUpdate()

    Properties = self.PropertyDicts[self.L]
    host = Properties['host']
    cursor = self.Cursors[host]
    table = Properties['table']
    rdbms = host.split(':')[1]

    table_archive = table+'_archive'

    #need to test for existence of table_archive
    if rdbms == 'sqlite':
        cursor.execute("SELECT name FROM sqlite_master WHERE type='table' ORDER BY name")
    else:
        cursor.execute("SHOW tables")

    results = cursor.fetchall()

    if (table_archive,) not in results:
        dlg = wxMessageDialog(self,
                    "Do you want to create an archive for table %s (%s)"%(table,rdbms),
                    "Create an archive...",
                    wxICON_QUESTION|wxYES_NO)
        val = dlg.ShowModal()
        dlg.Destroy()
        if val==wxID_YES:
            self.CreateTable(host,table_archive)
        else:
            return

    label1 = "In table %s (%s) \narchive all finished items older than:"%(table,rdbms)
    label2 = "Archive all finished items"
    dlg = FinishedDialog(self, "Archive completed items", days=7, spin_label=label1, check_label=label2)

    val = dlg.ShowModal()
    dlg.Destroy() #dialogs and frames not destroyed right away to allow processing events, methods
    if val==wxID_CANCEL:
        return

    if dlg.check.GetValue():
        cursor.execute("SELECT id,priority,name,createdate,finisheddate,duedate,owner1,owner2,owner3,note FROM "+table+" WHERE finisheddate IS NOT NULL")
    else:
        days = dlg.text.GetValue()
        date = mx.DateTime.today() - int(days)
        cursor.execute("SELECT id,priority,name,createdate,finisheddate,duedate,owner1,owner2,owner3,note FROM "+table+" WHERE finisheddate &lt; %s",(date,))

    results = cursor.fetchall()
    dlg = wxMessageDialog(self,
                        "Archiving will remove %d records from %s.\nDo you want to proceed?"%(len(results),table),
                        "Proceed to archive...",
                        wxICON_QUESTION|wxYES_NO)

    val = dlg.ShowModal()
    dlg.Destroy()
    if val == wxID_NO:
        return

    if table in SYNC_TABLES:
        if rdbms == 'sqlite':
            def track_deletes():
                timestamp = mx.DateTime.now()
                cursor.execute("INSERT INTO sync (id,action,table_name,name,timestamp) VALUES (%s,%s,%s,%s,%s)",(id,'d',table,name,timestamp))
        else:
            def track_deletes():
                cursor.execute("INSERT INTO sync (id,action,table_name,user,name) VALUES (%s,%s,%s,%s,%s)",(id,'d',table,USER,name))
    else:
        def track_deletes():
            pass	

    for row in results:
        # the next line is necessary because pysqlite returns a tuple-like object that is not a tuple
        r = tuple(row)
        id = r[0]
        name = r[2]
        cursor.execute("INSERT INTO "+table_archive+"  (id,priority,name,createdate,finisheddate,duedate,owner1,owner2,owner3,note) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)",r)
        timestamp = self.TimeStamper(host, cursor, table_archive, id)
        cursor.execute("DELETE from "+table+" WHERE id = %s", (id,))
        track_deletes()

    self.OnRefresh()
    dlg = wxMessageDialog(self,
                        "Table %s had items older than %s days successfully archived"%(table,days),
                        "Archiving successful...",
                        wxICON_INFORMATION|wxOK)
    dlg.ShowModal()
</t>
<t tx="ekr.20051104081502.426">def OnWorkOffline(self, evt=None):
    global OFFLINE_ONLY
    OFFLINE_ONLY = not OFFLINE_ONLY
    if OFFLINE_ONLY:
        del self.Cursors[REMOTE_HOST]
    else:
        server = REMOTE_HOST.split(':')[0]
        try:
            socket.gethostbyname(server)
        except:
            dlg = wxMessageDialog(None, "Cannot connect to remote server! Will set to work offline.", "ListManager", style=wxOK|wxICON_EXCLAMATION|wxSTAY_ON_TOP)
            dlg.ShowModal()
            dlg.Destroy()
            OFFLINE_ONLY = True

    self.filemenu.Check(idOFFLINE,OFFLINE_ONLY)

</t>
<t tx="ekr.20051104081502.428"></t>
<t tx="ekr.20051104081502.429">def OnItemSelected(self, evt=None):
    if self.modified:
        self.OnUpdate()

    if evt:
        idx = evt.GetIndex()
    elif self.curIdx != -1:
        idx = self.curIdx
    else: # really to catch self.curIdx = -1 (see OnDelete and OnRefresh)
        self.name.Clear() # could be moved out of if
        self.owners.Clear() # could be moved out of if
        self.note.Clear()
        #note that Clearing does set self.modified (eg {'name':1})
        self.modified = {}
        return

    L = self.L
    item = self.ItemLists[L][idx]

    self.name.Clear()
    self.name.AppendText(item.name) #SetValue(item.name) - if you use setvalue you don't get the font

    self.owners.Clear()
    self.owners.AppendText('; '.join(item.owners))

    note = self.GetNote(L,item)
    if note.find("&lt;leo_file&gt;") != -1:
        self.note.SetValue("Leo Outline")
        self.note.SetEditable(False)
    else:
        self.note.SetValue(note)
        self.note.SetEditable(True)

    self.ListCtrls[L].EnsureVisible(idx)
    self.curIdx = idx

    #writing to text widgets caused wxEVT_COMMAND_TEXT_UPDATED which is caught by EVT_TEXT, which updates self.modified
    self.modified={}

</t>
<t tx="ekr.20051104081502.430">def OnItemActivated(self,evt):
    g.pr("On Activated")

</t>
<t tx="ekr.20051104081502.431">def OnShowAll(self, evt=None):
    L = self.L
    OLBox = self.OwnerLBoxes[L]

    Properties = self.PropertyDicts[L]
    Properties['showfinished'] = -1
    Properties['owner'] = '*ALL'

    OLBox.SetStringSelection('*ALL')

    self.OnRefresh()
</t>
<t tx="ekr.20051104081502.432">def OnRefresh(self, evt=None):
    #OnItemSelected should be able to handle no items so this could be very short
    L = self.L

    results = self.ReadFromDB()
    self.ItemLists[L] = self.CreateAndDisplayList(results)

    if self.ItemLists[L]:
        self.ListCtrls[L].SetItemState(0, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED)
        self.curIdx = 0
    else:
        self.curIdx = -1		

    self.OnItemSelected()
</t>
<t tx="ekr.20051104081502.433">def OnFilterOwners(self, evt=None):
    if self.modified:
        self.OnUpdate()
    sel = self.OwnerLBoxes[self.L].GetStringSelection()

    if sel:
        self.PropertyDicts[self.L]['owner'] = sel
        self.OnRefresh()
</t>
<t tx="ekr.20051104081502.434">def OnColumnClick(self, evt):
    col_num = evt.GetColumn()
    L = self.L
    LCtrl = self.ListCtrls[L]
    Sort = self.PropertyDicts[L]['sort']
    attr2col = self.attr2col_num

    prev_sort_attr = Sort.get('attribute') #if this is the first sort Properties['sort'] is {}

    #following is a little bit ugly but gets the key from the value, which is col_num
    Sort['attribute'] = attr2col.keys()[attr2col.values().index(col_num)]

    if prev_sort_attr == Sort['attribute']:
        Sort['direction'] = not Sort['direction']
    else:
        Sort['direction'] = 0

    self.OnRefresh()

    LCtrl.ClearColumnImage(attr2col['priority'])
    LCtrl.ClearColumnImage(attr2col['date'])
    img_num = LCtrl.arrows[Sort['direction']]
    LCtrl.SetColumnImage(col_num, img_num)

</t>
<t tx="ekr.20051104081502.435">def OnShowFinished(self,evt):
    Properties = self.PropertyDicts[self.L]
    label1 = "Enter the number of days to retain\ncompleted tasks in the display:"
    label2 = "Show all finished items"
    dlg = FinishedDialog(self, "Display of completed items", days=Properties['showfinished'], spin_label=label1, check_label=label2)
    if dlg.ShowModal()==wxID_OK:
        if dlg.check.GetValue():
            Properties['showfinished'] = -1
        else:
            days = dlg.text.GetValue()
            Properties['showfinished'] = int(days)			
        self.OnRefresh()
    dlg.Destroy()

</t>
<t tx="ekr.20051104081502.436">def OnColumnRightClick(self, evt=None):
    col = evt.GetColumn()
    if col != self.attr2col_num['date']:
        return

    L = self.L
    LCtrl = self.ListCtrls[L]
    Properties = self.PropertyDicts[L]

    #x,y = evt.GetPosition()
    datemenu = wxMenu()

    for i,date in enumerate(['Create Date','Last Modified','Due Date','Completion Date']):
        datemenu.Append(200+i, date)
        EVT_MENU(self, 200+i, lambda e, i=i: self.ChangeDateDisplayed(e,i))

    x = LCtrl.GetColumnWidth(1)+ LCtrl.GetColumnWidth(2) + LCtrl.GetColumnWidth(3)
    self.PopupMenu(datemenu,(x,40))
    datemenu.Destroy()


</t>
<t tx="ekr.20051104081502.437">def OnDisplayDateCategory(self, evt=None):
    dlg = wxSingleChoiceDialog(self, 'Date Display', 'Choose a date to display:',
                    ['Create Date','Last Modified','Due Date','Completion Date']
                    , wxOK|wxCANCEL)
    val = dlg.ShowModal()
    dlg.Destroy()

    if val == wxID_OK:
        idx = dlg.GetSelection()
        self.ChangeDateDisplayed(i=idx)

</t>
<t tx="ekr.20051104081502.438">def ChangeDateDisplayed(self, evt=None, i=0):
    L = self.L
    LCtrl = self.ListCtrls[L]
    self.PropertyDicts[L]['LCdate'] = displaydate = ('createdate','timestamp','duedate','finisheddate')[i]	
    col_num = self.attr2col_num['date']
    col_info = LCtrl.GetColumn(col_num)
    col_info.SetText(self.date_titles[displaydate])
    LCtrl.SetColumn(col_num,col_info)
    self.DisplayList(self.ItemLists[L])
    #self.OnRefresh() #have gone back and forth but think that it should be self.DisplayList
</t>
<t tx="ekr.20051104081502.439">def DisplayList(self, List, L=None):
    #OnPasteItems needs to be able to have an L that is not self.L
    if L is None:
        L = self.L
    LCtrl = self.ListCtrls[L]
    LCdate = self.PropertyDicts[L]['LCdate']
    if LCdate == 'timestamp':
        format = '%m/%d %H:%M:%S'
    else:
        format = '%m/%d/%y'
    LCtrl.DeleteAllItems()

    for x,item in enumerate(List):
        &lt;&lt; draw item &gt;&gt;


</t>
<t tx="ekr.20051104081502.440">LCtrl.InsertImageStringItem(x, str(item.priority), LCtrl.idx1)
LCtrl.SetStringItem(x,1,item.name)
LCtrl.SetStringItem(x,2,'; '.join(item.owners))
date = item.__dict__[LCdate]
LCtrl.SetStringItem(x,3,date and date.Format(format) or "")

if item.finisheddate:
    LC_Item = LCtrl.GetItem(x)
    LC_Item.SetImage(LCtrl.idx0) #might just want generic number or greyed one two three
    LC_Item.SetTextColour(wxLIGHT_GREY)
    LCtrl.SetItem(LC_Item)

elif item.priority==2:
    LC_Item = LCtrl.GetItem(x)
    f = self.LC_font
    f.SetWeight(wxBOLD)
    LC_Item.SetFont(f)
    f.SetWeight(wxNORMAL) #resetting weight
    LCtrl.SetItem(LC_Item)

elif item.priority==3:
    LC_Item = LCtrl.GetItem(x)
    f = self.LC_font
    f.SetWeight(wxBOLD)
    LC_Item.SetFont(f)
    f.SetWeight(wxNORMAL) #return to normal
    LC_Item.SetTextColour(wxRED)
    LCtrl.SetItem(LC_Item)
</t>
<t tx="ekr.20051104081502.441"></t>
<t tx="ekr.20051104081502.442">def OnPageSetup(self, evt):
    #need to pass printdata to tableprint

    psdata = wxPageSetupDialogData()

    # if want to vary margins will need to save them as ivars and then set
    #psdata.SetMarginTopLeft((self.Left,self.Top))
    psdata.EnableMargins(False)
    psdata.SetPrintData(self.printdata) #gets Paper Orientation and PaperId info from printdata

    dlg = wxPageSetupDialog(self, psdata)
    if dlg.ShowModal() == wxID_OK:
        self.printdata = dlg.GetPageSetupData().GetPrintData()
        dlg.Destroy()
</t>
<t tx="ekr.20051104081502.443">def OnPrint(self, evt=None, prev=False, showprtdlg=True): 		#???self.psdata = psdata
    IList = self.ItemLists[self.L]
    Properties = self.PropertyDicts[self.L]

    prt = PrintTable(self.printdata) #self.printdata is the wxPrintData object with Orientation Info

    font_name = prt.default_font_name
    prt.text_font = {'Name':font_name, 'Size':11, 'Colour':[0, 0, 0], 'Attr':[0, 0, 0]}
    prt.label_font = {'Name':font_name, 'Size':12, 'Colour':[0, 0, 0], 'Attr':[1, 0, 0]}
    prt.header_font = {'Name':font_name, 'Size':14, 'Colour':[0, 0, 0], 'Attr':[1, 0, 0]}

    prt.row_def_line_colour = wxLIGHT_GREY
    prt.column_def_line_colour = wxLIGHT_GREY

    prt.left_margin = 0.5

    data = []
    for row,item in enumerate(IList):	
        data.append([str(item.priority),
                    item.name,
                    item.duedate and item.duedate.Format('%m/%d/%y') or '',
                    '; '.join([x.split(',')[0] for x in item.owners])]) #just last names

        if item.finisheddate:
            prt.SetCellText(row, 0, wxLIGHT_GREY)
            prt.SetCellText(row, 1, wxLIGHT_GREY)
            prt.SetCellText(row, 2, wxLIGHT_GREY)
            prt.SetCellText(row, 3, wxLIGHT_GREY)

    prt.data = data
    prt.label = ['P','Item','Due','Owner']

    if self.printdata.GetOrientation() == wxPORTRAIT:
        prt.set_column = [.2, 5, .65, 1]
    else:
        prt.set_column = [.2, 7, .65, 1.5]

    title = "Table: %s   Owner: %s    "%(Properties['table'],Properties['owner'])
    prt.SetHeader(title, type='Date &amp; Time', align=wxALIGN_LEFT, indent = 1.5)
    prt.SetFooter("Page No ", type ="Num")

    if prev:
        prt.Preview()
    else:
        prt.Print(prompt=showprtdlg)
</t>
<t tx="ekr.20051104081502.444"></t>
<t tx="ekr.20051104081502.445">def OnWindowExit(self, evt):
    #this is called if you close the ListManager Window with the X
    if evt.CanVeto():
        self.OnExit()
    else:
        evt.Skip()
</t>
<t tx="ekr.20051104081502.446">def OnExit(self, event=None):   
    &lt;&lt; save configuration file &gt;&gt;
    sys.stderr.dlg.Destroy() #destroys the error dialog; need to do this to shut down correctly
    if self.ModifierDialog: #only reason to check is if closed before ModifierDialog is constructed
        self.ModifierDialog.Destroy()
    self.Close(1)
</t>
<t tx="ekr.20051104081502.447">cp.remove_section('Files')
cp.add_section("Files")

x,y = self.GetSizeTuple()

cp.set('Configuration','x', str(x))
cp.set('Configuration','y', str(y))

numfiles = self.filehistory.GetNoHistoryFiles()

for n in range(numfiles):
    cp.set("Files", "path%d"%n, self.filehistory.GetHistoryFile(n))

try:
    #you have to give ConfigParser a writable object
    cfile = file(config_file, 'w')
    cp.write(cfile)
    cfile.close()
except IOError:
    g.pr("The configuration file can't be written!")
    time.sleep(10) #so you can see that there was a problem
</t>
<t tx="ekr.20051104081502.448"></t>
<t tx="ekr.20051104081502.449">def OnFind(self, evt=None):
    self.FindDialog.Show(True)
    self.FindDialog.FindText.SetSelection(-1,-1)
    self.FindDialog.FindText.SetFocus()


</t>
<t tx="ekr.20051104081502.450">def FindString(self, evt=None):
    L = self.L
    Properties = self.PropertyDicts[L]
    cursor = self.Cursors[Properties['host']]
    table = Properties['table']

    pat = self.FindDialog.FindText.GetValue()
    likepat = r"'%"+pat+r"%'"
    finished = self.FindDialog.SearchFinished.GetValue()
    notes = self.FindDialog.SearchNotes.GetValue()

    if finished:
        WHERE = "WHERE "
    else:
        WHERE = "WHERE finisheddate IS NULL AND "

    if notes:
        SELECT = "SELECT priority,name,createdate,finisheddate,duedate,owner1,owner2,owner3,id,timestamp,note FROM %s "%table
        WHERE = WHERE + "(name LIKE %s OR note LIKE %s) ORDER BY timestamp DESC"%(likepat,likepat)
    else:
        SELECT = "SELECT priority,name,createdate,finisheddate,duedate,owner1,owner2,owner3,id,timestamp FROM %s "%table
        WHERE = WHERE + "name LIKE %s ORDER BY timestamp DESC"%likepat

    sql = SELECT + WHERE			
    try:
        cursor.execute(sql)
    except:
        g.pr("Cannot read %s: %s"%(Properties['host'],table))
        return
    else:
        results = cursor.fetchall()

    case = self.FindDialog.MatchCase.GetValue()
    whole = self.FindDialog.MatchWhole.GetValue()

    if whole:
        pat = '\\b%s\\b'%pat

    if case:
        z = re.compile(pat)
    else:
        z =re.compile(pat, re.I)

    if notes:
        results = [x for x in results if re.search(z,x[1]) or re.search(z,x[10])]
    else:
        results = [x for x in results if re.search(z,x[1])]

    Properties['LCdate'] = 'timestamp'
    self.ItemLists[L]= IList = self.CreateAndDisplayList(results)

    LCtrl = self.ListCtrls[L]
    col_num = self.attr2col_num['date']
    col_info = LCtrl.GetColumn(col_num)
    col_info.SetText(self.date_titles['timestamp'])
    LCtrl.SetColumn(col_num,col_info)

    if IList:
        self.curIdx = 0
        LCtrl.SetItemState(0, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED)
    else:		
        self.curIdx = -1

    self.OnItemSelected()

    Properties['sort'] = {'direction':0,'attribute':'date'}
    Properties['owner'] = '*ALL'

    owner_idx = self.OwnerLBoxes[L].GetSelection()
    if owner_idx != -1:
        self.OwnerLBoxes[L].SetSelection(owner_idx, 0) #get exception if index = -1

    self.SetStatusText("Found %d items"%len(IList))
</t>
<t tx="ekr.20051104081502.451">def FindNode(self, item, showfinished=True):
    L = self.L
    LCtrl = self.ListCtrls[L]
    Properties = self.PropertyDicts[L]

    Properties['owner'] = '*ALL'
    Properties['showfinished'] = showfinished

    self.ItemLists[L] = IList = self.CreateAndDisplayList(self.ReadFromDB())

    id = item.id
    idx = -1
    for item in IList:
        idx+=1
        if id == item.id:
            break
    else:
        idx = -1

    if idx != -1:	
        LCtrl.SetItemState(idx, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED)
        LCtrl.EnsureVisible(idx)
    self.curIdx = idx

</t>
<t tx="ekr.20051104081502.452"></t>
<t tx="ekr.20051104081502.453">def GetCursor(self, host):
    cursor = self.Cursors.get(host)
    if cursor:
        return cursor

    location, rdbms = host.split(':')

    if rdbms == 'sqlite':
        db = os.path.join(DIRECTORY,location,DB)
        try:
            Con = sqlite.connect(db=db, autocommit=1)
            cursor = Con.cursor()
            self.sqlite_connections.append(Con)  #getting a weak reference error from PySQLite and this makes it go away
        except:
            dlg = wxMessageDialog(self,
                    "Could not connect to SQLite database at %s"%location,
                    "Connection problem!",
                    wxICON_ERROR|wxOK)
            dlg.ShowModal()
            dlg.Destroy()
            cursor = None

    elif not OFFLINE_ONLY:
        try:
            Con = MySQLdb.connect(host=location, user=USER, passwd=PW, db=DB)
            cursor = Con.cursor()
        except:
            dlg = wxMessageDialog(self,
                    "host = %s | user = %s | password = %s**** | db = %s - could not connect!"%(host,USER,PW[:3],DB),
                    "Connection problem",
                    wxICON_ERROR|wxOK)
            dlg.ShowModal()
            dlg.Destroy()
            cursor = None

    if cursor:
        self.Cursors[host] = cursor

    return cursor


</t>
<t tx="ekr.20051104081502.454">def GetNote(self, L=None, item=None):
    if L is None:
        L = self.L

    if item is None:
        if self.curIdx != -1:
            item = self.ItemLists[L][self.curIdx]
        else:
            return ''

    Properties = self.PropertyDicts[L]

    cursor = self.Cursors[Properties['host']]
    table = Properties['table']
    cursor.execute("SELECT note from "+table+" WHERE id = %s", (item.id,))

    ###### Debug -- this does happen where note brings back None 053003
    z = cursor.fetchone()
    if z is None:
        g.pr("In GetNote -&gt; SELECT should not bring back None")
        g.pr("           -&gt; item.id=",item.id)
        z = (None,)
    note = z[0]
    if note is None:
        note = ''
    return note

</t>
<t tx="ekr.20051104081502.455">def CreateTable(self, host, table):
    cursor = self.Cursors[host]
    rdbms = host.split(':')[1]
    if rdbms == 'sqlite':
        sql = """CREATE TABLE '%s' ('id' varchar(36) PRIMARY KEY,
'priority' int(1),
'name' varchar(150),
'createdate' datetime,
'finisheddate' date,
'duedate' date,
'owner1' varchar(25),
'owner2' varchar(25),
'owner3' varchar(25),
'note' text,
'timestamp' timestamp(14))"""%table
    else:
        sql = """CREATE TABLE `%s` (`id` varchar(36) NOT NULL default '',
`priority` int(1) NOT NULL default '1',
`name` varchar(150) NOT NULL default '',
`createdate` datetime NOT NULL default '0000-00-00 00:00:00',
`finisheddate` date default '0000-00-00',
`duedate` date default '0000-00-00',
`owner1` varchar(25) default '',
`owner2` varchar(25) default '',
`owner3` varchar(25) default '',
`note` text,
`timestamp` timestamp(14) NOT NULL,PRIMARY KEY  (`id`)) TYPE=MyISAM"""%table

    cursor.execute(sql)
</t>
<t tx="ekr.20051104081502.456">def ReadFromDB(self):
    L = self.L
    Properties = self.PropertyDicts[L]

    host = Properties['host']
    cursor = self.GetCursor(host)
    if cursor is None:
        return None

    table = Properties['table']

    owner = Properties['owner']
    if owner == '*ALL':
        WHERE = ""
    else:
        WHERE = 'WHERE (owner1 = "%s" OR owner2 = "%s" OR owner3 = "%s")'%(owner,owner,owner)

    #-1 show them all; 0 show none; integer show for that many days
    days = Properties['showfinished']	
    if days != -1:
        if days:
            date = mx.DateTime.now() - days
            t = "(finisheddate IS NULL OR finisheddate &gt; '%s')"%date
        else:
            t = "finisheddate IS NULL"

        if WHERE:
            WHERE = "%s AND %s"%(WHERE,t)
        else:
            WHERE = " WHERE %s"%t

    Sort = Properties['sort']
    if Sort:
        sort_attr = Sort['attribute']
        if sort_attr == 'date':
            sort_attr = Properties['LCdate']
        elif sort_attr == 'owners':
            sort_attr = 'owner1'

        WHERE = WHERE + " ORDER BY " + sort_attr
        #if not direction: WHERE = WHERE + " DESC"   works because ASC is the default
        if not Sort['direction']:
            WHERE = WHERE + " DESC" 

    sql = "SELECT priority,name,createdate,finisheddate,duedate,owner1,owner2,owner3,id,timestamp FROM %s %s"%(table,WHERE)

    try:
        cursor.execute(sql)
    except:
        g.pr("Cannot read %s: %s"%(Properties['host'],table))
        return None #[]
    else:
        return cursor.fetchall()



</t>
<t tx="ekr.20051104081502.457">def CreateAndDisplayList(self, results):
    LCtrl = self.ListCtrls[self.L]
    LCdate = self.PropertyDicts[self.L]['LCdate']
    if LCdate == 'timestamp':
        format = '%m/%d %H:%M:%S'
    else:
        format = '%m/%d/%y'
    itemlist = []

    LCtrl.DeleteAllItems()
    class Item: pass

    for x,row in enumerate(results):

        item = Item()
        &lt;&lt; assign item attributes &gt;&gt;
        itemlist.append(item)

        &lt;&lt; draw item &gt;&gt;

    return itemlist


</t>
<t tx="ekr.20051104081502.458">item.priority = int(row[0]) #int(row[0]) needs int because it seems to come back as a long from MySQL
item.name = row[1]
item.createdate = row[2]
item.finisheddate = row[3]
item.duedate = row[4]
item.owners = [y for y in row[5:8] if y] #if you carry around ['tom',None,None] Note this is 5:8 not 5:7
item.id = row[8]
item.timestamp = row[9]

</t>
<t tx="ekr.20051104081502.459">LCtrl.InsertImageStringItem(x, str(item.priority), LCtrl.idx1)
LCtrl.SetStringItem(x,1,item.name)
LCtrl.SetStringItem(x,2,'; '.join(item.owners))
date = item.__dict__[LCdate]
LCtrl.SetStringItem(x,3,date and date.Format(format) or "")

if item.finisheddate:
    LC_Item = LCtrl.GetItem(x)
    LC_Item.SetImage(LCtrl.idx0) #might just want generic number or greyed one two three
    LC_Item.SetTextColour(wxLIGHT_GREY)
    LCtrl.SetItem(LC_Item)

elif item.priority==2:
    LC_Item = LCtrl.GetItem(x)
    f = self.LC_font
    f.SetWeight(wxBOLD)
    LC_Item.SetFont(f)
    f.SetWeight(wxNORMAL) #resetting weight
    LCtrl.SetItem(LC_Item)

elif item.priority==3:
    LC_Item = LCtrl.GetItem(x)
    f = self.LC_font
    f.SetWeight(wxBOLD)
    LC_Item.SetFont(f)
    f.SetWeight(wxNORMAL) #return to normal
    LC_Item.SetTextColour(wxRED)
    LCtrl.SetItem(LC_Item)
</t>
<t tx="ekr.20051104081502.460">def OnSync(self, evt=None):
    if self.modified:
        self.OnUpdate()
    #Note that the results of an sqlite query are an instance that you need to turn into a tuple or MySQL gets unhappy

    if OFFLINE_ONLY:
        dlg = wxMessageDialog(self, "You need to be online to synchronize!", style = wxOK|wxICON_ERROR)
        dlg.ShowModal()
        dlg.Destroy()
        return

    dlg = wxMessageDialog(self,"Synchronize Table(s): "+" and ".join(SYNC_TABLES),"Synchronize...",wxICON_QUESTION|wxYES_NO)
    val = dlg.ShowModal()
    dlg.Destroy()
    if val == wxID_NO:
        return

    if REMOTE_HOST is None:
        g.pr("There doesn't appear to be a Remote Server")
        return

    if LOCAL_HOST is None:
        g.pr("There doesn't appear to be a Local Server")
        return

    g.pr("LOCAL_HOST=",LOCAL_HOST)
    g.pr("REMOTE_HOST=",REMOTE_HOST)

    r_cursor = self.GetCursor(REMOTE_HOST)
    if r_cursor is None:
        g.pr("Couldn't get a cursor for %s"%REMOTE_HOST)
        return

    l_cursor = self.GetCursor(LOCAL_HOST)
    if l_cursor is None:
        g.pr("Couldn't get a cursor for %s"%LOCAL_HOST)
        return

    # moving the sync time back a second to make sure that we don't lose track of any nodes
    #that are being updated or inserted at the same time as we are syncing
    r_cursor.execute("SELECT NOW()")
    l_now = mx.DateTime.now()-mx.DateTime.oneSecond
    r_now = r_cursor.fetchone()[0]-mx.DateTime.oneSecond
    #because of some inconsistent rounding appears necessary to make sure the sqlite timestamp is less than l_now
    #having seen same issue for mysql but for consistency (and because sqlite could also be "server" rdbms
    l_ts = l_now - mx.DateTime.DateTimeDelta(0,0,0,0.02)
    r_ts = r_now - mx.DateTime.DateTimeDelta(0,0,0,0.02)
    g.pr("l_now=",l_now, "l_ts =",l_ts)
    g.pr("r_now=",r_now, "r_ts=",r_ts)

    r_cursor.execute("SELECT MAX(last_sync) FROM user_sync WHERE user = %s", (USER,))
    r_last_sync = r_cursor.fetchone()[0]
    g.pr("last sync (remote time) =",r_last_sync)

    l_cursor.execute("SELECT MAX(last_sync) FROM user_sync")
    l_last_sync = l_cursor.fetchone()[0] #note MAX returns a string with sqlite so we turn it make into DateTime
    l_last_sync = mx.DateTime.DateTimeFrom(l_last_sync)
    g.pr("last sync (local time) =",l_last_sync)

    for table in SYNC_TABLES:
        # Need to pick up changes for both so syncing one doesn't add new things and screw up the second sync
        g.pr("Checking "+table+" on the Remote Server; changes (excluding deletes) are:")
        r_cursor.execute("SELECT id,createdate from "+table+" WHERE timestamp &gt; %s AND timestamp &lt;= %s",(r_last_sync,r_now)) 
        r_results = r_cursor.fetchall()
        g.pr("Server changes (excluding deletes)")
        g.pr(r_results)

        g.pr("Checking "+table+" on Local; changes (excluding deletes) are:")
        l_cursor.execute("SELECT id,createdate from "+table+" WHERE timestamp &gt; %s AND timestamp &lt;= %s",(l_last_sync,l_now))
        l_results = l_cursor.fetchall()
        g.pr("Local changes (excluding deletes)")
        g.pr(l_results)

        for id, createdate in r_results:
            r_cursor.execute("SELECT priority,name,owner1,owner2,owner3,createdate,finisheddate,duedate,note,id FROM "+table+" WHERE ID = %s",(id,))
            row = r_cursor.fetchone()
            if row:
                if createdate &gt; r_last_sync:
                    l_cursor.execute("INSERT INTO "+table+" (priority,name,owner1,owner2,owner3,createdate,finisheddate,duedate,note,id) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", row) #*row also works
                    g.pr("Created %s in %s on Local"%(id,table))
                else:
                    l_cursor.execute("UPDATE "+table+" SET priority = %s, name =%s, owner1 = %s, owner2 = %s, owner3 = %s, createdate = %s, finisheddate = %s, duedate = %s, note = %s WHERE id = %s", row)
                    g.pr("Updated %s in %s on Local"%(id,table))
                # for reasons I don't understand l_now here is a 1/100 ahead of l_now when inserted into user_sync
                l_cursor.execute("UPDATE "+table+" SET timestamp = %s WHERE id = %s", (l_ts,id))

        for id, createdate in l_results:
            l_cursor.execute("SELECT priority,name,owner1,owner2,owner3,createdate,finisheddate,duedate,note,id FROM "+table+" WHERE ID = %s",(id,))
            row = l_cursor.fetchone()
            if row:
                row = tuple(row)
                #above needed because sqlite returns an enhanced tuple-like object that is not a tuple
                if createdate &gt; l_last_sync:
                    r_cursor.execute("INSERT INTO "+table+" (priority,name,owner1,owner2,owner3,createdate,finisheddate,duedate,note,id) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", row)
                    g.pr("Created %s in %s on Server"%(id,table))
                else:
                    r_cursor.execute("UPDATE "+table+" SET priority = %s, name =%s, owner1 = %s, owner2 = %s, owner3 = %s, createdate = %s, finisheddate = %s, duedate = %s, note = %s WHERE id = %s", row)
                    g.pr("Updated %s in %s on Server"%(id,table))
                r_cursor.execute("UPDATE "+table+" SET timestamp = %s WHERE id = %s", (r_ts,id))

    #Handle the deletes; Note if at some point only 'd's are being written won't have to check for 'd'
    r_cursor.execute("SELECT id,table_name FROM sync WHERE timestamp &gt; %s AND timestamp &lt;= %s AND action = 'd'",(r_last_sync,r_now))
    r_results = r_cursor.fetchall()

    l_cursor.execute("SELECT id,table_name FROM sync WHERE timestamp &gt; %s AND timestamp &lt;= %s AND action = 'd'",(l_last_sync,l_now))
    l_results = l_cursor.fetchall()

    for id,table in l_results:
        r_cursor.execute("DELETE from "+table+" WHERE id = %s", (id,))
        g.pr("Deleted %s from %s on Server (if it existed there)"%(id,table))

    for id,table in r_results:
        l_cursor.execute("DELETE from "+table+" WHERE id = %s", (id,))
        g.pr("Deleted %s from %s on Local (if it existed there)"%(id,table)	)
    #End of deletes code

    #update the user_sync database with the latest sync times
    l_cursor.execute("INSERT INTO user_sync (user,last_sync) VALUES (%s,%s)", (USER,l_now)) #don't really need USER for local
    r_cursor.execute("INSERT INTO user_sync (user,last_sync) VALUES (%s,%s)", (USER,r_now)) 

    g.pr("Synchronization completed")

</t>
<t tx="ekr.20051104081502.461">def TimeStamper(self, host, cursor, table, id):
    #note that you can insert a timestamp value into an mysql timestamp field
    if host.split(':')[1] == 'sqlite': #host -&gt; location:rdbms
        timestamp = mx.DateTime.now()
        cursor.execute("UPDATE "+table+" SET timestamp = %s WHERE id = %s", (timestamp,id))
    else:
        cursor.execute("Select timestamp from "+table+" WHERE id = %s", (id,))
        timestamp = cursor.fetchone()[0]

    return timestamp
</t>
<t tx="ekr.20051104081502.462"></t>
<t tx="ekr.20051104081502.463">def OnShowEvaluate(self, evt=None):

    self.EvalDialog.Show(True)
    self.EvalDialog.EvalText.SetSelection(-1,-1)
    self.EvalDialog.EvalText.SetFocus()

</t>
<t tx="ekr.20051104081502.464">def OnEvaluate(self, evt=None):
    expr = self.EvalDialog.EvalText.GetValue()
    g.pr("%s =&gt; "%expr,newline=False)
    g.pr(eval(expr))

</t>
<t tx="ekr.20051104081502.465"></t>
<t tx="ekr.20051104081502.466">def OnShowAbout(self, evt=None):
    from about import AboutBox
    dlg = AboutBox(self, app_version = VERSION)
    dlg.ShowModal()
    dlg.Destroy()

</t>
<t tx="ekr.20051104081502.467">def OnShowHelp(self, evt=None):
    os.startfile('ListManager.chm')

</t>
<t tx="ekr.20051104081502.468">def GetUID(self):
    pyiid = CreateGuid()
    # the str(pyiid) looks like {....} and doing [1:-1] strips that off
    return str(pyiid)[1:-1]

</t>
<t tx="ekr.20051104081502.469">def OnIdle(self, evt):	
    &lt;&lt; Check for Transfers From Outlook &gt;&gt;
    &lt;&lt; Check if Edited File has Changed &gt;&gt;

</t>
<t tx="ekr.20051104081502.471">if OUTLOOK:
    input,output,exc = select.select([self.sock],[],[],0)
    if input:
        client,addr = self.sock.accept() # Get a connection
        rec = client.recv(8192)
        d = pickle.loads(rec)

        class Item: pass

        item = Item()
        item.id = self.GetUID()
        item.priority = 1
        item.createdate = mx.DateTime.now()
        item.duedate = item.finisheddate = None

        #outlook strings are unicode; ascii encode makes sure no chars above 127
        name = d['Subject'].encode('ascii','replace') 
        item.name = name[:150]

        owner = d['SenderName'].encode('ascii','replace') #encode takes unicode to standard strings
        owner = owner[:25]
        item.owners = [owner]

        note = d['CreationTime'] + '\n' + d['Body'].encode('ascii','replace')
        #foldername = d['Parent.Name']

        #location, rdbms, table = MAIL_LIST_PATH.split(':')
        #host = '%s:%s'%(location,rdbms)
        host, table = re.split('(.*?:.*?):', MAIL_LIST_PATH)[1:3] #really just for fun

        cursor = self.Cursors[host]

        cursor.execute("INSERT INTO "+table+" (priority,name,createdate,finisheddate,duedate,owner1,note,id) VALUES (%s,%s,%s,%s,%s,%s,%s,%s)",
            (item.priority, name, item.createdate, item.finisheddate, item.duedate, owner, note, item.id))

        item.timestamp = self.TimeStamper(host, cursor, table, item.id)

        #check to see if table is open
        for L,Properties in enumerate(self.PropertyDicts):
            if Properties['table'] == table and Properties['host'] == host:
                break
        else:
            g.pr("Table not open but wrote to database anyway") #Needs to be a dialog box
            return

        # could have started to edit something and never finished it
        if self.modified:
            self.OnUpdate()

        if self.L != L:
            self.nb.SetSelection(L) # Note that this does not call OnPageChange if the page doesn't change

        LCtrl = self.ListCtrls[L]

        if self.curIdx != -1:
            LCtrl.SetItemState(self.curIdx, 0, wxLIST_STATE_SELECTED)

        self.ItemLists[L].insert(0,item)    
        LCtrl.InsertImageStringItem(0,"1", LCtrl.idx1)
        LCtrl.SetStringItem(0,self.attr2col_num['name'],name)
        LCtrl.SetStringItem(0, self.attr2col_num['owners'], owner)

        if Properties['LCdate'] == 'timestamp':
            LCtrl.SetStringItem(0, self.attr2col_num['date'], item.timestamp.Format("%m/%d %H:%M:%S"))
        elif Properties['LCdate'] == 'createdate':
            LCtrl.SetStringItem(0, self.attr2col_num['date'], item.createdate.Format('%m/%d/%y'))

        LCtrl.SetItemState(0, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED)
        self.curIdx = 0 

</t>
<t tx="ekr.20051104081502.473">for ed in self.editor:
    path = ed['path']
    t = os.path.getmtime(path)
    if t != ed['time']:
        f = file(path,'r')
        note = f.read()
        f.close()
        ed['time'] = t

        host = ed['host']
        cursor = self.Cursors[host]
        table = ed['table']
        id = ed['id']
        cursor.execute("UPDATE "+table+" SET note = %s WHERE id = %s", (note,id)) 
        # see @rst documentation note
        ts = self.TimeStamper(host, cursor, table, id)

        idx = self.curIdx
        L = self.L
        if idx != -1:
            item = self.ItemLists[L][idx]
            if item.id == id:
                self.note.SetValue(note)
                item.timestamp = ts

                if self.PropertyDicts[L]['LCdate'] == 'timestamp':
                    self.ListCtrls[L].SetStringItem(idx, self.attr2col_num['date'], item.timestamp.Format("%m/%d %H:%M:%S"))

                if 'note' in self.modified: #if necessary only if somehow note text didn't change
                    del self.modified['note']

</t>
<t tx="ekr.20051104081502.475">class ListCtrl(wxListCtrl, wxListCtrlAutoWidthMixin):
    @others
</t>
<t tx="ekr.20051104081502.476">def __init__(self, parent, ID, pos=wxDefaultPosition, size=wxDefaultSize, style=0):
    wxListCtrl.__init__(self, parent, ID, pos, size, style)
    wxListCtrlAutoWidthMixin.__init__(self)

    self.il = wxImageList(16,16)

    sm_up = self.il.Add(wxBitmap('bitmaps\\up_arrow.bmp')) #(images.getSmallUpArrowBitmap())
    sm_dn = self.il.Add(wxBitmap('bitmaps\\down_arrow.bmp'))
    self.arrows = (sm_up,sm_dn)

    self.idx1 = self.il.Add(wxBitmap('bitmaps\\box.bmp'))
    self.idx0 = self.il.Add(wxBitmap('bitmaps\\filledwhitebox.bmp'))    

    self.SetImageList(self.il, wxIMAGE_LIST_SMALL)

    EVT_LIST_COL_BEGIN_DRAG(self, self.GetId(), self.OnColBeginDrag)    

    self.SetUpColumns()

</t>
<t tx="ekr.20051104081502.477">def SetUpColumns(self):
    #Need to to construct column heads for columns with sorting by hand to get sorting images on columns
    info = wxListItem()
    info.m_mask = wxLIST_MASK_TEXT | wxLIST_MASK_IMAGE | wxLIST_MASK_FORMAT
    info.m_image = -1

    #Oth column is priority which is sortable
    info.m_format = wxLIST_FORMAT_LEFT
    info.m_text = "P"
    self.InsertColumnInfo(0, info)
    self.SetColumnWidth(0, 35)

    self.InsertColumn(1, "Name")
    self.SetColumnWidth(1, 590)

    self.InsertColumn(2, "Owner")
    self.SetColumnWidth(2, 100)

    #3th column is create ate and same as with priority - needs to constructed by hand
    info.m_format = wxLIST_FORMAT_LEFT
    info.m_text = "Due Date"
    self.InsertColumnInfo(3, info)
    self.SetColumnWidth(3, 75)                

</t>
<t tx="ekr.20051104081502.478">def OnColBeginDrag(self, evt):
    #if inplace editor then change its dimensions
    if evt.GetColumn() == 0:
        evt.Veto()
</t>
<t tx="ekr.20051104081502.479">class MyApp(wxApp):
    @others
</t>
<t tx="ekr.20051104081502.480">def OnInit(self):
    global OFFLINE_ONLY, CANCEL
    wxInitAllImageHandlers()

    if STARTUP_DIALOG:
        startup = StartupDialog(None, 'List Manager')
        val = startup.ShowModal()
        startup.Destroy()
        if val == wxID_YES:
            OFFLINE_ONLY = True
        elif val == wxID_NO:
            OFFLINE_ONLY = False
        elif val == wxID_CANCEL:
            CANCEL = True
            return True

    if OFFLINE_ONLY is False:
        server = REMOTE_HOST.split(':')[0]
        try:
            socket.gethostbyname(server)
        except:
            dlg = wxMessageDialog(None, "Cannot connect to remote server! Only offline access is possible.", "ListManager", style=wxOK|wxICON_EXCLAMATION|wxSTAY_ON_TOP)
            dlg.ShowModal()
            dlg.Destroy()
            OFFLINE_ONLY = True

    frame = ListManager(None, -1, "List Manager", size = (X,Y))
    frame.Show(True)
    self.SetTopWindow(frame)
    CANCEL = False
    return True


</t>
<t tx="ekr.20051104081502.481">class Logger:
    def __init__(self):
        self.dlg = LoggerDialog(None, "", "Alerts and Exceptions", dir=DIRECTORY)
    def write(self, error_msg):
        if not self.dlg.IsShown():
            self.dlg.text.AppendText("\n%s\n"%time.asctime())
            self.dlg.Show(True)

        self.dlg.text.AppendText(error_msg)

</t>
<t tx="ekr.20051104081502.482">def run():
    app = MyApp(0)
    if not CANCEL:
        sys.stderr = sys.stdout = Logger()
        app.MainLoop()

if __name__ == '__main__':
    run()
</t>
<t tx="ekr.20051104081502.483">@ @rst-options
code_mode = True
@c


@language python
from wxPython.wx import *
# the following two are needed for the calendar
from wxPython.calendar import *
from wxPython.utils import *
import os
@others
</t>
<t tx="ekr.20051104081502.484">class TicklerDialog(wxDialog):
    @others
</t>
<t tx="ekr.20051104081502.485">def __init__(self, parent, msg, caption, pos = wxDefaultPosition, size = wxDefaultSize):
    wxDialog.__init__(self, parent, -1, caption, pos, size, style=wxSTAY_ON_TOP | wxTHICK_FRAME | wxCAPTION)

    TC = wxTextCtrl(self, -1, msg, wxDefaultPosition,
                    (450,250),
                    wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH2)

    sizer = wxBoxSizer(wxVERTICAL)
    box = wxBoxSizer(wxHORIZONTAL)        

    sizer.Add(TC, 1, wxALIGN_CENTRE|wxALL, 5)
    line = wxStaticLine(self, -1, size = (20,-1), style = wxLI_HORIZONTAL)

    sizer.Add(line, 0, wxGROW|wxALIGN_CENTER_VERTICAL|wxTOP, 5)
    btn = wxButton(self, wxID_OK, "GO TO ITEM")
    box.Add(btn, 0, wxALIGN_CENTRE|wxALL, 5)
    btn.SetDefault()

    btn = wxButton(self, wxID_FORWARD, "SHOW NEXT")
    box.Add(btn, 0, wxALIGN_CENTRE|wxALL, 5)

    btn = wxButton(self, wxID_APPLY, "MAIL")
    box.Add(btn, 0, wxALIGN_CENTRE|wxALL, 5)        

    btn = wxButton(self, wxID_CANCEL, "CANCEL")
    box.Add(btn, 0, wxALIGN_CENTRE|wxALL, 5)

    sizer.AddSizer(box, 0, wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5)
    self.SetSizer(sizer)
    self.SetAutoLayout(True)
    sizer.Fit(self)

    EVT_LEFT_DOWN(TC, self.OnLeftDown)
    EVT_BUTTON(self, wxID_FORWARD, self.OnForward)
    EVT_BUTTON(self, wxID_APPLY, self.OnMail)

    TC.SetCursor(wxStockCursor(wxCURSOR_ARROW))        

    self.TC = TC
</t>
<t tx="ekr.20051104081502.486">def OnLeftDown(self, evt):
    self.EndModal(wxID_OK)
</t>
<t tx="ekr.20051104081502.487">def OnForward(self, evt):
    self.EndModal(wxID_FORWARD)
</t>
<t tx="ekr.20051104081502.488">def OnMail(self, evt):
    self.EndModal(wxID_APPLY)        
</t>
<t tx="ekr.20051104081502.489">class StartupDialog(wxDialog):
    @others
</t>
<t tx="ekr.20051104081502.490">def __init__(self, parent, caption, pos=wxDefaultPosition, size=(300,115)):
    wxDialog.__init__(self, parent, -1, caption, pos, size, style=wxSTAY_ON_TOP|wxCAPTION)

    msg = "You can connect to the server using the network,\nor work offline, or cancel this logon."

    image = wxStaticBitmap(self, -1, wxBitmap('bitmaps\\wxpdemo.bmp'), (-1,-1), size=(32,32)) #sizer determines position
    text = wxStaticText(self, -1, msg, (-1,-1), size=(250,32)) #sizer determines position

    rect = wxBoxSizer(wxHORIZONTAL)
    rect.Add(image, 0, wxALIGN_LEFT|wxALL, 4)
    rect.Add(text, 1, wxALIGN_CENTER|wxTOP, 7)
    sizer = wxBoxSizer(wxVERTICAL)


    box = wxBoxSizer(wxHORIZONTAL)
    btn = wxButton(self, wxID_NO, 'Connect')
    box.Add(btn, 0, wxALL, 10)
    btn.SetDefault()

    btn = wxButton(self, wxID_YES, 'Work Offline')
    box.Add(btn, 0, wxALL, 10)

    btn = wxButton(self, wxID_CANCEL, 'Cancel')
    box.Add(btn, 0, wxALL, 10)

    sizer.AddSizer(rect)
    sizer.AddSizer(box)

    self.SetSizer(sizer)

    EVT_BUTTON(self, wxID_NO, self.OnSelection)
    EVT_BUTTON(self, wxID_YES, self.OnSelection)
    EVT_BUTTON(self, wxID_CANCEL, self.OnSelection)
</t>
<t tx="ekr.20051104081502.491">def OnSelection(self,evt):
    val = evt.GetId()
    self.EndModal(val)
</t>
<t tx="ekr.20051104081502.492">class ModifierDialog(wxDialog):
    @others
</t>
<t tx="ekr.20051104081502.493">def __init__(self, parent, title,
             pos=wxDefaultPosition,
             size=wxDefaultSize,
             style=wxCAPTION,
             modifierlist=None,
             curselections = ''):
    wxDialog.__init__(self, parent, -1, title, pos, size, style)

    sizer1 = wxBoxSizer(wxVERTICAL)
    sizer2 = wxBoxSizer(wxHORIZONTAL)

    tc = wxTextCtrl(self, -1, "", size = (150,-1))
    sizer1.Add(tc, 0, wxALIGN_CENTRE|wxALL, 5)
    self.tc = tc

    if not modifierlist:
        modifierlist = []
    lb = wxListBox(self, -1,  wxDefaultPosition, (150,300), #wxPoint(90, 80)
                    modifierlist, wxLB_MULTIPLE|wxLB_SORT)

    sizer1.Add(lb, 1, wxALIGN_CENTRE|wxALL, 5)

    line = wxStaticLine(self, -1, size = (20,-1), style = wxLI_HORIZONTAL)
    sizer1.Add(line, 0, wxGROW|wxALIGN_CENTER_VERTICAL|wxTOP, 5)


    btn = wxButton(self, wxID_OK, "OK")
    sizer2.Add(btn, 0, wxALIGN_CENTRE|wxALL, 5)
    btn.SetDefault()

    btn = wxButton(self, wxID_CANCEL, "CANCEL")
    sizer2.Add(btn, 0, wxALIGN_CENTRE|wxALL, 5)

    sizer1.AddSizer(sizer2, 0, wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5)
    self.SetSizer(sizer1)
    self.SetAutoLayout(True)
    sizer1.Fit(self)

    for sel in curselections:
        index = lb.FindString(sel)
        if index !=-1:
            lb.SetSelection(index)

    self.lb = lb

    EVT_BUTTON(self, wxID_CANCEL, self.ClearSelections)


</t>
<t tx="ekr.20051104081502.494">def GetUserInput(self):
    idx_list = self.lb.GetSelections()
    mod_list =[]
    for i in idx_list:
        mod_list.append(self.lb.GetString(i))
        self.lb.Deselect(i) #071203

    new_list = []
    manual_string = self.tc.GetValue() #text entry box

    if manual_string:
        manual_list = [x.strip() for x in manual_string.split(';')]
        for name in manual_list:
            clean_name = ", ".join([x.strip().title() for x in name.split(',')])
            if clean_name not in mod_list:
                mod_list.append(clean_name)
                new_list.append(clean_name)


    return (mod_list, new_list)
</t>
<t tx="ekr.20051104081502.495">def SelectCurrent(self, cur_sel):
    for sel in cur_sel:
        index = self.lb.FindString(sel)
        if index !=-1:
            self.lb.SetSelection(index)


</t>
<t tx="ekr.20051104081502.496">def ClearSelections(self, evt=None):
    idx_list = self.lb.GetSelections() #note you can't just use the indexes of the SelectCurrent since they may have clicked before cancelling
    for i in idx_list:
        self.lb.Deselect(i)

    evt.Skip()
</t>
<t tx="ekr.20051104081502.497">class MailDialog(wxDialog):
    @others
</t>
<t tx="ekr.20051104081502.498">def __init__(self, parent, title,
             pos=wxDefaultPosition,
             size=wxDefaultSize,
             style=wxSTAY_ON_TOP| wxTHICK_FRAME|wxCAPTION|wxSYSTEM_MENU,
             recipients='',
             subject = '',
             body = ''):

    wxDialog.__init__(self, parent, -1, title, pos, size, style)

    sizer = wxBoxSizer(wxVERTICAL)
    box = wxBoxSizer(wxHORIZONTAL)

    recipients = "; ".join(recipients)
    label = wxStaticText(self, -1, "To:",wxDefaultPosition, size=(40,-1), style=wxALIGN_LEFT)
    RTC = wxTextCtrl(self, -1, recipients, size = (480,-1))
    box.Add(label)
    box.Add(RTC)

    #sizer.Add(10,10,0)      

    sizer.AddSizer(box)        

    box = wxBoxSizer(wxHORIZONTAL)       
    label = wxStaticText(self, -1, "Subject:",wxDefaultPosition, size=(40,-1),style=wxALIGN_LEFT)
    STC = wxTextCtrl(self, -1, subject, size = (480,-1)) 
    box.Add(label)
    box.Add(STC)

    sizer.AddSizer(box)
    sizer.Add(1, 5, 0)

    BTC = wxTextCtrl(self, -1, body, wxDefaultPosition, size = (500,400), style=wxTE_MULTILINE|wxTE_RICH2)

    sizer.Add(BTC)

    box = wxBoxSizer(wxHORIZONTAL)
    btn = wxButton(self, wxID_OK, "SEND MAIL")
    box.Add(btn, 0, wxALIGN_CENTRE|wxALL, 5)
    btn.SetDefault()

    btn = wxButton(self, wxID_CANCEL, "CANCEL")
    box.Add(btn, 0, wxALIGN_CENTRE|wxALL, 5)

    sizer.AddSizer(box)
    self.SetSizer(sizer)
    self.SetAutoLayout(True)
    sizer.Fit(self)

    self.RTC = RTC
    self.STC = STC
    self.BTC = BTC

</t>
<t tx="ekr.20051104081502.499">class CalendarDialog(wxDialog):
    @others
</t>
<t tx="ekr.20051104081502.500">def __init__(self, parent, title,
             pos=wxDefaultPosition,
             size=wxDefaultSize,
             style=wxCAPTION,
             date=0):

    wxDialog.__init__(self, parent, -1, title, pos, size, style)

    if not date:
        date = wxDateTime_Now()

    cal = wxCalendarCtrl(self, -1, date, #pos = (25,50),
                         style = wxCAL_SHOW_HOLIDAYS | wxCAL_SUNDAY_FIRST)

    EVT_CALENDAR(self, cal.GetId(), self.OnCalSelected)

    #EVT_CLOSE(self, self.OnCloseWindow)          

    self.cal = cal

    # Set up control to display a set of holidays:
    EVT_CALENDAR_MONTH(self, cal.GetId(), self.OnChangeMonth)

    self.holidays = [(1,1), (10,31), (12,25) ]    # (these don't move around)

    self.OnChangeMonth()        

#-------------------------------------------------------------------------        
    sizer1 = wxBoxSizer(wxVERTICAL)
    sizer2 = wxBoxSizer(wxHORIZONTAL)

    sizer1.Add(cal, 0, wxALIGN_CENTRE|wxALL, 5)

    line = wxStaticLine(self, -1, size = (20,-1), style = wxLI_HORIZONTAL)
    sizer1.Add(line, 0, wxGROW|wxALIGN_CENTER_VERTICAL|wxRIGHT|wxTOP, 5)


    btn = wxButton(self, wxID_OK, "OK")
    btn.SetDefault()
    sizer2.Add(btn, 0, wxALIGN_CENTRE|wxALL, 5)

    btn = wxButton(self, wxID_CANCEL, "CANCEL")
    #btn.SetDefault()
    sizer2.Add(btn, 0, wxALIGN_CENTRE|wxALL, 5)

    sizer1.AddSizer(sizer2, 0, wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5)
    self.SetSizer(sizer1)
    self.SetAutoLayout(True)
    sizer1.Fit(self)
</t>
<t tx="ekr.20051104081502.501">def OnCalSelected(self, evt):
    self.result = evt.GetDate()
    self.EndModal(wxID_OK)
</t>
<t tx="ekr.20051104081502.502">def OnChangeMonth(self, evt=None):
    cur_month = self.cal.GetDate().GetMonth() + 1   # convert wxDateTime 0-11 =&gt; 1-12
    for month, day in self.holidays:
        if month == cur_month:
            self.cal.SetHoliday(day)        
</t>
<t tx="ekr.20051104081502.503">def OnCloseWindow(self, event):
    #self.cal.Destroy
    #self.Destroy()
    g.pr("I got to close window")
</t>
<t tx="ekr.20051104081502.504">def GetDate(self):
    return self.result
</t>
<t tx="ekr.20051104081502.505">class FindDialog(wxDialog):
    @others
</t>
<t tx="ekr.20051104081502.506">def __init__(self, parent, caption, msg, pos=wxDefaultPosition, size=(300,120)):
    wxDialog.__init__(self, parent, -1, caption, pos, size, style=wxSTAY_ON_TOP|wxCAPTION)    

    self.FindText = wxTextCtrl(self, -1, msg, wxDefaultPosition,(200,24))

    box_a = wxBoxSizer(wxHORIZONTAL)
    box_a.Add(self.FindText, 1, wxALIGN_CENTER|wxALL, 5)

    box_b = wxBoxSizer(wxVERTICAL)        
    btn = wxButton(self, wxID_OK, "OK")
    box_b.Add(btn, 0, wxALIGN_CENTER|wxALL,5)
    btn.SetDefault()               

    btn = wxButton(self, wxID_CANCEL, "CANCEL")
    box_b.Add(btn, 0, wxALIGN_CENTER)

    box_a.AddSizer(box_b)

    self.MatchCase = wxCheckBox(self, -1, "Match Case")
    self.MatchWhole = wxCheckBox(self, -1, "Match Whole Word")
    box_c = wxBoxSizer(wxVERTICAL)
    box_c.Add(self.MatchCase, 0, wxLEFT|wxBOTTOM, 5)
    box_c.Add(self.MatchWhole, 0, wxLEFT, 5)

    self.SearchNotes = wxCheckBox(self, -1, "Search Notes")
    self.SearchFinished = wxCheckBox(self, -1, "Search Finished")
    box_d = wxBoxSizer(wxVERTICAL)
    box_d.Add(self.SearchNotes, 0, wxLEFT|wxBOTTOM, 5)
    box_d.Add(self.SearchFinished, 0, wxLEFT, 5)

    box_e = wxBoxSizer(wxHORIZONTAL)
    box_e.AddSizer(box_c)
    box_e.AddSizer(box_d)

    sizer = wxBoxSizer(wxVERTICAL)
    sizer.AddSizer(box_a)
    sizer.AddSizer(box_e)

    self.SetSizer(sizer)

    EVT_BUTTON(self, wxID_OK, parent.FindString)


</t>
<t tx="ekr.20051104081502.507">class EvalDialog(wxDialog):
    @others
</t>
<t tx="ekr.20051104081502.508">def __init__(self, parent, caption, msg, pos=wxDefaultPosition, size=(300,80)):
    wxDialog.__init__(self, parent, -1, caption, pos, size, style=wxSTAY_ON_TOP|wxCAPTION)    

    EvalText = wxTextCtrl(self, -1, msg, wxDefaultPosition,(200,24))


    box_a = wxBoxSizer(wxHORIZONTAL)
    box_a.Add(EvalText, 1, wxALIGN_CENTER|wxALL, 5)

    box_b = wxBoxSizer(wxVERTICAL)        
    btn = wxButton(self, wxID_OK, "OK")
    box_b.Add(btn, 0, wxALIGN_CENTER|wxALL,5)
    btn.SetDefault()               

    btn = wxButton(self, wxID_CANCEL, "CANCEL")
    box_b.Add(btn, 0, wxALIGN_CENTER)

    box_a.AddSizer(box_b)

    self.SetSizer(box_a)

    self.EvalText = EvalText
    self.parent = parent

    #EVT_BUTTON(self, wxID_OK, self.PostOKEvent)
    EVT_BUTTON(self, wxID_OK, parent.OnEvaluate)



</t>
<t tx="ekr.20051104081502.509">def PostOKEvent(self, evt=None):
    wxPostEvent(self.parent, evt)
</t>
<t tx="ekr.20051104081502.510">class LoggerDialog(wxDialog):
    @others
</t>
<t tx="ekr.20051104081502.511">def __init__(self, parent, msg, caption, pos=(-1,-1), size=(500,300), dir=None):
    wxDialog.__init__(self, parent, -1, caption, pos, size)
    #if pos == (-1,-1):
        #self.CenterOnScreen(wxBOTH)

    if dir:
        self.dir = dir
    else:
        self.dir = os.getcwd()

    text = wxTextCtrl(self, -1, msg, (-1,-1), (450,250), wxTE_MULTILINE | wxTE_READONLY)

    sizer = wxBoxSizer(wxVERTICAL)
    box = wxBoxSizer(wxHORIZONTAL)        

    sizer.Add(text, 1, wxALIGN_CENTRE|wxALL, 5)

    btn = wxButton(self, wxID_OK, "Close")
    box.Add(btn, 0, wxALIGN_CENTRE|wxALL, 5)
    btn.SetDefault()

    ID_SAVE = wxNewId()

    btn = wxButton(self, ID_SAVE, "Save to File")
    box.Add(btn, 0, wxALIGN_CENTRE|wxALL, 5)        

    sizer.AddSizer(box, 0, wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5)
    self.SetSizer(sizer)
    self.SetAutoLayout(True)
    sizer.Fit(self)

    self.text = text

    EVT_BUTTON(self, ID_SAVE, self.OnSave)
</t>
<t tx="ekr.20051104081502.512">def OnSave(self, evt):

    path = os.path.join(self.dir, 'logfile.txt')

    f = file(path,'a')
    f.write(self.text.GetValue())
    f.close()

    dlg = wxMessageDialog(self,"Appended text to logfile.text", "Notice", wxICON_INFORMATION|wxOK)
    dlg.ShowModal()
    dlg.Destroy()

    self.text.Clear()
</t>
<t tx="ekr.20051104081502.513">class FinishedDialog(wxDialog):
    @others
</t>
<t tx="ekr.20051104081502.514">def __init__(self, parent, title,
            pos=wxDefaultPosition,
            size=wxDefaultSize,
            style=wxCAPTION,
            days=0,
            spin_label="",
            check_label=""):

    wxDialog.__init__(self, parent, -1, title, pos, size)
    self.Centre()

    self.check = wxCheckBox(self, -1, check_label)

    if days == -1:
        self.check.SetValue(True)
        days = 0

    panel = wxPanel(self, -1, (-1,-1),(225,75))
    wxStaticText(panel, -1, spin_label,(15, 15))
    self.text = wxTextCtrl(panel, -1, str(days), (30, 50), (30, -1))
    h = self.text.GetSize().height
    self.spin = wxSpinButton(panel, -1, (56, 50), (h, h), wxSP_VERTICAL)
    wxStaticText(panel, -1, 'days',(76, 53))
    self.spin.SetRange(0, 14)
    self.spin.SetValue(days)

    H_sizer = wxBoxSizer(wxHORIZONTAL)

    line = wxStaticLine(self, -1, size = (20,-1), style = wxLI_HORIZONTAL)

    btn = wxButton(self, wxID_OK, "OK")
    H_sizer.Add(btn, 0, wxALIGN_CENTRE|wxALL, 5)
    btn.SetDefault()

    btn = wxButton(self, wxID_CANCEL, "CANCEL")
    H_sizer.Add(btn, 0, wxALIGN_CENTRE|wxALL, 5)

    V_sizer = wxBoxSizer(wxVERTICAL)
    V_sizer.Add(panel,1,wxALIGN_CENTER|wxEXPAND)
    V_sizer.Add(-1,5)
    V_sizer.Add(self.check,0,wxALIGN_LEFT|wxALL,5)
    V_sizer.Add(line,0, wxGROW|wxALIGN_CENTER_VERTICAL|wxTOP, 5)
    V_sizer.AddSizer(H_sizer, 0, wxGROW|wxALIGN_CENTER_VERTICAL|wxALL, 5)

    self.SetSizer(V_sizer)
    self.SetAutoLayout(True)
    V_sizer.Fit(self)

    EVT_SPIN(self, self.spin.GetId(), self.OnSpin)
    EVT_CHECKBOX(self, self.check.GetId(), self.OnCheck)

    if self.check.GetValue():
        self.spin.Enable(False)
        self.text.Enable(False)

    self.Layout() #doesn't appear necessary


</t>
<t tx="ekr.20051104081502.515">def OnSpin(self, evt):
    self.text.SetValue(str(evt.GetPosition()))
</t>
<t tx="ekr.20051104081502.516">def OnCheck(self, evt=None):
    if self.check.GetValue():
        self.spin.Enable(False)
        self.text.Enable(False)
    else:
        self.spin.Enable(True)
        self.text.Enable(True)
</t>
<t tx="ekr.20051104081502.517">class TreeDialog(wxDialog):
    @others
</t>
<t tx="ekr.20051104081502.518">def __init__(self, parent, caption, pos=wxDefaultPosition, size=(300,400), tree={}):
    wxDialog.__init__(self, parent, -1, caption, pos, size, style=wxSTAY_ON_TOP|wxCAPTION)

    TreeCtrl = wxTreeCtrl(self, -1, wxDefaultPosition, (300,400), wxTR_HAS_BUTTONS)    #|wxTR_HIDE_ROOT)#wxDefaultSize,

    sizer = wxBoxSizer(wxVERTICAL)
    sizer.Add(TreeCtrl, 1, wxALIGN_CENTER|wxALL, 5)

    box = wxBoxSizer(wxHORIZONTAL)
    btn = wxButton(self, wxID_OK, "OK")
    box.Add(btn, 0, wxALIGN_CENTRE|wxALL, 5)
    btn.SetDefault()

    btn = wxButton(self, wxID_CANCEL, "CANCEL")
    box.Add(btn, 0, wxALIGN_CENTRE|wxALL, 5)

    sizer.AddSizer(box)
    self.SetAutoLayout(1)
    self.SetSizer(sizer)

    il = wxImageList(16,16)

    fldridx = il.Add(wxBitmap('bitmaps\\folder.bmp'))
    fldropenidx = il.Add(wxBitmap('bitmaps\\folder_open.bmp'))
    listidx =  il.Add(wxBitmap('bitmaps\\list.bmp'))

    TreeCtrl.SetImageList(il)

    root = TreeCtrl.AddRoot("List Manager")
    TreeCtrl.SetItemImage(root, fldridx, wxTreeItemIcon_Normal)
    TreeCtrl.SetItemImage(root, fldropenidx, wxTreeItemIcon_Expanded)

    for host in tree:
        child = TreeCtrl.AppendItem(root, host)
        TreeCtrl.SetItemImage(child, fldridx, wxTreeItemIcon_Normal)
        TreeCtrl.SetItemImage(child, fldropenidx, wxTreeItemIcon_Expanded)
        for listname in tree[host]:
            last = TreeCtrl.AppendItem(child, listname)
            TreeCtrl.SetItemImage(last, listidx, wxTreeItemIcon_Normal)
            TreeCtrl.SetItemImage(last, listidx, wxTreeItemIcon_Selected)

    TreeCtrl.Expand(root)

    self.TreeCtrl= TreeCtrl
    self.il = il #? prevents GC

    EVT_LEFT_DCLICK(TreeCtrl, self.OnLeftDClick)
</t>
<t tx="ekr.20051104081502.519">def OnLeftDClick(self, event=None):
    self.EndModal(wxID_OK)
</t>
<t tx="ekr.20051104081502.520">@ @rst-options
code_mode = True
@c

@language python
&lt;&lt; outlookAddin declarations &gt;&gt;
@others

if __name__ == '__main__':
    import win32com.server.register
    win32com.server.register.UseCommandLine(OutlookAddin)
    if "--unregister" in sys.argv:
        UnregisterAddin(OutlookAddin)
    else:
        RegisterAddin(OutlookAddin)
</t>
<t tx="ekr.20051104081502.521"># This is mainly stolen from Mark Hammond's demo plugin for win32com.client
# A demo plugin for Microsoft Outlook (NOT Outlook Express)

from win32com import universal
from win32com.server.exception import COMException
from win32com.client import gencache, DispatchWithEvents
from win32com.client import Dispatch
import winerror
import pythoncom
from win32com.client import constants
import win32ui ##
import sys
from socket import *
import pickle

# Support for COM objects we use.
#sz comment gencache.EnsureModule makes sure you are using makepy if the makepy-derived
#file doesn't already exist
#but as long as you did run makepy then you should just be alble to do a normal dispatch

mod = gencache.EnsureModule('{00062FFF-0000-0000-C000-000000000046}', 0, 9, 0, bForDemand=True) # Outlook 9
gencache.EnsureModule('{2DF8D04C-5BFA-101B-BDE5-00AA0044DE52}', 0, 2, 1, bForDemand=True) # Office 9

# The TLB defining the interfaces we implement
universal.RegisterInterfaces('{AC0714F2-3D04-11D1-AE7D-00A0C90F26F4}', 0, 1, 0, ["_IDTExtensibility2"])

Target = 'mail_transfer'


</t>
<t tx="ekr.20051104081502.522">class ButtonEvent:
    @others
</t>
<t tx="ekr.20051104081502.523">def OnClick(self, button, cancel):
    #activeExplorer and MailTransferFolder are globals defined in OnConnection
    sel = activeExplorer.Selection

    for i in range(1,sel.Count+1):
        item = sel.Item(i)
        item.Move(MailTransferFolder)

    return cancel

</t>
<t tx="ekr.20051104081502.524">class FolderEvent:
    @others
</t>
<t tx="ekr.20051104081502.525">def OnItemAdd(self, item):
    try:
        s = socket(AF_INET,SOCK_STREAM)
        s.connect(('localhost', 8888))
        d = {}
        d['Parent.Name'] = item.Parent.Name
        d['SenderName'] = item.SenderName
        d['Subject'] = item.Subject
        d['Body'] = item.Body[:5000]
        d['CreationTime'] = item.CreationTime.Format()
        str = pickle.dumps(d)
        s.send(str) # ?Receive no more than 1024 bytes
        s.close()
        win32ui.MessageBox("Sent %s to ListManager"%item.Subject)
    except:
        pass
</t>
<t tx="ekr.20051104081502.526">class OutlookAddin:
    &lt;&lt; class OutlookAddin declarations &gt;&gt;
    @others
</t>
<t tx="ekr.20051104081502.527">_com_interfaces_ = ['_IDTExtensibility2']
_public_methods_ = []
_reg_clsctx_ = pythoncom.CLSCTX_INPROC_SERVER
_reg_clsid_ = "{0F47D9F3-598B-4d24-B7E3-92AC15ED27E2}"
_reg_progid_ = "Python.Test.OutlookAddin"
_reg_policy_spec_ = "win32com.server.policy.EventHandlerPolicy"
</t>
<t tx="ekr.20051104081502.528">def OnConnection(self, application, connectMode, addin, custom):
    global MailTransferFolder
    global activeExplorer
    # ActiveExplorer may be none when started without a UI (eg, WinCE synchronisation)
    activeExplorer = application.ActiveExplorer()
    if activeExplorer:
        bars = activeExplorer.CommandBars
        toolbar = bars.Item("Standard")
        item = toolbar.Controls.Add(Type=constants.msoControlButton, Temporary=True)
        item = self.toolbarButton = DispatchWithEvents(item, ButtonEvent) #? just need this to be an ivar
        item.Caption="List Manager"
        item.TooltipText = "Click to move"
        item.Enabled = True
        #self.toolbarButton = DispatchWithEvents(item, ButtonEvent) #need something that won't get GC'd. Note Dispatch returns item

    ns = application.GetNamespace("MAPI")
    Folders = ns.Folders

    for i in range(1,len(Folders)+1):
        if Folders[i].Name.find("Mailbox") != -1:
            folders = Folders[i].Folders
            break
    else:
        win32ui.MessageBox("Can't find Mailbox!")
        return	

    for i in range(1,len(folders)+1):
        if folders[i].Name == Target:
            MailTransferFolder = folders[i]
            self.targetMailbox = DispatchWithEvents(folders[i].Items, FolderEvent) #? just need this to be an ivar
            win32ui.MessageBox("Enabled: %s\nOutlookAddin3"%Target)
            break
    else:
        win32ui.MessageBox("Could not find mail folder: %s\nOutlookAddin3"%Target)
</t>
<t tx="ekr.20051104081502.529">def OnDisconnection(self, mode, custom):
    g.pr("OnDisconnection")
</t>
<t tx="ekr.20051104081502.530">def OnAddInsUpdate(self, custom):
    g.pr("OnAddInsUpdate", custom)
</t>
<t tx="ekr.20051104081502.531">def OnStartupComplete(self, custom):
    g.pr("OnStartupComplete", custom)
</t>
<t tx="ekr.20051104081502.532">def OnBeginShutdown(self, custom):
    g.pr("OnBeginShutdown", custom)
</t>
<t tx="ekr.20051104081502.533">def RegisterAddin(klass):
    import _winreg
    key = _winreg.CreateKey(_winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Office\\Outlook\\Addins")
    subkey = _winreg.CreateKey(key, klass._reg_progid_)
    _winreg.SetValueEx(subkey, "CommandLineSafe", 0, _winreg.REG_DWORD, 0)
    _winreg.SetValueEx(subkey, "LoadBehavior", 0, _winreg.REG_DWORD, 3)
    _winreg.SetValueEx(subkey, "Description", 0, _winreg.REG_SZ, klass._reg_progid_)
    _winreg.SetValueEx(subkey, "FriendlyName", 0, _winreg.REG_SZ, klass._reg_progid_)
</t>
<t tx="ekr.20051104081502.534">def UnregisterAddin(klass):
    import _winreg
    try:
        _winreg.DeleteKey(_winreg.HKEY_CURRENT_USER, "Software\\Microsoft\\Office\\Outlook\\Addins\\" + klass._reg_progid_)
    except WindowsError:
        pass
</t>
<t tx="ekr.20051104081502.535">########
Headline
########

@ @rst-options
.. These options have NO EFFECT for rst2 plugin!
code_mode=False
generate_rst=True
http_server_support = False
show_organizer_nodes=True
show_headlines=True
show_leo_directives=True
stylesheet_path=c:\prog\leoCVS\leo\doc
write_intermediate_file = True
verbose=True
@c

This is a test of pdf stuff

.. contents::
</t>
<t tx="ekr.20051104081502.536"></t>
<t tx="ekr.20051104081502.537">child node text
</t>
<t tx="ekr.20051104081502.538">import sys
sys.path.append(r'c:\reportlab_1_20')

debug = True

@others

from reportlab.pdfgen import canvas
c = canvas.Canvas('hello.pdf')
for i in (10,50):
    text(c,'x'*10,i,i)
# pencil(c,text='Note')

key = 'key1'

c.bookmarkPage(key)
c.addOutlineEntry('OutlineEntry',key)


c.showPage()
c.save()
</t>
<t tx="ekr.20051104081502.539">def text(c,text,i=100,j=100):
    c.drawString(i,j,text)
</t>
<t tx="ekr.20051104081502.540">def pencil(canvas, text="No.2"):
    from reportlab.lib.colors import yellow, red, black,white
    from reportlab.lib.units import inch
    u = inch/10.0
    canvas.setStrokeColor(black)
    canvas.setLineWidth(4)
    # draw erasor
    canvas.setFillColor(red)
    canvas.circle(30*u, 5*u, 5*u, stroke=1, fill=1)
    # draw all else but the tip (mainly rectangles with different fills)
    canvas.setFillColor(yellow)
    canvas.rect(10*u,0,20*u,10*u, stroke=1, fill=1)
    canvas.setFillColor(black)
    canvas.rect(23*u,0,8*u,10*u,fill=1)
    canvas.roundRect(14*u, 3.5*u, 8*u, 3*u, 1.5*u, stroke=1, fill=1)
    canvas.setFillColor(white)
    canvas.rect(25*u,u,1.2*u,8*u, fill=1,stroke=0)
    canvas.rect(27.5*u,u,1.2*u,8*u, fill=1, stroke=0)
    canvas.setFont("Times-Roman", 3*u)
    canvas.drawCentredString(18*u, 4*u, text)
    # now draw the tip
    penciltip(canvas,debug=0)
    # draw broken lines across the body.
    canvas.setDash([10,5,16,10],0)
    canvas.line(11*u,2.5*u,22*u,2.5*u)
    canvas.line(22*u,7.5*u,12*u,7.5*u)
</t>
<t tx="ekr.20051104081502.541">def penciltip(canvas, debug=1):
    from reportlab.lib.colors import tan, black, green
    from reportlab.lib.units import inch
    u = inch/10.0
    canvas.setLineWidth(4)
    if debug:
        canvas.scale(2.8,2.8) # make it big
        canvas.setLineWidth(1) # small lines
    canvas.setStrokeColor(black)
    canvas.setFillColor(tan)
    p = canvas.beginPath()
    p.moveTo(10*u,0)
    p.lineTo(0,5*u)
    p.lineTo(10*u,10*u)
    p.curveTo(11.5*u,10*u, 11.5*u,7.5*u, 10*u,7.5*u)
    p.curveTo(12*u,7.5*u, 11*u,2.5*u, 9.7*u,2.5*u)
    p.curveTo(10.5*u,2.5*u, 11*u,0, 10*u,0)
    canvas.drawPath(p, stroke=1, fill=1)
    canvas.setFillColor(black)
    p = canvas.beginPath()
    p.moveTo(0,5*u)
    p.lineTo(4*u,3*u)
    p.lineTo(5*u,4.5*u)
    p.lineTo(3*u,6.5*u)
    canvas.drawPath(p, stroke=1, fill=1)
    if debug:
        canvas.setStrokeColor(green) # put in a frame of reference
        canvas.grid([0,5*u,10*u,15*u], [0,5*u,10*u])
</t>
<t tx="ekr.20051104081502.542"></t>
<t tx="ekr.20051104081502.543">part 1, line 1
part 2, line 2, no newline
</t>
<t tx="ekr.20051104081502.544">part 2, line 1, no newline
</t>
<t tx="ekr.20051104081502.545">part 3, line 1
part 3, line 2, newline
</t>
<t tx="ekr.20051104081502.546"># g.app.config.updateSettings(c)
g.es('test_setting',c.config.getBool('test_setting'))
</t>
<t tx="ekr.20051104081502.547"># This problem has been around forever.
g.pr('-' * 40)
# Yes. We *do* want to warn in c.config.exists.
g.pr('exists',g.app.config.exists(c,'showMinibuffer','bool'))
val = c.config.getBool('showMinibuffer')
g.pr('bool:showMinibuffer',val)
val = c.config.getShortcut('showMinibuffer')
g.pr('shortcut:showMinibuffer',val)
</t>
<t tx="ekr.20051104081502.548">c.frame.log.selectTab('Test')
g.es('Test',color='red',tabName='Test')
</t>
<t tx="ekr.20051104081502.549">c.frame.log.selectTab('Log')
g.es('Test',color='blue')
</t>
<t tx="ekr.20051104081502.551">k = c.keyHandler

def f (event):
    g.es_print('Hello',color='purple')

def f2 (event):
    g.es_print('Hello2',color='purple')

k.registerCommand('print-hello','Alt-Ctrl-Shift-p',f)
k.registerCommand('print-hello2',None,f2)
</t>
<t tx="ekr.20051104081502.99"></t>
<t tx="ekr.20051107115231.25"># getWidth no longer exists.
k = c.keyHandler
h = 'Test headline abc'
p = c.testManager.findNodeAnywhere(h)
assert p,'node not found: %s' % h
c.redraw(p) # To make node visible
c.frame.tree.editLabel(p)
w = c.edit_widget(p)
try:
    assert w
    g.app.gui.set_focus(c,w)
    w2 = g.app.gui.get_focus(c)
    # assert w == w2 or hasattr(w,'widget') and w.widget == w2,'w: %s\nw2: %s' % (w,w2)
    w.setSelectionRange('end','end')
    n = w.getWidth()
    g.app.gui.event_generate(c,'X','Shift+X',w)
    g.app.gui.event_generate(c,'Y','Shift+Y',w)
    g.app.gui.event_generate(c,'Z','Shift+Z',w)
    g.app.gui.event_generate(c,'\n','Return',w)
    w.update()
    assert w, 'fail 2'
   
finally:
    if 1:
        c.setHeadString(p,h) # Essential
        c.redraw(p)
</t>
<t tx="ekr.20060127120604"></t>
<t tx="ekr.20060208195054"># c.commandsDict: keys are emacs command names, values are functions f.
# k.inverseCommandsDict: keys are f.__name__, values are emacs command names.

@others

d1 = c.commandsDict ; d2 = c.k.inverseCommandsDict

if 0:
    vals = d2.values() ; vals.sort()
    vals = [z for z in vals if z.startswith('contract')]
    g.pr('inverseCommandsDict.values()',vals)

keys1 = d1.keys() ; keys1.sort()
vals1 = d1.values()
vals1 = [f.__name__ for f in vals1]
vals1.sort()

keys2 = d2.keys() ; keys2.sort()
vals2 = d2.values(); vals2.sort()

if 0:
    g.pr(keys1,'\n\n')
    g.pr(vals2,'\n\n')
    g.pr(keys2,'\n\n')
    g.pr(vals1)

# g.trace(g.dictToString(c.k.abbreviationsDict))

abbrevDict = c.config.getAbbrevDict()

# Find @button and @command nodes in this file.
@others
buttonKeys = []
for p in c.allNodes_iter():
    h = p.h.strip().lower()
    for kind in ('@button','@command'):
        if h.startswith(kind):
            key1 = mungeKey(h,kind,substitute=False)
            if key1 not in buttonKeys:
                buttonKeys.append(key1)
            key = mungeKey(h,kind,substitute=True)
            if key not in buttonKeys:
                buttonKeys.append(key)

for z in g.app.config.atCommonButtonsList:
    h,junk = z
    key = mungeKey(h,'@button')
    # g.trace(key)
    if key not in buttonKeys:
        buttonKeys.append(key)

# g.pr('buttonKeys',buttonKeys)

for key in keys1:
    if key not in vals2 and key.lower() not in vals2:
        if (
            key.startswith('enter-') and key.endswith('-mode') or
            key.startswith('press-') and key.endswith('-button') or
            key.startswith('delete-') and key.endswith('-button') or
            key.startswith('nav-') and key.endswith('-menu')
        ):
            vals2.append(key)
        elif key in buttonKeys or key.lower() in buttonKeys:
            # List of buttons defined in this file, or in @settings tree.
            vals2.append(key)
        elif key.startswith('open-with-'):
            vals2.append(key)
        elif key in abbrevDict.keys():
            pass # g.trace('abbrev',key)
        else:
            assert False, '%s not in inverseCommandsDict.values()' % key

vals2.sort()
for val in vals2:
    if val not in keys1:
        assert False, '%s not in commandsDict.keys()' % (val)
</t>
<t tx="ekr.20061008162912">assert p.firstChild(), 'no child node'
assert p.firstChild().b.startswith('@ignore'), 'No @ignore in child'
ok = c.fileCommands.write_Leo_file(
    'file-name',outlineOnlyFlag=True,toString=True,toOPML=False)
assert ok, 'error writing file'
count = 0
s = g.app.write_Leo_file_string
for line in g.splitLines(s):
    if line.find('@ignore') != -1:
        count += 1
assert count &gt;=1, "not enough @ignore's in written file: count: %s, lines:\n%s" % (count,s)
</t>
<t tx="ekr.20061008162912.1">@ignore # Test that this node gets written.
</t>
<t tx="ekr.20061101121602.126">c.testManager.runEditCommandTest(p)
</t>
<t tx="ekr.20061101121602.127">Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.
to around 500 deaths per year and nearly $14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK, helps arm America's communities with the
communication and safety skills needed to save lives and property– before and
during the event. StormReady helps community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of
severe weather through better planning, education, and awareness. No community
is storm proof, but StormReady can help communities save lives. Does StormReady
make a difference?
</t>
<t tx="ekr.20061101121602.128">Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.

Some 90% of all presidentially declared disasters are weather related, leading
to around 500 deaths per year and nearly $14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK, helps arm America's communities with the
communication and safety skills needed to save lives and property– before and
during the event. StormReady helps community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of
severe weather through better planning, education, and awareness. No community
is storm proof, but StormReady can help communities save lives. Does StormReady
make a difference?
</t>
<t tx="ekr.20061101121602.129">Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.
to around 500 deaths per year and nearly $14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK, helps arm America's communities with the
communication and safety skills needed to save lives and property– before and
during the event. StormReady helps community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of
severe weather through better planning, education, and awareness. No community
is storm proof, but StormReady can help communities save lives. Does StormReady
make a difference?
</t>
<t tx="ekr.20061101121602.154">@pagewidth 70 # Required for unit test.

c.testManager.runEditCommandTest(p)
</t>
<t tx="ekr.20061101121602.155">Some 90% of all presidentially declared disasters are weather related,
leading to around 500 deaths per year and nearly $14 billion in damage.
         StormReady, a program started in 1999 in Tulsa, OK,
  helps arm America's communities with the communication and safety
skills needed to save lives and property– before and during the event.
StormReady helps community leaders and emergency managers strengthen local safety programs.
</t>
<t tx="ekr.20061101121602.156">Some 90% of all presidentially declared disasters are weather related,
leading to around 500 deaths per year and nearly $14 billion in damage.
StormReady, a program started in 1999 in Tulsa, OK,
helps arm America's communities with the communication and safety
skills needed to save lives and property– before and during the event.
StormReady helps community leaders and emergency managers strengthen local safety programs.
</t>
<t tx="ekr.20061101121602.157">Some 90% of all presidentially declared disasters are weather related,
leading to around 500 deaths per year and nearly $14 billion in damage.
         StormReady, a program started in 1999 in Tulsa, OK,
  helps arm America's communities with the communication and safety
skills needed to save lives and property– before and during the event.
StormReady helps community leaders and emergency managers strengthen local safety programs.
</t>
<t tx="ekr.20061101121602.174">c.testManager.runEditCommandTest(p)
assert g.app.unitTestDict.get('colorized')
</t>
<t tx="ekr.20061101121602.175">Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. stormready, a program started in 1999 in tulsa, ok, helps arm america's communities with the communication and safety skills needed to save lives and property– before and during the event. stormready helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
</t>
<t tx="ekr.20061101121602.176">Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
</t>
<t tx="ekr.20061101121602.177">Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. stormready, a program started in 1999 in tulsa, ok, helps arm america's communities with the communication and safety skills needed to save lives and property– before and during the event. stormready helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
</t>
<t tx="ekr.20061101121602.282">c.testManager.runEditCommandTest(p)
</t>
<t tx="ekr.20061101121602.283">Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.



StormReady communities are better prepared to save lives from the onslaught of
severe weather through better planning, education, and awareness. No community
is storm proof, but StormReady can help communities save lives. Does StormReady
make a difference?
</t>
<t tx="ekr.20061101121602.284">Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.



StormReady communities are better prepared to save lives from the onslaught of
severe weather through better planning, education, and awareness. No community
is storm proof, but StormReady can help communities save lives. Does StormReady
make a difference?
</t>
<t tx="ekr.20061101121602.285">Americans live in the most severe weather-prone country on Earth. Each year,
Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000
tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly
weather impacts every American. Communities can now rely on the National Weather
Service’s StormReady program to help them guard against the ravages of Mother
Nature.

Some 90% of all presidentially declared disasters are weather related, leading
to around 500 deaths per year and nearly $14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK, helps arm America's communities with the
communication and safety skills needed to save lives and property– before and
during the event. StormReady helps community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of
severe weather through better planning, education, and awareness. No community
is storm proof, but StormReady can help communities save lives. Does StormReady
make a difference?
</t>
<t tx="ekr.20061101121602.350">c.testManager.runEditCommandTest(p)
assert g.app.unitTestDict.get('colorized')
</t>
<t tx="ekr.20061101121602.351">Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

SOME 90% OF ALL PRESIDENTIALLY DECLARED DISASTERS ARE WEATHER RELATED, LEADING TO AROUND 500 DEATHS PER YEAR AND NEARLY $14 BILLION IN DAMAGE. STORMREADY, A PROGRAM STARTED IN 1999 IN TULSA, OK, HELPS ARM AMERICA'S COMMUNITIES WITH THE COMMUNICATION AND SAFETY SKILLS NEEDED TO SAVE LIVES AND PROPERTY– BEFORE AND DURING THE EVENT. STORMREADY HELPS COMMUNITY LEADERS AND EMERGENCY MANAGERS STRENGTHEN LOCAL SAFETY PROGRAMS.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
</t>
<t tx="ekr.20061101121602.352">Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
</t>
<t tx="ekr.20061101121602.353">Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

SOME 90% OF ALL PRESIDENTIALLY DECLARED DISASTERS ARE WEATHER RELATED, LEADING TO AROUND 500 DEATHS PER YEAR AND NEARLY $14 BILLION IN DAMAGE. STORMREADY, A PROGRAM STARTED IN 1999 IN TULSA, OK, HELPS ARM AMERICA'S COMMUNITIES WITH THE COMMUNICATION AND SAFETY SKILLS NEEDED TO SAVE LIVES AND PROPERTY– BEFORE AND DURING THE EVENT. STORMREADY HELPS COMMUNITY LEADERS AND EMERGENCY MANAGERS STRENGTHEN LOCAL SAFETY PROGRAMS.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?
</t>
<t tx="ekr.20061104172236.23">w = c.frame.body.bodyCtrl
y = 10
for x in range(0,100,10):
    event = g.app.gui.create_key_event(c,None,None,w,x=x,y=y)
    c.frame.body.onClick(event)
</t>
<t tx="ekr.20070113145100"># Not part of cvs distributions, but needed for two unit tests.

dir = g.os_path_join(g.app.loadDir,'..','test','unittest',g.u('chinese\u8116folder'),encoding='utf-8')
s   = g.os_path_join(dir,g.u('chinese\u8116test.leo'),encoding='utf-8')
    
if not g.os_path_exists(dir):
    import os
    os.mkdir(dir)
    g.pr('created chinese folder')
    
if not g.os_path_exists(s):
    f = file(s,'w')
    f.close()
    g.pr('created chinese file')
    
</t>
<t tx="ekr.20070217065840">@nocolor-node

@
To make unit tests, do the following:
    
- Use the make-test script (Alt-5) to create a suboutline for a unit test.
- Put text in the before node, selected desired text, then do the do-before script (Alt-6).
- Execute the command, then do the do-after script (Alt-7).
</t>
<t tx="ekr.20070217065840.1">try:
    p1 = p.insertAfter()
    c.setHeadString(p1,'@test ')
    body = 'c.testManager.runEditCommandTest(c,p)'
    c.setBodyString(p1,body)
    for s in ('work','before','after'):
        p2 = p1.insertAsLastChild()
        c.setHeadString(p2,s)
    p1.expand()
finally:
    c.redraw()
    c.editPosition(p1)</t>
<t tx="ekr.20070217065840.2">@
p should be in tree whose root is a @test node containing 'work', 'before' and
'after' children. The work node should have body text. If all is as expected,
copy the body text the work node to the before node, and represent the selection
range of the work in the headline of the before node.
@c

@others

sel = getSel(c)
top,work,before,after = findNodes(p)
if top and work.b:

    c.setBodyString(before,work.b)
    c.setBodyString(after,'')
    putSelectionInHeadline(c,before,'before',sel)
    c.redraw()
else:
    g.es_print('do-before: not in a proper @test tree')</t>
<t tx="ekr.20070217065840.3">def getSel(c):
    
    w = c.frame.body.bodyCtrl
    i,j= w.getSelectionRange()
    if i == j:
        i = j = w.getInsertPoint()
        sel = (i,i)
    return i,j</t>
<t tx="ekr.20070217065840.4">def findNodes(p):
    
    '''Find the top, work, before and after nodes.
    p should be in tree whose root is a @test node containing
    'work', 'before' and 'after' children.'''
    
    for p in p.self_and_parents_iter():
        if p.h.startswith('@test '):
            break
    top    = p and p.copy()
    work   = top and top.firstChild() 
    before = work and work.next()     
    after  = before and before.next()
    if (
        work   and work.h.startswith('work') and
        before and before.h.startswith('before') and
        after  and after.h.startswith('after')
    ):
        return top,work,before,after
    else:
        return None,None,None,None</t>
<t tx="ekr.20070217065840.5">def putSelectionInHeadline (c,p,prefix,sel):
    
    # g.trace(p.h,repr(sel))

    w = c.frame.body.bodyCtrl
    i,j = sel
    i,j = w.toGuiIndex(i),w.toGuiIndex(j)
    s = '%s sel=%s,%s' % (prefix,i,j)
    c.setHeadString(p,s)
</t>
<t tx="ekr.20070217065840.6">@
p should be in tree whose root is a @test node containing 'work', 'before' and
'after' children. If all is as expected, copy the work node to the after node,
and represent the selection range of the work node in the headline of the after node.
@c

@others

sel = getSel(c)
top,work,before,after = findNodes(p)
if top:
    c.setBodyString(after,work.b)
    putSelectionInHeadline(c,after,'after',sel)
    c.redraw()
else:
    g.es_print('do-after: not in @test tree')</t>
<t tx="ekr.20070217065840.8">def findNodes(p):
    
    '''Find the top, work, before and after nodes.
    p should be in tree whose root is a @test node containing
    'work', 'before' and 'after' children.'''
    
    for p in p.self_and_parents_iter():
        if p.h.startswith('@test '):
            break
    top    = p and p.copy()
    work   = top and top.firstChild()
    before = work and work.next()
    after  = before and before.next()
    if (
        work   and work.h.startswith('work') and
        before and before.h.startswith('before') and
        after  and after.h.startswith('after')
    ):
        return top,work,before,after
    else:
        return None,None,None,None</t>
<t tx="ekr.20070217065840.9">def putSelectionInHeadline (c,p,prefix,sel):
    
    # g.trace(p.h,repr(sel))
    
    w = c.frame.body.bodyCtrl
    i,j = sel
    i,j = w.toGuiIndex(i),w.toGuiIndex(j)
    s = '%s sel=%s,%s' % (prefix,i,j)
    c.setHeadString(p,s)
</t>
<t tx="ekr.20070217072822">def getSel(c):
    
    w = c.frame.body.bodyCtrl
    i,j= w.getSelectionRange()
    if i == j:
        i = j = w.getInsertPoint()
        sel = (i,i)
    return i,j</t>
<t tx="ekr.20070417092935" str_leo_pos="6">
@nosearch</t>
<t tx="ekr.20070503064257"></t>
<t tx="ekr.20070528100318"># Required to make a typing test work.
</t>
<t tx="ekr.20070926095117">def mungeKey (h,kind,substitute=True):

    key = h[len(kind):].strip()
    i = key.find('@key')
    if i &gt; -1: key = key[:i].strip()
    if substitute:
        key = key.replace(' ','-')
    # g.trace(key)
    return key


</t>
<t tx="ekr.20071113090055.5"># This will work regardless of where this method is.
@language python
@tabwidth -4
# @path xyzzy # Creates folder called xyzzy: interferes with other unit tests.
@pagewidth 120

d = c.atFileCommands.scanAllDirectives(p)
# print(d)
assert d.get('language') == 'python'
assert d.get('tabwidth') == -4
# assert d.get('path').endswith('xyzzy')
assert d.get('pagewidth') == 120
</t>
<t tx="ekr.20071113140035">fn = g.os_path_abspath(g.os_path_join(g.app.loadDir,'..','core','leoPy.leo'))
assert g.os_path_exists(fn),fn
c1 = c
c2 = g.openWithFileName(fn,old_c=None,enableLog=False)
assert c2
c.frame.bringToFront()
g.app.setLog(c.frame.log)

d1 = {} ; d2 = {}
for c,d in ( (c1,d1),(c2,d2)):
    for p in c.all_unique_positions():
        if p.h.startswith('@test'):
            d[p.h]=p.h

if 0: # not important
    g.pr()
    g.pr('----- Only in unitTest.leo')
    for h in sorted(d1.keys()):
        if not d2.get(h):
            print(h)

print('\n----- Only in leoPy.leo')
for h in sorted(d2.keys()):
    if not d1.get(h):
        print(h)</t>
<t tx="ekr.20071113145804.4">@first # -*- coding: utf-8 -*-
@language python

try:
    ec = c.editCommands ; w = c.frame.body.wrapper
    s = w.getAllText()

    # This strings tests unicode, paren matching, and auto-indentation.
    u = g.u('(a\u00c9\u03a9B\u3045\u4e7cz):\n') # '(aÉ©BE|cz):\n'
    u = g.u('(pdq):\n')
    w.setInsertPoint(len(s))
    for char in u:
        stroke = g.choose(char=='\n','Return',char)
        event = g.app.gui.create_key_event(c,char,stroke,w)
        ec.selfInsertCommand(event)
    result = w.getAllText()
    #g.trace('result',repr(result))
    assert result.endswith('    '),'result:\n%s' % result
    # Test of autocompleter.
finally:
    if 1:
        w.setAllText(s)
        p.setBodyString(s)
        # g.trace(repr(s))
        c.recolor()

# end:
</t>
<t tx="ekr.20071113203234"></t>
<t tx="ekr.20080324133327.2">True: allow linux-like pastes using a mouse's middle button.

Important: this may cause crashes on some platforms.
</t>
<t tx="ekr.20080405085247.1"></t>
<t tx="ekr.20080703104536.1"></t>
<t tx="ekr.20080806084924.2">@others
</t>
<t tx="ekr.20080806084924.3">pass
</t>
<t tx="ekr.20080806084924.4">pass
</t>
<t tx="ekr.20080806084924.5">pass
</t>
<t tx="ekr.20080806095923.2">root = p.firstChild()
uA = 'unknownAttributes'
tag = 'round-trip-u.uA'
ttag = 'round-trip-t.uA'
trace = False

if 0: # Set the uA's.
    for p2 in root.self_and_subtree_iter():
        p2.v.unknownAttributes = {tag: p2.h}
else: # Test the uA's.
    # The root is a special case.
    v = root.v
    assert hasattr(v,uA),'no v.uA for %s' % v
    assert getattr(v,uA),'empty v.uA for %s' % v
    for p2 in root.self_and_subtree_iter():
        v = p2.v
        assert hasattr(v,uA),'no v.uA for %s' % v
        a = getattr(v,uA)
        d = {tag: v.h}
        if trace: print(d)
        assert a == d, 'expected v.uA: "%s", got "%s"' % (d,a)
</t>
<t tx="ekr.20080806211453.1">@language python
@tabwidth -4
@others
</t>
<t tx="ekr.20080806211453.5">root = p.firstChild()
uA = 'unknownAttributes'
tag = 'round-trip-u.uA'
ttag = 'round-trip-t.uA'
trace = False

if 0: # Set the uA's.
    for p2 in root.self_and_subtree_iter():
        p2.v.unknownAttributes = {tag: p2.h}
else: # Test the uA's.
    # The root is a special case.
    v = root.v
    assert hasattr(v,uA),'no v.uA for %s' % v
    assert getattr(v,uA),'empty v.uA for %s' % v
    for p2 in root.self_and_subtree_iter():
        v = p2.v
        assert hasattr(v,uA),'no v.uA for %s' % v
        a = getattr(v,uA)
        d = {tag: v.h}
        if trace: print(d)
        assert a == d, 'expected v.uA: "%s", got "%s"' % (d,a)
</t>
<t tx="ekr.20080821123427.2">@first # -*- coding: utf-8 -*-

import sys

print('=' * 40)

e = sys.getdefaultencoding()
print('encoding',e)

table = (
    'La Peña',
    g.u('La Peña'),
    # u'La Peña',
    g.u('La Pe\xf1a')
)

for s in table:
    print(type(s))
    g.es_print('g.es_print',s)
    if type(s) != type(u'a'):
        s = unicode(s,e)
    print('print     ',s)
    print('repr(s)   ',repr(s))
</t>
<t tx="ekr.20080822160527.1">pass
pass
pass
</t>
<t tx="ekr.20080907122804.1">@others</t>
<t tx="ekr.20080907123324.2">@language python
@tabwidth -4
# before @others: line 1
@others
# last line: line 6</t>
<t tx="ekr.20080907123324.3">def spam(): # line 2
    pass
</t>
<t tx="ekr.20080917151620.9">@language python
@comment a b c
    # @comment must follow @language
@tabwidth -4
@pagewidth 72
@encoding utf-8
@lineending crlf

d = c.scanAllDirectives(p)
# print(g.dictToString(d))

table = (
    ('delims', ('a','b','c'),),
    ('encoding','utf-8'),
    ('language','python'),
    ('lineending','\r\n'),
    ('pagewidth',72),
    ('tabwidth',-4),
)

for kind,expected in table:
    got = d.get(kind)
    assert got == expected, 'kind: %s, expected %s, got %s' % (
        kind,repr(expected),repr(got))
</t>
<t tx="ekr.20081121164135.1">path = g.os_path_join(g.app.loadDir,"..","plugins","leoGuiPluginsRef.leo")
c.testManager.runLeoTest(path)
</t>
<t tx="ekr.20090704085350.5014">@others</t>
<t tx="ekr.20090704085350.5028">@language python
@others</t>
<t tx="ekr.20090704085350.5029">def spam():
    pass</t>
<t tx="ekr.20090704085350.5030">def eggs():
    pass</t>
<t tx="ekr.20090704085350.5034">@first
@language python
@others
</t>
<t tx="ekr.20090704085350.5035">def spam():
    pass # Unicode test: Ã after.
</t>
<t tx="ekr.20090704085350.5036">def eggs():
    pass
</t>
<t tx="ekr.20091206090247.5060"># Use these with caution.</t>
<t tx="ekr.20091206090247.5061">count = 0
for p in c.all_unique_positions():
    count += 1
    # Empty tnodeLists are not errors because they never get written to the .leo file.
    v = p.v
    if hasattr(v,"tnodeList") and len(v.tnodeList) &gt; 0 and not v.isAnyAtFileNode():
        g.es("deleting tnodeList for " + `v`,color="blue")
        delattr(v,"tnodeList")
        c.setChanged(True)

s = "%d nodes" % count
print(s) ; g.es(s)</t>
<t tx="ekr.20091206090247.5062"># About the only time you should run this script is when:
# - changing the format of timestamps in nodeIndices.setTimestamp or
# - when making a retroactive change to leoID.txt.

if 0: # This is usually a very bad idea.

    for p in c.all_positions():
        p.v.fileIndex = None

    g.es("all timestamps cleared")</t>
<t tx="ekr.20091206090247.5063">doDelete = False
put = g.es_print
for p in c.all_positions():
    if p.v.u:
        put("found v.u:",p.h,
            g.listToString(p.v.u.keys()))
        if doDelete:
            p.v.u = None
put('done') 
c.redraw()</t>
<t tx="ekr.20100102164959.5088">nodes = 0 ; lines = 0
for p in c.all_unique_positions():
    nodes += 1
    lines += len(g.splitLines(p.b))

pages = ((nodes * 10) + lines) / 50
s = "%d nodes,  %d lines, %d pages" % (nodes,lines,pages)
print(s); g.es(s)</t>
<t tx="ekr.20100123172713.5114"></t>
<t tx="ekr.20100123172713.5116">count = 0
for p in c.all_unique_positions():
    count += 1
    # Empty tnodeLists are not errors because they never get written to the .leo file.
    v = p.v
    if hasattr(v,"tnodeList"): # and len(v.tnodeList) &gt; 0 and not v.isAnyAtFileNode():
        g.es("deleting tnodeList for " + `v`,color="blue")
        delattr(v,"tnodeList")
        c.setChanged(True)

s = "%d nodes" % count
print s ; g.es(s)</t>
<t tx="ekr.20100125180231.5120">@first # -*- coding: utf-8 -*-

s = g.ue('炰','utf-8')
g.es(s)
g.pr(s)
s = '炰'
g.pr(s)
</t>
<t tx="ekr.20100127162342.5123">import glob,os

tkPass = (
    'EditAttributes','Library',
    'URLloader','UniversalScrolling','UASearch',
    'autotrees','chapter_hoist','cleo','dump_globals',
    'expfolder','geotag','graphed','groupOperations',
    'hoist','import_cisco_config',
    'keybindings','leoupdate',
    'maximizeNewWindows', 'mnplugins','mod_labels',
    'mod_read_dir_outline','mod_tempfname','multifile',
    'newButtons','nodeActions','nodenavigator',
    'open_with','pie_menus','pluginsTest',
    'read_only_nodes','rClick',
    'scheduler','searchbar','searchbox','shortcut_button',
    'script_io_to_body','searchbox',
    'templates','textnode','tkGui','toolbar',
    'xcc_nodes',
)
tkPassWithProblems = (
    'at_view', # at_view plugin not loaded: win32Clipboard not present.
    'image', # can not import ImageTk.
    'table', # failed to import 'tktable'
    'xsltWithNodes', # Can not import Ft from plugin leo.plugins.xsltWithNodes.
)
tkFail = (
    'ConceptualSort','at_produce','autocompleter','rowcol',
)
passList = (
    '__init__','FileActions','UNL',
    'active_path','add_directives','attrib_edit',
    'backlink','base64Packager','baseNativeTree','bibtex','bookmarks',
    'codewisecompleter','colorize_headlines','contextmenu',
    'ctagscompleter','cursesGui','datenodes','debugger_pudb',
    'detect_urls','dtest','empty_leo_file','enable_gc','initinclass',
    'leo_to_html','leo_interface','leo_pdf','leo_to_rtf',
    'leoOPML','leoremote','lineNumbers',
    'macros','mime','mod_autosave','mod_framesize','mod_leo2ascd',
    'mod_scripting','mod_speedups','mod_timestamp',
    'nav_buttons','nav_qt','niceNosent','nodeActions','nodebar',
    'open_shell','outline_export','quit_leo',
    'paste_as_headlines','plugins_menu','pretty_print','projectwizard',
    'qt_main','qt_quicksearch','qtframecommands',
    'quickMove',
        # Warning: changed this line by guessing!
        # func = types.MethodType(func, quickMove)
    'quicksearch','redirect_to_log','rClickBasePluginClasses',
    'run_nodes', # Changed thread.allocate_lock to threading.lock().acquire()
    'rst3',
    'scrolledmessage','setHomeDirectory','slideshow','spydershell','startfile',
    'testRegisterCommand','todo','trace_gc_plugin','trace_keys','trace_tags',
    'vim','xemacs',
)
passWithImportProblems = ( # Other than tk input problems.
    'ipython','word_export',
)
dead = (
    'at_folder','exampleTemacsExtension','ironPythonGui','LeoN',
    'rst2','swing_gui','temacs','usetemacs','wxGui',)
error = ( # Real errors with tracebacks.
)
fail = (
    'stickynotes_plus', # requires markdown.
    'zenity_file_dialogs', # requires zenity, and probably ubuntu.
)
noAttribute = (
    # AttributeError: 'module' object has no attribute &lt;module name&gt;
    # This was a sign of a missing init top-level function.
)
changed = (
    'LeoN',
)
plugins = g.os_path_abspath(g.os_path_join(
    g.app.loadDir,'..','plugins','*.py'))
files = glob.glob(plugins)
files.sort()
os.system('cls') # Clear the screen on windows.
for fn in files:
    m = g.shortFileName(fn)[:-3]
    # Change the next line to choose different plugins.
    if m in passList:
        try:
            __import__('leo.plugins.%s' % m)
            if 1: print('pass %s' % m)
        except ImportError:
            if 1: print('FAIL %s' % m)
        except Exception:
            if 1: g.es_exception()
            if 1: print('error %s' % m)
</t>
<t tx="ekr.20100131171342.5473"></t>
<t tx="ekr.20100131171342.5474">if g.app.gui.guiName() == 'tkinter':

    pc = g.app.pluginsController
    tkGui = pc.loadOnePlugin('leo.plugins.tkGui',verbose=False)
    assert(tkGui)

    import leo.core.leoFrame as leoFrame
    import inspect,sys

    baseClass = leoFrame.leoBody
    subClasses  = (tkGui.leoTkinterBody,leoFrame.nullBody)
    baseObject = c.frame.body

    methods = inspect.getmembers(baseClass,inspect.ismethod)
    methodNames = [z[0] for z in methods]

    for name in baseObject.mustBeDefinedOnlyInBaseClass:
        try:
            assert name in methodNames, 'not defined in base class %s.%s' % (baseClass.__name__,name)
        except AssertionError:
            exctype, value = sys.exc_info()[:2]
            print(value)
            raise

    for subClass in subClasses:
        subclassName = subClass.__name__
        for name in methodNames:
            base_func = getattr(baseClass,name)
            sub_func =  getattr(subClass,name)
            try:
                if name in baseObject.mustBeDefinedOnlyInBaseClass:
                    assert base_func.im_func == sub_func.im_func, 'defined in subclass %s.%s' % (subclassName,name)
                if name in baseObject.mustBeDefinedInSubclasses:
                    assert base_func.im_func != sub_func.im_func, 'not defined in subclass %s.%s' % (subclassName,name)
            except AssertionError:
                #raise
                exctype, value = sys.exc_info()[:2]
                print(value)
</t>
<t tx="ekr.20100131171342.5475">if g.app.gui.guiName() == 'tkinter':

    pc = g.app.pluginsController
    tkGui = pc.loadOnePlugin('leo.plugins.tkGui',verbose=False)

    import leo.core.leoFrame as leoFrame
    import inspect

    baseClass = leoFrame.leoFrame
    subClasses  = (tkGui.leoTkinterFrame,leoFrame.NullFrame)
    baseObject = c.frame

    methods = inspect.getmembers(baseClass,inspect.ismethod)
    methodNames = [z[0] for z in methods]

    for name in baseObject.mustBeDefinedOnlyInBaseClass:
        assert name in methodNames, 'not defined in base class %s.%s' % (baseClass.__name__,name)

    for subClass in subClasses:
        subclassName = subClass.__name__
        for name in methodNames:
            base_func = getattr(baseClass,name)
            sub_func =  getattr(subClass,name)
            if name in baseObject.mustBeDefinedOnlyInBaseClass:
                assert base_func.im_func == sub_func.im_func, 'defined in subclass %s.%s' % (subclassName,name)
            if name in baseObject.mustBeDefinedInSubclasses:
                assert base_func.im_func != sub_func.im_func, 'not defined in subclass %s.%s' % (subclassName,name)
</t>
<t tx="ekr.20100131171342.5476">if g.app.gui.guiName() == 'tkinter':

    pc = g.app.pluginsController
    tkGui = pc.loadOnePlugin('leo.plugins.tkGui',verbose=False)

    import leo.core.leoGui as leoGui
    import inspect

    baseClass = leoGui.leoGui
    subClasses  = (tkGui.tkinterGui,) # nullGui can inherit almost all leoGui dummy methods.
    baseObject = g.app.gui

    methods = inspect.getmembers(baseClass,inspect.ismethod)
    methodNames = [z[0] for z in methods]

    for name in baseObject.mustBeDefinedOnlyInBaseClass:
        assert name in methodNames, 'not defined in base class %s.%s' % (baseClass.__name__,name)

    for subClass in subClasses:
        subclassName = subClass.__name__
        for name in methodNames:
            base_func = getattr(baseClass,name)
            sub_func =  getattr(subClass,name)
            try:
                if name in baseObject.mustBeDefinedOnlyInBaseClass:
                    assert base_func.im_func == sub_func.im_func, 'defined in subclass %s.%s' % (subclassName,name)
                if name in baseObject.mustBeDefinedInSubclasses:
                    assert base_func.im_func != sub_func.im_func, 'not defined in subclass %s.%s' % (subclassName,name)
            except AssertionError:
                raise
</t>
<t tx="ekr.20100131171342.5477">if g.app.gui.guiName() == 'tkinter':

    pc = g.app.pluginsController
    tkGui = pc.loadOnePlugin('leo.plugins.tkGui',verbose=False)

    import leo.core.leoFrame as leoFrame
    import inspect

    baseClass = leoFrame.leoTree
    subClasses  = (tkGui.leoTkinterTree,leoFrame.nullTree)
    baseObject = c.frame.tree

    methods = inspect.getmembers(baseClass,inspect.ismethod)
    methodNames = [z[0] for z in methods]

    for name in baseObject.mustBeDefinedOnlyInBaseClass:
        assert name in methodNames, 'not defined in base class %s.%s' % (baseClass.__name__,name)

    for subClass in subClasses:
        subclassName = subClass.__name__
        for name in methodNames:
            base_func = getattr(baseClass,name)
            sub_func =  getattr(subClass,name)
            if name in baseObject.mustBeDefinedOnlyInBaseClass:
                assert base_func.im_func == sub_func.im_func, 'defined in subclass %s.%s' % (subclassName,name)
            if name in baseObject.mustBeDefinedInSubclasses:
                assert base_func.im_func != sub_func.im_func, 'not defined in subclass %s.%s' % (subclassName,name)
</t>
<t tx="ekr.20100131171342.5478">logCtrl = c.frame.log.logCtrl

table = (
    ('mustBeDefinedInSubclasses',logCtrl.mustBeDefinedInSubclasses),
    ('mustBeDefinedInBaseClass',logCtrl.mustBeDefinedOnlyInBaseClass),
    ('mustBeDefined',logCtrl.mustBeDefined),
)

# Check existence.
for tag,aList in table:
    for z in aList:
        assert hasattr(c.frame.log,z),'%s %s %s' % (tag,c.frame.log,z)
        assert hasattr(c.frame.body,z),'%s %s %s' % (tag,c.frame.body,z)

# Check signatures.
import inspect
for tag,aList in table:
    for z in aList:
        func = getattr(c.frame.body.bodyCtrl,z)
        func2 = getattr(c.frame.log.logCtrl,z)
        assert func,z
        assert func2,z
        d1 = inspect.getargspec(func)
        d2 = inspect.getargspec(func2)
        assert d1==d2,'\n%s\n\nd1 %s\n\nd2 %s' % (z,d1,d2)
</t>
<t tx="ekr.20100131171342.5483">import os
import sys

trace = False

python_interp = sys.executable
test_path = g.os_path_join(g.app.loadDir,"..","test","unittest")
src_path  = g.os_path_join(g.app.loadDir,"..","..")

leo_file   = g.os_path_join(src_path,"launchLeo.py")
batch_file = g.os_path_join(test_path,"batchTest.py")
test_file  = g.os_path_join(test_path,"createdFile.txt")

# Execute this command: python launchLeo.py --script test\unittest\batchTest.py

if 1:
    command = r"%s %s --silent --script %s" % (python_interp,leo_file,batch_file)
else:
    command = r"%s %s --script %s" % (python_interp,leo_file,batch_file)

@others

if trace:
    print('@test batch mode: loadDir: %s' % g.app.loadDir)

removeFile(test_file)
os.system(command)

assert(g.os_path_exists(test_file))
</t>
<t tx="ekr.20100131171342.5484">def removeFile(path):

    trace = False

    if os.path.exists(test_file):
        if trace:
            print("@test batch mode: removeFile: deleting",test_file)
        os.remove(test_file)
    else:
        if trace:
            print("@test batch mode: removeFile: not found:",test_file)
</t>
<t tx="ekr.20100131171342.5508"></t>
<t tx="ekr.20100131171342.5509">import leo.core.leoBridge as leoBridge

if g.app.isExternalUnitTest:
    print('running @test leoBridge init logic')
    # This can not be run locally!
    b = leoBridge.controller(gui='nullGui',
        loadPlugins=True,
        readSettings=True,
        silent=False,
        tracePlugins=True,
        verbose=True)
    g = b.globals()
    path = g.os_path_finalize_join(g.app.loadDir,'..','doc','LeoDocs.leo')
    assert g.os_path_exists(path)
    c = b.openLeoFile(path)
    assert c
    assert c.rootPosition()
else:
    self.skipTest('Can not be run locally')
</t>
<t tx="ekr.20100131171342.5608"># print('settingsNameDict',c.k.settingsNameDict)

table = (
    ('Key-1','1'), # 2016/04/12
    ('key-1','1'), # 2016/04/12
    ('1', '1'), # 2016/04/12
    ('a','a'),
    ('A','a'),
    ('Alt-a','Alt+a'),
    ('Alt-A','Alt+a'),
    ('Alt-Shift-a','Alt+A'),
    ('Alt-=','Alt+equal'),
    ('Alt-+','Alt+plus'),
    # We can no longer igtnore the shift.
    # ('Alt-Shift++','Alt+plus'), # Ignore the shift.
    ('Alt--','Alt+minus'),
    ('Shift-a','A'),
    ('Shift-A','A'),
    ('RtArrow','Right'),
    ('Shift-RtArrow','Shift+Right'),
    ('Ctrl-RtArrow','Ctrl+Right'),
    ('Control-Right','Ctrl+Right'),
    ('PageUp','Prior'), ('Prior','Prior'),('Shift-PageUp','Shift+Prior'),
    ('PageDn','Next'),('Next','Next'),('Shift-Next','Shift+Next'),
)
for setting, result in table:
    val = c.k.strokeFromSetting(setting)
    assert val==result,'Expected %s, Got %s' % (result,val)
</t>
<t tx="ekr.20100131180007.5434">@language python
@comment a b c
    # @comment must follow @language.
@tabwidth -8
@pagewidth 72
@encoding utf-8
@path: anError # @path ends with ':'.

# @path xyzzy # Creates folder called xyzzy: interferes with other unit tests.

d = g.get_directives_dict(p)

# assert d.get('_p') == p # Never used, and a bad idea.
assert d.get('language') == 'python'
assert d.get('tabwidth') == '-8'
assert d.get('pagewidth') == '72'
assert d.get('encoding') == 'utf-8'
assert d.get('comment') == 'a b c'
assert not d.get('path'),d.get('path')
# assert d.get('path').endswith('xyzzy')
</t>
<t tx="ekr.20100203163606.5365">import os

def run(files):
    args = [r'python c:\python26\Tools\Scripts\2to3.py']
    for z in files:
        args.append(z)
        # args.append('-xprint')
    args.append('&gt;out2')
    args = ','.join(args)
    os.system(args)

tkPass = (
    'EditAttributes','Library',
    'URLloader','UniversalScrolling','UASearch',
    'autotrees','chapter_hoist','cleo','dump_globals',
    'expfolder','geotag','graphed','groupOperations',
    'hoist','import_cisco_config',
    'keybindings','leoupdate',
    'maximizeNewWindows', 'mnplugins','mod_labels',
    'mod_read_dir_outline','mod_tempfname','multifile',
    'newButtons','nodeActions','nodenavigator',
    'open_with','pie_menus','pluginsTest',
    'read_only_nodes','rClick',
    'scheduler','searchbar','searchbox','shortcut_button',
    'script_io_to_body','searchbox',
    'templates','textnode','tkGui','toolbar',
    'xcc_nodes',
)

passList = (
    '__init__','FileActions','UNL',
    'active_path','add_directives','attrib_edit',
    'backlink','base64Packager','baseNativeTree','bibtex','bookmarks',
    'codewisecompleter','colorize_headlines','contextmenu',
    'ctagscompleter','cursesGui','datenodes','debugger_pudb',
    'detect_urls','dtest','empty_leo_file','enable_gc','initinclass',
    'leo_to_html','leo_interface','leo_pdf','leo_to_rtf',
    'leoOPML','leoremote','lineNumbers',
    'macros','mime','mod_autosave','mod_framesize','mod_leo2ascd',
    'mod_scripting','mod_speedups','mod_timestamp',
    'nav_buttons','nav_qt','niceNosent','nodeActions','nodebar',
    'open_shell','outline_export','quit_leo',
    'paste_as_headlines','plugins_menu','pretty_print','projectwizard',
    'qt_main','qt_quicksearch','qtframecommands',
    'quickMove',
        # Warning: changed this line by guessing!
        # func = types.MethodType(func, quickMove)
    'quicksearch','redirect_to_log','rClickBasePluginClasses',
    'run_nodes', # Changed thread.allocate_lock to threading.lock().acquire()
    'rst3',
    'scrolledmessage','setHomeDirectory','slideshow','spydershell','startfile',
    'testRegisterCommand','todo','trace_gc_plugin','trace_keys','trace_tags',
    'vim','xemacs',
)
core_files = (
    'leoApp','leoAtFile','leoCache','leoChapters','leoCommands',
    'leoEditCommands','leoFileCommands','leoFind','leoFrame',
    'leoGlobals','leoGui','leoImport','leoMenu','leoNodes',
    'leoPlugins','leoShadow','leoTangle','leoUndo',
)
external_files = (
    'ipy_leo','lproto',
)
table = (
    ('plugins',passList),
    ('plugins',tkPass),
    ('core',core_files),
    ('external',external_files),
)
files = []
for theDir,aList in table:
    for z in aList:
        if not z.endswith('.py'): z = z + '.py'
        # print(z)
        fn = os.path.abspath(os.path.join('leo',theDir,z))
        if os.path.exists(fn): files.append(fn)
        else: print('*** file not found:',fn)

run(files)
print('done: results are in out2')
</t>
<t tx="ekr.20100204153116.5369">import tempfile
import os

s = 'Select the following string: वादक. Typing and undo now work.'
fd,fn = tempfile.mkstemp(text=False)
s = g.toEncodedString(s)
os.write(fd,s)
os.close(fd)
f = open(fn,'rb')
s2 = f.read()
f.close()
assert s==s2
os.remove(fn)
print('deleted',fn)
</t>
<t tx="ekr.20100204165850.5373">k = c.k
colorizer = c.frame.body.getColorizer()
ed = c.editCommands

# These don't set ivars
    # 'toggle-active-pane'),
    # 'toggle-angle-brackets',
    # 'toggle-input-state'),
    # 'toggle-mini-buffer'),
    # 'toggle-split-direction'),

table = [
    (k,'abbrevOn','toggle-abbrev-mode'),
    (ed,'extendMode','toggle-extend-mode'),
]

# Not valid for external tests.
table2 = [
    (k,'enable_autocompleter','toggle-autocompleter'),
    (k,'enable_calltips','toggle-calltips'),
    (c,'sparse_find','toggle-find-collapses-nodes'),
    (colorizer,'showInvisibles','toggle-invisibles'),
    (c,'sparse_move','toggle-sparse-move'),
]

if not g.app.isExternalUnitTest:
    table.extend(table2)

for obj,ivar,command in table:
    val1 = getattr(obj,ivar)
    try:
        k.simulateCommand(command)
        val2 = getattr(obj,ivar)
        assert val2 == (not val1),'failed 1 %s' % command
        k.simulateCommand(command)
        val3 = getattr(obj,ivar)
        assert val3 == val1,'failed 2 %s' % command
        # print('pass',command)
    finally:
        setattr(obj,ivar,val1)
</t>
<t tx="ekr.20100205235740.5392">import glob
trace = False
failed,n = [],0
skip_tuples3 = (
    ('extensions','asciidoc.py'),
)
skip_tuples2 = (
    ('test', 'python3_test.py'),
)
join = g.os_path_finalize_join
skip_tuples = skip_tuples3 if g.isPython3 else skip_tuples2
skip_list = [join(g.app.loadDir,'..',a,b) for a,b in skip_tuples]
for theDir in ('core','external','extensions','plugins','scripts','test'):
    if trace: print(theDir)
    path = g.os_path_finalize_join(g.app.loadDir,'..',theDir)
    assert g.os_path_exists(path),path
    aList = glob.glob(g.os_path_join(path,'*.py'))
    for z in aList:
        if z in skip_list:
            pass # print('%s: skipped: %s' % (p.h,z))
        else:
            n += 1
            fn = g.shortFileName(z)
            # if trace: print('%8s %s' % (theDir,fn))
            s,e = g.readFileIntoString(z)
            if not c.testManager.checkFileSyntax(fn,s,reraise=False,suppress=False):
                failed.append(z)
if trace: print('tested %s files' % n)
assert not failed,'failed %s\n' % g.listToString(failed,sort=True)
</t>
<t tx="ekr.20100208095817.5387"># Disabled this test because it's best to open this file without caching.

import leo.core.leoCache as leoCache

cacher = leoCache.cacher(c)

assert cacher.test()
</t>
<t tx="ekr.20100208230953.5383"></t>
<t tx="ekr.20100212072149.5341">child = g.findNodeInChildren(c, p, 'syntax-error')
assert child, 'no child'
try:
    c.goToScriptLineNumber(1, child)
finally:
    p.contract()
    c.selectPosition(p)
    c.redraw()
</t>
<t tx="ekr.20100212072149.5342">@language python
def spam:
    pass
</t>
<t tx="ekr.20100223094723.5375"></t>
<t tx="ekr.20100223094723.5376">import leo.core.leoImport as leoImport
ic = c.importCommands

s = '''\

def one():
    pass

import a
from . import a

@language python

d = {} # An interior comment.

# This is a comment.
# and another comment.
@aDecorator
class cl: # An interior comment
    def method(self):
        pass

def two():
    pass

'''

# tree = c.importCommands.pythonUnitTest(p,s=s,showTree=True)

expected = s.find('# This is a comment')
scanner = leoImport.PythonScanner(importCommands=ic,atAuto=False)
i = s.find('import a')
assert i &gt; -1
i = scanner.skipToTheNextClassOrFunction(s,i,lastIndent=0)
assert i==expected,'expected %s, got %s %s' % (
    expected,i,repr(s[i:]))
</t>
<t tx="ekr.20100223094723.5377">import leo.core.leoImport as leoImport
ic = c.importCommands

s = '''\

def one():
    pass

import a
from . import a

d = {}

# This is a comment.
@tabwith -4 # This looks like a comment.
# and another comment.
@aDecorator
def two():
    pass

'''

# tree = c.importCommands.pythonUnitTest(p,s=s,showTree=True)

expected = s.find('# This is a comment')
scanner = leoImport.PythonScanner(importCommands=ic,atAuto=False)
i = s.find('import a')
assert i &gt; -1
i = scanner.skipToTheNextClassOrFunction(s,i,lastIndent=0)
assert i==expected,'expected %s, got %s %s' % (
    expected,i,repr(s[i:]))
</t>
<t tx="ekr.20100223094723.5378">import leo.core.leoImport as leoImport
ic = c.importCommands

s = '''\

def one():
    pass

import a
from . import a

d = {}

# This is a comment.
# and another comment.

@tabwidth -4

aList = ('a','b','def')

if __name__ == '__main__':
    pass

'''

lastLine = 'pass\n'
expected = s.find(lastLine) + len(lastLine) + 1
scanner = leoImport.PythonScanner(importCommands=ic,atAuto=False)
i = s.find('import a')
assert i &gt; -1
i = scanner.skipToTheNextClassOrFunction(s,i,lastIndent=0)
assert i==expected,'expected %s, got %s %s' % (
    expected,i,repr(s[i:]))
</t>
<t tx="ekr.20100223094723.5379">import leo.core.leoImport as leoImport
ic = c.importCommands

s = '''\

def one():
    pass

import a
from . import a

if 0:
    def two():
        pass

if __name__ == '__main__':
    pass

'''

scanner = leoImport.PythonScanner(importCommands=ic,atAuto=False)
expected = i = s.find('import a')
assert i &gt; -1
i = scanner.skipToTheNextClassOrFunction(s,i,lastIndent=0)
assert i==expected,'expected %s, got %s %s' % (
    expected,i,repr(s[i:]))
</t>
<t tx="ekr.20100223123103.5382">import leo.core.leoFrame as leoFrame

# Do nothing when run externally.
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    assert not isinstance(c.frame,leoFrame.NullFrame)
    def closeEnough(f1,f2):
        return abs(f1-f2) &lt; 0.0001
    f = c.frame
    ratio,ratio2 = f.ratio,f.secondary_ratio
    table = (
        c.bodyWantsFocusNow,
        c.logWantsFocusNow,
        c.treeWantsFocusNow,
    )
    for func in table:
        name = func.__name__
        func()
        f.contractPane()
        if func == c.logWantsFocusNow:
            assert ratio2 != f.secondary_ratio,'fail 1'
        else:
            assert ratio != f.ratio,'fail 2: %s, %s: %s' % (ratio,f.ratio,name)
        func()
        f.expandPane()
        assert closeEnough(ratio,f.ratio),'fail 3 %s != %s: %s' % (
            ratio,f.ratio,name)
        assert closeEnough(ratio2,f.secondary_ratio),'fail 4 %s != %s: %s' % (
            ratio2,f.secondary_ratio,name)
</t>
<t tx="ekr.20100225094004.5405"># test/at-file-test.leo contains tnodeList.
# test/at-file-test.py contains file-like sentinels.
g.app.unitTestDict={}
fn = g.os_path_finalize_join(g.app.loadDir,'..','test','unittest','at-file-test.leo')

try:
    c2 = g.openWithFileName(fn,c)
    assert c2
    assert c2.changed,'not changed'
    p2 = g.findNodeAnywhere(c2,'@file at-file-test.py')
    assert p2,'no p2'
    assert p2.isDirty(),'not dirty'
    assert g.app.unitTestDict.get('read-convert'),'not converted'
    ok = True
finally:
    if True: # and ok:
        # Close the frame without prompt.
        g.app.destroyWindow(c2.frame)
        c.setLog()
        c.bodyWantsFocus()
</t>
<t tx="ekr.20101009105124.6195">True (recommended):
    Write "E" attribute bits in &lt;v&gt; elements.
    Leo outlines will record the expansion state of all nodes.

False:
    (Good for files like unitTest.leo)
    Suppress "E" attribute bits in &lt;v&gt; elements.
    Only the ancestors of the presently selected node will
    be expanded when Leo opens an outline.
</t>
<t tx="ekr.20101021205258.6013"></t>
<t tx="ekr.20101220161557.6013"># Some of these tests give warnings.</t>
<t tx="ekr.20101220161557.6014">@language python
@all
</t>
<t tx="ekr.20101220161557.6016"># Some tests are disabled when g.app.isExternalUnitTest is True.
# Using self.skipTest(reason) is now preferred.</t>
<t tx="ekr.20110118082508.3766"># Required when running tests externally
@language plain
@pagewidth 40
@tabwidth 8

c.testManager.runEditCommandTest(p)
</t>
<t tx="ekr.20110118082508.3772">Americans live in the most severe
weather-prone country on Earth. Each
year, Americans cope with an average of
10,000 thunderstorms, 2,500 floods,
1,000 tornadoes, as well as an average
of 6 deadly hurricanes. Potentially
deadly weather impacts every American.
Communities can now rely on the National
Weather Service’s StormReady program to
help them guard against the ravages of
Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?

Last paragraph.
</t>
<t tx="ekr.20110118082508.3773">Americans live in the most severe weather-prone country on Earth. Each year, Americans cope with an average of 10,000 thunderstorms, 2,500 floods, 1,000 tornadoes, as well as an average of 6 deadly hurricanes. Potentially deadly weather impacts every American. Communities can now rely on the National Weather Service’s StormReady program to help them guard against the ravages of Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?

Last paragraph.
</t>
<t tx="ekr.20110118082508.3779"># Required when running tests externally
@language plain
@pagewidth 40
@tabwidth 8

c.testManager.runEditCommandTest(p)
</t>
<t tx="ekr.20110118082508.3780">Americans live in the most severe
weather-prone country on Earth. Each
year, Americans cope with an average of
10,000 thunderstorms, 2,500 floods,
1,000 tornadoes, as well as an average
of 6 deadly hurricanes. Potentially
deadly weather impacts every American.
Communities can now rely on the National
Weather Service’s StormReady program to
help them guard against the ravages of
Mother Nature.

Some 90% of all presidentially declared
disasters are weather related, leading
to around 500 deaths per year and nearly
$14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK,
helps arm America's communities with the
communication and safety skills needed
to save lives and property– before and
during the event. StormReady helps
community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?

Last paragraph.
</t>
<t tx="ekr.20110118082508.3781">Americans live in the most severe
weather-prone country on Earth. Each
year, Americans cope with an average of
10,000 thunderstorms, 2,500 floods,
1,000 tornadoes, as well as an average
of 6 deadly hurricanes. Potentially
deadly weather impacts every American.
Communities can now rely on the National
Weather Service’s StormReady program to
help them guard against the ravages of
Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?

Last paragraph.
</t>
<t tx="ekr.20110118082508.3782">Americans live in the most severe
weather-prone country on Earth. Each
year, Americans cope with an average of
10,000 thunderstorms, 2,500 floods,
1,000 tornadoes, as well as an average
of 6 deadly hurricanes. Potentially
deadly weather impacts every American.
Communities can now rely on the National
Weather Service’s StormReady program to
help them guard against the ravages of
Mother Nature.

Some 90% of all presidentially declared
disasters are weather related, leading
to around 500 deaths per year and nearly
$14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK,
helps arm America's communities with the
communication and safety skills needed
to save lives and property– before and
during the event. StormReady helps
community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?

Last paragraph.
</t>
<t tx="ekr.20110118082508.3787"># Required when running tests externally
@language plain
@pagewidth 40
@tabwidth 8

c.testManager.runEditCommandTest(p)
</t>
<t tx="ekr.20110118082508.3788">Americans live in the most severe
weather-prone country on Earth. Each
year, Americans cope with an average of
10,000 thunderstorms, 2,500 floods,
1,000 tornadoes, as well as an average
of 6 deadly hurricanes. Potentially
deadly weather impacts every American.
Communities can now rely on the National
Weather Service’s StormReady program to
help them guard against the ravages of
Mother Nature.

Some 90% of all presidentially declared
disasters are weather related, leading
to around 500 deaths per year and nearly
$14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK,
helps arm America's communities with the
communication and safety skills needed
to save lives and property– before and
during the event. StormReady helps
community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better
prepared to save lives from the
onslaught of severe weather through
better planning, education, and
awareness. No community is storm proof,
but StormReady can help communities save
lives. Does StormReady make a
difference?

Last paragraph.
</t>
<t tx="ekr.20110118082508.3789">Americans live in the most severe
weather-prone country on Earth. Each
year, Americans cope with an average of
10,000 thunderstorms, 2,500 floods,
1,000 tornadoes, as well as an average
of 6 deadly hurricanes. Potentially
deadly weather impacts every American.
Communities can now rely on the National
Weather Service’s StormReady program to
help them guard against the ravages of
Mother Nature.

Some 90% of all presidentially declared
disasters are weather related, leading
to around 500 deaths per year and nearly
$14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK,
helps arm America's communities with the
communication and safety skills needed
to save lives and property– before and
during the event. StormReady helps
community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?

Last paragraph.
</t>
<t tx="ekr.20110118082508.3790">Americans live in the most severe
weather-prone country on Earth. Each
year, Americans cope with an average of
10,000 thunderstorms, 2,500 floods,
1,000 tornadoes, as well as an average
of 6 deadly hurricanes. Potentially
deadly weather impacts every American.
Communities can now rely on the National
Weather Service’s StormReady program to
help them guard against the ravages of
Mother Nature.

Some 90% of all presidentially declared
disasters are weather related, leading
to around 500 deaths per year and nearly
$14 billion in damage. StormReady, a
program started in 1999 in Tulsa, OK,
helps arm America's communities with the
communication and safety skills needed
to save lives and property– before and
during the event. StormReady helps
community leaders and emergency managers
strengthen local safety programs.

StormReady communities are better
prepared to save lives from the
onslaught of severe weather through
better planning, education, and
awareness. No community is storm proof,
but StormReady can help communities save
lives. Does StormReady make a
difference?

Last paragraph.
</t>
<t tx="ekr.20110118082508.3792">Americans live in the most severe
weather-prone country on Earth. Each
year, Americans cope with an average of
10,000 thunderstorms, 2,500 floods,
1,000 tornadoes, as well as an average
of 6 deadly hurricanes. Potentially
deadly weather impacts every American.
Communities can now rely on the National
Weather Service’s StormReady program to
help them guard against the ravages of
Mother Nature.

Some 90% of all presidentially declared disasters are weather related, leading to around 500 deaths per year and nearly $14 billion in damage. StormReady, a program started in 1999 in Tulsa, OK, helps arm America's communities with the communication and safety skills needed to save lives and property– before and during the event. StormReady helps community leaders and emergency managers strengthen local safety programs.

StormReady communities are better prepared to save lives from the onslaught of severe weather through better planning, education, and awareness. No community is storm proof, but StormReady can help communities save lives. Does StormReady make a difference?

Last paragraph.
</t>
<t tx="ekr.20110521073115.3494"></t>
<t tx="ekr.20110521073115.3495">builtins, including cython builtins
</t>
<t tx="ekr.20110521073115.3496">cython keywords
</t>
<t tx="ekr.20110610122533.3369"></t>
<t tx="ekr.20110610122533.3388"></t>
<t tx="ekr.20110610122533.3389"># Not valid for external tests: uses @&lt;file&gt; node.
if not g.app.isExternalUnitTest:
    root = p.parent().parent()
    h = '@auto unittest/at-auto-line-number-test.py'
    target = g.findNodeAnywhere(c, h)
    assert target, 'no @auto node'
    p, n, found = c.gotoCommands.find_file_line(1, target)
    assert found, 'not found'
    assert n == 1, 'n: %s' % (n)
    assert p.h == 'at_auto_child', p.h
</t>
<t tx="ekr.20110610122533.3390"># Not valid for external tests: uses @&lt;file&gt; node.
if not g.app.isExternalUnitTest:
    h = '@auto unittest/at-auto-line-number-test.py'
    root = g.findNodeAnywhere(c, h)
    assert root, 'no root'
    p, n, found = c.gotoCommands.find_file_line(20, root)
    assert not found, 'not found'
</t>
<t tx="ekr.20110610122533.3391"># Not valid for external tests: uses @&lt;file&gt; node.
if not g.app.isExternalUnitTest:
    h = '@auto unittest/at-auto-line-number-test.py'
    root1 = g.findNodeAnywhere(c, h)
    assert root1
    assert root1.isAnyAtFileNode()
    fileName, isScript, lines, n, root = c.gotoCommands.setup_file(n=3, p=root1)
    assert fileName == h[6:], 'fileName: %s' % (fileName)
    assert root == root1, 'root: %s, root1: %s' % (root and root.h, root1 and root1.h)
    if 0:
        print('root:%s, isRaw:%s, n:%s, len(lines): %s' % (
            root and root.h, isRaw, n, len(lines)))
</t>
<t tx="ekr.20110610122533.3392"># Not valid for external tests: uses @&lt;file&gt; node.
if not g.app.isExternalUnitTest:
    h = '@auto unittest/at-auto-line-number-test.py'
    root1 = g.findNodeAnywhere(c, h)
    assert root1
    assert root1.isAnyAtFileNode()
    scriptData = {'p': root1.copy(), 'lines': ['a', 'b', 'c']}
    fileName, lines2, p2, root2 = c.gotoCommands.setup_script(scriptData)
    assert fileName == h[6:], 'fileName'
    assert lines2 == scriptData.get('lines'), 'lines'
    assert p2 == root1, 'p'
    assert root2 == root1, 'root'
    if 0:
        print('root:%s, n:%s, len(lines): %s' % (
            root and root.h, n, len(lines)))
</t>
<t tx="ekr.20110610122533.3394"># Not valid for external tests: uses @&lt;file&gt; node.
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    root = p.parent().parent()
    h = '@file unittest/at-file-line-number-test.py'
    target = g.findNodeAnywhere(c, h)
    assert target, 'no target'
    gnx = target.v.fileIndex
    assert gnx
    found = c.gotoCommands.find_gnx(root, gnx, h)
    assert found, 'not found'
</t>
<t tx="ekr.20110610122533.3395"># Not valid for external tests: uses @&lt;file&gt; node.
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    trace = False
    root = p.parent().parent()
    h = '@file unittest/at-file-line-number-test.py'
    target = g.findNodeAnywhere(c, h)
    assert target, 'no target'
    s = c.gotoCommands.get_external_file_with_sentinels(target)
    if trace:
        g.cls()
        print(''.join(['%3s %s' % (i, s) for i, s in enumerate(g.splitLines(s))]))
    for n in range(20):
        p, offset, found = c.gotoCommands.find_file_line(n, p=target)
        if found:
            if trace: print('found %2s %2s %s' % (n, offset, p and p.h))
        else:
            assert n == 10, n
            if trace: print('not found: %s' % n)
            break
</t>
<t tx="ekr.20110610122533.3397"># Not valid for external tests: uses @&lt;file&gt; node.
if not g.app.isExternalUnitTest:

    h = '@shadow unittest/at-shadow-line-number-test.py'
    root1 = g.findNodeAnywhere(c,h)
    assert root1
    assert root1.isAnyAtFileNode()
    
    fileName,lines,n,root2 = c.GoToLineNumber(c).setup_file(n=6,p=root1)
    assert fileName == h[8:],'fileName'
    assert root2 == root1
    
    if 0:
        print('root:%s, isRaw:%s, n:%s, len(lines): %s' % (
            root and root.h,isRaw,n,len(lines)))
</t>
<t tx="ekr.20110610122533.3399"># Not valid for external tests: uses @&lt;file&gt; node.
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    trace = False
    h = '@nosent unittest/at-nosent-line-number-test.py'
    root = g.findNodeAnywhere(c, h)
    assert root
    assert root.isAtNoSentFileNode(), root
    s = c.gotoCommands.get_external_file_with_sentinels(root)
    if trace:
        g.cls()
        print(''.join(['%3s %s' % (i, s) for i, s in enumerate(g.splitLines(s))]))
    for n in range(20):
        p, offset, found = c.gotoCommands.find_file_line(n, p=root)
        if found:
            if trace: print('found: %2s %2s %s' % (n, offset, p and p.h))
        else:
            if trace: print('not found: %s' % n)
            assert n == 7, n
            break
</t>
<t tx="ekr.20110610122533.3401"># Not valid for external tests: uses @&lt;file&gt; node.
if not g.app.isExternalUnitTest:
    root = p.parent().parent()
    h = '@auto unittest/at-auto-line-number-test.py'
    target = g.findNodeAnywhere(c, h)
    assert target, 'no target'
    child = target.firstChild()
    assert child.h == 'at_auto_child', 'child.h'
    p, found = c.gotoCommands.find_root(child)
    assert p == target, 'p' #p and p.h
    assert found, 'not found'
</t>
<t tx="ekr.20110610122533.3404">c.gotoCommands.success(lines=['a', 'b'], n=3, n2=3, p=p)
c.gotoCommands.fail(lines=['a', 'b'], n=3, root=p)

</t>
<t tx="ekr.20110610122533.3405"># This is **not** a real unit test.
# It simply restores the screen to a more convenient state.
c.contractParent()
g.app.unitTestDict['restoreSelectedNode'] = False
</t>
<t tx="ekr.20110610122533.3406"># Not valid for external tests: uses @&lt;file&gt; node.
if not g.app.isExternalUnitTest:
    fn = '../test/at-auto-unit-test.py'
    root = g.findNodeAnywhere(c, '@auto %s' % (fn))
    assert root, 'no root'
    child1 = root.firstChild()
    assert child1, 'no child1'
    grand11 = child1.firstChild()
    assert grand11, 'no grand11'
    grand12 = grand11.next()
    assert grand12, 'no grand12'
    child2 = child1.next()
    assert child2, 'no child2'
    grand21 = child2.firstChild()
    assert grand21, 'no grand21'
    grand22 = grand21.next()
    assert grand22, 'no grand22'

    def oops(found, p2, node, n, n2):
        result = [' ']
        result.append('goto-global-line test failed at line %s' % (n))
        if not found:
            result.append('line %s not found', n)
        else:
            result.append('got node "%s", expected "%s"' % (p2.h, node.h))
            result.append('got offset %s, expected %s' % (n2, n))
        return '\n'.join(result)

    table = (
        # Use 1-based numbers externally.
        # find_file_line converts to zero-based numbers.
        (1, child1, 0),
        (2, grand11, 0),
        (3, grand11, 1),
        (4, grand12, 0),
        (5, grand12, 1),
        (6, child1, 2),
        (7, child2, 0),
        (8, grand21, 0),
        (9, grand21, 1),
        (10, grand22, 0),
        (11, grand22, 1),
        (12, root, 3),
    )
    # Test against actual lines of the file.
    path = g.os_path_finalize_join(g.app.loadDir, '..', 'test', fn)
    f = open(path, 'r'); s = f.read(); f.close()
    lines = g.splitLines(s) # The lines from the file.
    for n, node, index in table:
        p2, n2, found = c.gotoCommands.find_file_line(n, root)
            # n, the argument to find_file_line, is 1-based
            # n2, the returned index into p2.b, is zero-based
        n -= 1
            # Convert n to zero-based for the comparisons below.
        lines2 = g.splitLines(p2.b)
        if 0:
            print('%2d %s' % (n, repr(lines[n])))
        else:
            ok = lines2[n2].lstrip() == lines[n].lstrip()
            if not ok:
                i = 0
                for z in lines:
                    print('%2d %s' % (i, repr(z)))
                    i += 1
            if not ok:
                print('at line %s, index %s, node %s\ngot line %s\nexpected %s' % (
                    n, n2, p2.h, repr(lines2[n2].lstrip()), repr(lines[n].lstrip())))
            assert ok
</t>
<t tx="ekr.20110615130436.3317"># This was used by @test writing a .leo file retains orphan bits.
# but this test is moot because Leo no longer writes orphan bits.</t>
<t tx="ekr.20110615130436.3319"># Not valid for external tests: uses @&lt;file&gt; node.
if not g.app.isExternalUnitTest:
    
    # Writing a .leo file must retain orphan bits of erroneous external files.
    
    h = '@file nonexistent-directory/orphan-bit-test.txt'
    p2 = g.findNodeAnywhere(c,h)
    assert p2,'not found: %s' % (h)
    assert p2.isOrphan(),'not an orphan originally'
    
    # It's dangerous to do the write, but this does test the bug fix.
    c.atFileCommands.clearAllOrphanBits(p2)
    assert p2.isOrphan(),'not an orphan after calling at.clearAllOrphanBits'
</t>
<t tx="ekr.20110728154927.3324"># Disabled because very slow
aList = [z.copy() for z in c.all_positions()]

total = 0

for i in range(len(aList)):
    for j in range(0,i):
        assert aList[j] &lt; aList[i],(i,j)
        total += 1

g.es('"%s": total tests: %s' % (p.h,total))
</t>
<t tx="ekr.20111006064419.3493">if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:

    exec(g.findTestScript(c,'@common x-marked-nodes test code'))
    
    def test(p):
        setup_test(p)
        c.moveMarked()
        root = c.rootPosition()
        assert root.h == 'Moved marked nodes',root.h
        n = p.numberOfChildren()
        assert n == 2 ,'delete: children: %s' % (n)
        c.undoer.undo()
        n = p.numberOfChildren()
        assert n == 4,'undo: children: %s' % (n)
        c.undoer.redo()
        n = p.numberOfChildren()
        assert n == 2 ,'delete: children: %s' % (n)
    
    try:
        test(p)
    finally:
        tear_down(p,'Moved marked nodes')
</t>
<t tx="ekr.20111026111009.3972"># lowercase xml tags, one per line.

html
body
head
div
table
nodeA
nodeB
</t>
<t tx="ekr.20111107113442.3849"></t>
<t tx="ekr.20111108170253.3968">@first # -*- coding: utf-8 -*-

table = (
    'test',
    'Ä 궯 奠',
    'Ä 궯 奠 after', # fails with cp6501: after is duplicated.
)

print('*'*20)
print('isPython3: %s' % g.isPython3)

for s in table:
    if g.isPython3:
        s = s.encode('ascii','replace') # create bytes.
    g.es(repr(s))
    g.es(s)
    g.pr ('g.pr(s)       : %s' % s)
    g.pr ('g.pr(repr(s)) : %s' % repr(s))
    print('print(s)      : %s' % s)
    print('print(repr(s)): %s' % s)
</t>
<t tx="ekr.20111112092813.4154">g.cls()</t>
<t tx="ekr.20111112093605.4679"># leoSettings.leo no longer sets any bindings for run-xxx-unit-test.
# These are now EKR's preferred settings everywhere:
# there should be little need to run unit tests externally.

run-selected-unit-tests-locally     = Alt-4
run-marked-unit-tests-locally       = Alt-5
run-all-unit-tests-locally          = Alt-6

# Important: Alt-9 is used by a unit test
</t>
<t tx="ekr.20111112171235.3854">w = c.frame.body.wrapper
p = g.findNodeInTree(c,p,'html')
assert p,'no test node'
s = p.b
indent = c.config.getBool('indent_added_comments',default=True)
try:
    i = p.b.find('text')
    assert i &gt; -1,'fail1: %s' % (repr(p.b))
    c.selectPosition(p)
    w.setSelectionRange(i,i+4)
    c.addComments()
    if indent:
        i = p.b.find('&lt;!-- text')
    else:
        i = p.b.find('&lt;!--     text')
    assert i &gt; -1,'fail2: %s' % (repr(p.b))
    c.deleteComments()
    assert p.b == s,'fail3: s\n%s\nresult\n%s' % (repr(s),repr(p.b))
    # Add a comment delim without a blank.
    c.addComments()
    p.b = p.b.replace('&lt;!-- ','&lt;!--')
    i = p.b.find('&lt;!--')
    w.setSelectionRange(i,i+4)
    c.deleteComments()
    assert p.b == s,'fail5: s\n%s\nresult\n%s' % (repr(s),repr(p.b))
finally:
    # print('\n'.join([repr(z) for z in g.splitLines(p.b)]))
    p.b = s
</t>
<t tx="ekr.20111112171235.3855">@language html
&lt;html&gt;
    text 
&lt;/html&gt;
</t>
<t tx="ekr.20111112171235.3858"># Can't be run externally.
w = c.frame.body.wrapper
p = g.findNodeInTree(c,p,'python')
assert p,'no test node'
s = p.b
indent = c.config.getBool('indent_added_comments',default=True)

try:
    i = p.b.find('pass')
    assert i &gt; -1,'fail1: %s' % (repr(p.b))
    c.selectPosition(p)
    w.setSelectionRange(i,i+4)
    c.addComments()
    if indent:
        i = p.b.find('# pass')
    else:
        i = p.b.find('#     pass')
    assert i &gt; -1,'fail2: %s' % (repr(p.b))
    c.deleteComments()
    assert p.b == s,'fail3: %s' % (repr(p.b))
    # Add a comment delim without a blank.
    c.addComments()
    p.b = p.b.replace('# pass','#pass')
    i = p.b.find('#')
    w.setSelectionRange(i,i+4)
    c.deleteComments()
    assert p.b == s,'fail5: s\n%s\nresult\n%s' % (repr(s),repr(p.b))
finally:
    # print('\n'.join([repr(z) for z in g.splitLines(p.b)]))
    p.b = s
</t>
<t tx="ekr.20111112171235.3859">@language python

def spam():
    pass

# after
</t>
<t tx="ekr.20111112193817.3908">if 0:
    # This works, but the label sticks, presumably because of a race condition.
    # Therefore, this is best left as a mini-test.

    w = c.frame.body
    for i in range(4):
        print(i)
        w.addEditor()
        w.deleteEditor()
</t>
<t tx="ekr.20111112211307.3910"># created by old and new add-comments.
</t>
<t tx="ekr.20111112211307.3911">@language python

def deleteCommentTest():

#     if 1:
#         a = 2
#         b = 3

    # if 1:
        # a = 2
        # b = 3

    pass
</t>
<t tx="ekr.20111112211307.3912">@language python

def deleteCommentTest():

    if 1:
        a = 2
        b = 3

    if 1:
        a = 2
        b = 3

    pass
</t>
<t tx="ekr.20111112211307.3913">5.0
12.8
</t>
<t tx="ekr.20111113194727.3869">import leo.core.leoFrame as leoFrame

w = leoFrame.BaseTextWrapper(c,'base-name','class-name',widget=None)

def check(expected):
    s = w.getAllText()
    assert s == expected,'expected %s got %s' % (expected,s)

w.setAllText('')        ; check('')
w.appendText('abc')     ; check('abc')
w.delete(1,2)           ; check('ac')
w.insert(0,'xy')        ; check('xyac')
w.insert(1,'z')         ; check('xzyac')
    # w.replace(2,4,'ABCD') ; check('xzABCDc')
        # This method no longer exists.  It is not used anywhere.
    # w.setSelectionRange(3,6)
    # s = w.getSelectedText()
    # assert s == 'BCD',repr(s)

w.deleteTextSelection() ; check('xzyac')
</t>
<t tx="ekr.20111115080347.3872"></t>
<t tx="ekr.20111121081052.3909">if g.app.isExternalUnitTest:
    pass # Prints to console, which is annoying.
else:
    old_focus = c.get_focus()
    
    for flag in (False,True):
        g.es('Hi')
        
    if flag:
        c.outerUpdate() # Restores focus, especially when run from a script.
    new_focus = c.get_focus()
    
    try:
        assert old_focus == new_focus,'old focus: %s new focus: %s' % (
            old_focus,new_focus)
    except AssertionError:
        c.bodyWantsFocusNow()
</t>
<t tx="ekr.20111121090700.3914">if g.app.isExternalUnitTest:
    pass
else:
    c.k.simulateCommand('print-bindings')
    log = c.frame.log
    
    # This works when run via execute-script.
    assert log.tabName == 'Bindings',log.tabName
    
    # w = c.frame.log.contentsDict.get('Bindings')
    # assert w,'no Bindings widget'
    # wrapper = w.leo_log_wrapper
    # s = wrapper.getAllText()
    # assert s,wrapper
</t>
<t tx="ekr.20111121113227.4035">c.k.simulateCommand('add-editor')
c.k.simulateCommand('delete-editor')
</t>
<t tx="ekr.20111123042627.6654"># Leo loads plugins in the order they appear here.

# **Important**: to change these defaults, put
# an @enabled-plugins node in myLeoSettings.leo.

# Highly-recommended plugins:
plugins_menu.py
free_layout.py # needs to be early
viewrendered.py

# Recommended plugins:
### contextmenu.py
# leo_to_html.py
mod_scripting.py
# nav_qt.py
# quicksearch.py
# stickynotes.py
# todo.py
</t>
<t tx="ekr.20111124094121.3941"># These exist for a unit test.</t>
<t tx="ekr.20111124094121.3942"></t>
<t tx="ekr.20111124094121.3943"></t>
<t tx="ekr.20111125182408.3947">def setup():
    while p.hasChildren():
        p.firstChild().doDelete()

setup()

try:
    files = (r'a\b.c',r'a\b.h',)
    c.importCommands.createImportParent(p,files)
    child = p.firstChild()
    assert child
    assert child.h == 'a/b',child.h
finally:
    setup()</t>
<t tx="ekr.20111125183140.3952">child = p.firstChild()
def setup():
    while p.hasChildren():
        p.firstChild().doDelete()

setup()
try:
    c.importCommands.createOutline(
        fileName=r'a\b\c.xyzzy',
        parent=p,
        atAuto=False,atShadow=False,
        s='test body',
        ext='xyzzy'
    )
    child = p.firstChild()
    assert child
    h = g.os_path_finalize_join(g.app.loadDir,'..','test','a','b','c.xyzzy')
    h = h.replace('\\','/')
    h = '@file ' + h
    # C: vs c: is not relevant here.
    assert child.h.lower() == h.lower(),child.h
finally:
    setup()</t>
<t tx="ekr.20111210175541.3957"># Important: the child of this node must be a clone of
# the corresponding node in @shadow unittest/at-shadow-unlink-clones.py

# The @shadow node will not exist for an external test.
if not g.app.isExternalUnitTest:
    try:
        # print('start',p.h)
        b = c.undoer.beforeChangeTree(p)
        h = '@shadow unittest/at-shadow-unlink-clones.py'
        root = g.findNodeAnywhere(c,h)
        assert root
        assert root.h == h,repr(root.h)
        child = p.firstChild()
        assert child
        assert child.isCloned(),'fail 1: test not set up properly'
        c.selectPosition(root)
        fn = root.atShadowFileNodeName()
        assert fn
        c.atFileCommands.readOneAtShadowNode (fn,root,force=True)
        c.undoer.afterChangeTree(p,'fc.readOneAtShadowNode',b)
        assert child.isCloned(),'fail 2: intended test fails'
        c.undoer.undo()
    finally:
        c.selectPosition(p)
        c.redraw()
</t>
<t tx="ekr.20111211094936.3970"></t>
<t tx="ekr.20111213122041.3930">@language python
@tabwidth -4

# Begin

@others

# End
</t>
<t tx="ekr.20120228174052.3929"># node 1 text A.
</t>
<t tx="ekr.20120310121839.3949"># Not valid when run externally: the chapter node will not exist.
if not g.app.isExternalUnitTest:

    p1 = g.findNodeAnywhere(c,'@chapter aaa')
    assert p1
    p2 = g.findNodeAnywhere(c,'aaa node 1')
    assert p2
    try:
        # g.es_print('**1**', c.hoistStack)
        assert not c.hoistStack, ('fail1', c.hoistStack)
        c.selectPosition(p1)
        assert c.p == p1, ('fail2', c.p, p1)
        c.hoist()
            # New in Leo 5.3: should do nothing
        assert c.p == p1, ('fail3', c.p, p1)
        # assert c.p == p2, ('fail3', c.p, p2)
        c.dehoist()
            # New in Leo 5.3: should do nothing:
        assert c.p == p1, ('fail3', c.p, p1)
        # assert c.p == p2, 'fail4\n%s\n%s' % (c.p, p2)
        assert c.hoistStack == [], ('fail5', c.hoistStack)
    finally:
        c.hoistStack = []
        c.selectPosition(p)
        c.redraw()
else:
    self.skipTest('Can not be run locally')
</t>
<t tx="ekr.20130503061511.4137">import leo.core.leoImport as leoImport
ic = c.importCommands
hs = leoImport.HtmlScanner(importCommands=ic,atAuto=True)

s1 = '''
&lt;table id="1"&gt; &lt;table id="2"&gt;
&lt;contents/&gt;
&lt;/table&gt;
&lt;/table&gt;
'''

s2 = '''
&lt;table id="1"&gt; 
&lt;table id="2"&gt;
&lt;contents/&gt;
&lt;/table&gt;
&lt;/table&gt;
'''

t1 = 
assert result == expected,'expected...\n%s\ngot...\n%s' % (
    repr(expected),repr(result))
</t>
<t tx="ekr.20130503061511.4140">s = '''\
&lt;HTML&gt;
&lt;head&gt;
    &lt;title&gt;Bodystring&lt;/title&gt;
&lt;/head&gt;
&lt;body class='bodystring'&gt;
&lt;div id='bodydisplay'&gt;&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
'''

html_tags = ('body','head','html','table',) # 'div',
setting = 'import_html_tags'

# Settings now work when run externally.
c.config.set(setting,'data',html_tags)
tags = c.config.getData(setting)
assert tags == html_tags,len(tags)

g.app.unitTestDict ['expectedErrors'] = 0

showTree = True

c.importCommands.htmlUnitTest(p,s=s,showTree=showTree)

if showTree:
    # g.cls()
    for p in p.subtree():
        print('\n***** %s\n' %p.h)
        print(p.b)
</t>
<t tx="ekr.20130503061511.4141">@language xml
@tabwidth -4
@others

</t>
<t tx="ekr.20130503061511.4145">@language xml
@tabwidth -4
@others

</t>
<t tx="ekr.20130503061511.4149">@language xml
@tabwidth -4
@others

</t>
<t tx="ekr.20130503061511.4150">&lt;HTML&gt;
@others
&lt;/html&gt;
</t>
<t tx="ekr.20130503061511.4151">
&lt;head&gt;
    &lt;title&gt;Bodystring&lt;/title&gt;
&lt;/head&gt;
</t>
<t tx="ekr.20130503061511.4152">&lt;body class='bodystring'&gt;
&lt;div id='bodydisplay'&gt;&lt;/div&gt;
&lt;/body&gt;
</t>
<t tx="ekr.20130503061511.4153">import leo.core.leoImport as leoImport
ic = c.importCommands
hs = leoImport.HtmlScanner(importCommands=ic,atAuto=True)
strip = hs.stripTokens
dump  = hs.formatTokens

s1 = '''&lt;table id="1"&gt;&lt;table id="2"&gt;
&lt;contents/&gt;
&lt;/table&gt;
&lt;/table&gt;'''

s2 = '&lt;table id="1"&gt;&lt;table id="2"&gt;&lt;contents/&gt;&lt;/table&gt;&lt;/table&gt;'
    
t1 = hs.tokenize(s1)
t2 = hs.tokenize(s2)
f1 = hs.filterTokens(t1)
f2 = hs.filterTokens(t2)

assert strip(f1) == strip(f2),'f1...\n%s\nf2...\n%s' % (
    dump(f1),dump(f2))
    
if 0:
    print(dump(f1))
</t>
<t tx="ekr.20130503061511.4154">fn = r'c:\recent\data.html'

# fn = r'c:\recent\data-smaller.html'
# fn = r'c:\recent\data666.html'

# These all pass on data.html:
    # html_tags = ('html','head','body',)
    # html_tags = ('html','head','body','table',)
    # html_tags = ('html','head','body','table','div',)
    # html_tags = ('html','head','body','table','div','script',)
    # html_tags = ('html','head','body','table','div','script','link',)
    # html_tags = ('html','head','body','table','div','script','link','p',)

html_tags = ('html','head','body','table','div','script','p','td','tr',)

# Settings now work when run externally.
setting = 'import_html_tags'
c.config.set(setting,'data',html_tags)
tags = c.config.getData(setting)
assert tags == html_tags,len(tags)

g.cls()

c.importCommands.importFilesCommand(files=[fn], treeType='@file')
</t>
<t tx="ekr.20130503061511.4155">@first # -*- coding: utf-8 -*-

table = (
    'test',
    'Ä 궯 奠',
    'Ä 궯 奠 after', # fails with cp6501: after is duplicated.
)

print('*'*20)
print('isPython3: %s' % g.isPython3)

for s in table:
    if g.isPython3:
        s = s.encode('ascii','replace') # create bytes.
    g.es(repr(s))
    g.es(s)
    g.pr ('g.pr(s)       : %s' % s)
    g.pr ('g.pr(repr(s)) : %s' % repr(s))
    print('print(s)      : %s' % s)
    print('print(repr(s)): %s' % s)
</t>
<t tx="ekr.20130503061511.4156">assert g.app.isExternalUnitTest

body = c.frame.body
assert repr(body.widget).startswith('stringTextWidget')
assert body.widget == body.bodyCtrl

w = body.bodyCtrl
w.setAllText(p.b)
assert p.b == w.getAllText()
</t>
<t tx="ekr.20130503061511.4157"># print('isExternalUnitTest',g.app.isExternalUnitTest)

if g.app.isExternalUnitTest:
    body = c.frame.body
else:
    import leo.core.leoCommands as leoCommands
    import leo.core.leoFrame as leoFrame
    import leo.core.leoGui as leoGui
    
    # Important: external unit tests should execute in this environment.
    nullGui   = leoGui.NullGui('null gui')
    nullFrame = leoFrame.NullFrame(title='nullFrame title',gui=nullGui)
    c2 = leoCommands.Commands(nullFrame,fileName='&lt;empty fileName&gt;')
    nullFrame.c = c2
    body = leoFrame.nullBody(frame=nullFrame,parentFrame=None)
    assert repr(body).startswith('&lt;leo.core.leoFrame.nullBody')

# Now test some basic operations.
assert repr(body.widget).startswith('stringTextWidget')
assert body.widget == body.bodyCtrl
w = body.bodyCtrl

w.setAllText(p.b)
assert p.b == w.getAllText()
</t>
<t tx="ekr.20130503061511.4158"># h = 'g.python_tokenize'
# p = p.firstChild()
# assert p.h == h
tokens = g.python_tokenize(p.b,line_numbers=False)

# tokens = [(kind,val) for (kind,val,line_number) in tokens]

# First, the basic check
tokens1 = [val for kind,val in tokens]
s = ''.join(tokens1)
assert p.b == s,repr(s)

if 0:
    for z in tokens:
        kind,val = z
        print('%6s %s' % (kind,repr(val)))
        
# Next, start filtering.
tokens = [(kind,g.choose(kind=='string','"S"',val)) for kind,val in tokens]

if 0: # Delete whitespace.
    tokens = [(kind,val) for (kind,val) in tokens if kind != 'ws']
    tokens = [(kind,g.choose(kind=='id',val+' ',val)) for (kind,val) in tokens]

# Last: stringize.
tokens = [val for kind,val in tokens if kind != 'comment']
# print(''.join(tokens))

if 0: # Print lines containing '='
    s = ''.join(tokens)
    for ch in '()[]{}&lt;&gt;.,:=+-/':
        s = s.replace(' '+ch,ch)
    aList = [z for z in g.splitLines(s)
        if z.find('=') &gt; -1] # and not z.find('+=')&gt;-1 and not z.find('-=')&gt;-1]
    print(''.join(aList))
    
</t>
<t tx="ekr.20130503061511.4175"></t>
<t tx="ekr.20130503061511.4176"></t>
<t tx="ekr.20130503061511.4177">def printMenusList(aList,level=0):
    
    for z in aList:
        a,b,c = z
        print('*** kind',a)
        if type(b) in (type(()),type([])):
            for z2 in b:
                a1,b1,c1 = z2
                if a1.startswith('@menu') and type(b1) in (type(()),type([])):
                    print()
                    print('*** inner menu: %s' % (level+1))
                    print(a1)
                    for z3 in b1:
                        print(z3)
                    if c1: print(c1)
                else:
                    print(z2)
            if c: print(c)
        else:
            print(b)
        print()
        break #
        
printMenusList(c.config.getMenusList())
       
</t>
<t tx="ekr.20130503061511.4178">print('\ninverseBindingDict...\n')

d = c.k.computeInverseBindingDict()

for key in sorted(list(d.keys())):

    if 1 == len(d.get(key)):
        print(key,d.get(key))
    else:
        print()
        print(key)
        print(d.get(key))
        print()
</t>
<t tx="ekr.20130503061511.4179">import leo.core.leoConfig as leoConfig # for ShortcutInfo
    
partial = True

d = c.k.bindingsDict
    # Keys are shortcuts; values are *lists* leoConfig.ShortcutInfo objects.
    
print('\nk.bindingsDict%s...\n' % ' (partial)' if partial else '')
    
for key in list(sorted(d.keys())):
    aList = d.get(key,[])
    for b in aList:
        assert isinstance(b,leoConfig.ShortcutInfo)
        if not partial or b.kind != 'leosettings.leo':
            print(b)
</t>
<t tx="ekr.20130503061511.4180">partial = True

panes = ('all','body','button','log','tree','text',
    'command','insert','overwrite',)

d = c.k.masterBindingsDict
    # Keys are scope names (in panes) or mode names.
    # Values are dicts:
        # keys are strokes; values are leoConfig.ShortcutInfo objects.
        
print('\nk.masterBindingsDict%s...\n' % ' (partial)' if partial else '')

for pane in sorted(list(d.keys())):
    kind = 'pane' if pane in panes else 'mode'
    print('%s: %s...' % (kind,pane))
    d2 = d.get(pane)
    for stroke in sorted(list(d2.keys())):
        b = d2.get(stroke)
        if not partial or b.kind != 'leosettings.leo':
            print('%6s %25s %17s %s' % (b.pane,stroke,b.kind,b.commandName))
            assert b.pane == pane
            assert b.stroke == stroke
    print()
</t>
<t tx="ekr.20130503061511.4181"></t>
<t tx="ekr.20130503061511.4182">@

g.app.config.modeCommandsDict
    Keys are command names: enter-x-mode.
    Values are inner dictionaries:
        Keys are command names, values are lists of ShortcutInfo nodes.
@c

d = g.app.config.modeCommandsDict
    
for key in sorted(d.keys()):
    print('*** mode ***',key)
    d2 = d.get(key)
    for key2 in sorted(d2.keys()):
        aList = d2.get(key2)
        print(key2)
        for si in aList:
            print('   ',si)
</t>
<t tx="ekr.20130503061511.4183">@
ivar                    Keys                Values
----                    ----                ------
c.commandsDict          command names (1)   functions
k.inverseCommandsDict   func.__name__       command names
k.bindingsDict          shortcuts           list of ShortcutInfo objects
k.masterBindingsDict    scope names (2)     inner masterBindingDicts (3)
k.masterGuiBindingsDict strokes             list of widgets in which stoke is bound
k.settingsNameDict (4)  settings.lower()    "Real" Tk specifiers
inverseBindingDict (5)  command names       lists of tuples (pane,key)
modeCommandsDict (6)    command name (7)    inner modeCommandsDicts (8)

Notes:
(1) Command names are minibuffer names (strings)
(2) Scope names are 'all','text',etc.
(3) inner masterBindingDicts: Keys are strokes; values are ShortcutInfo objects.
(4) k.settingsNameDict has no inverse.
(5) inverseBindingDict is **not** an ivar: it is computed by k.computeInverseBindingDict.
(6) A global dict: g.app.gui.modeCommandsDict
(7) enter-x-command
(8) Keys are command names, values are lists of ShortcutInfo objects.
@c

si_type = c.k.ShortcutInfo
disabled_func_type = None # Should be any bound method.
k = c.k

@others

test_dict_of_objects(c.commandsDict,type('s'),disabled_func_type,'commandsDict')
test_dict_of_objects(k.inverseCommandsDict,type('s'),type('s'),'inverseCommandsDict')
test_dict_of_lists(k.bindingsDict,si_type,'bindingsDict')
test_dict_of_dicts(k.masterBindingsDict,si_type,'masterBindingsDict')
test_dict_of_lists(k.masterGuiBindingsDict,None,'masterGuiBindingsDict')
test_dict_of_objects(k.settingsNameDict,type('s'),type('s'),'settingsNameDict')
test_dict_of_lists(k.computeInverseBindingDict(),type(tuple()),'inverseBindingDict')

# Test individual dicts separately.
d = g.app.config.modeCommandsDict
test_dict_of_dicts(d,None,'modeCommandsDict')
for key in sorted(d.keys()):
    d2 = d.get(key)
    test_dict_of_lists(d2,si_type,'inner modeCommandsDict')
        # This requires a hack to special-case the
        # '*entry-commands*' and '*command-prompt*' keys.
</t>
<t tx="ekr.20130503061511.4184">def test_dict_of_dicts(d,theType,tag):

    assert d,tag

    for key in d.keys():
        d2 = d.get(key)
        assert type(d2) == type({})
        for key in d2.keys():
            obj = d2.get(key)
            if theType:
                assert type(obj) == theType,repr(obj)
</t>
<t tx="ekr.20130503061511.4185">def test_dict_of_lists(d,theType,tag):

    assert d,tag

    for key in d.keys():
        obj = d.get(key)
        if key in ('*entry-commands*','*command-prompt*'):
            # Special case for g.app.config.modeCommandsDict
            assert type(obj)==type([]),repr(obj)
        else:
            assert type(obj) == type([])
            # Don't check types of list elements if theType is None.
            if theType:
                for z in obj:
                    assert type(z)==theType,'key: %s obj: %s' % (key,repr(obj))
</t>
<t tx="ekr.20130503061511.4186">def test_dict_of_objects(d,keyType,valueType,tag):

    assert d,tag

    for key in d.keys():
        assert type(key) == keyType,repr(key)
        obj = d.get(key)
        # Don't check type of obj if valueType is None.
        if valueType:
            assert type(obj) == valueType,'\nobj: %s\nvalueType: %s' % (repr(obj),valueType)
</t>
<t tx="ekr.20130503061511.4187"># import types
# types.ListType does not exist in Python 3.x.
# assert isinstance(aList,list().__class__)
</t>
<t tx="ekr.20130503061511.4188">@others

# import os ; os.system('cls')
    
d1 = g.app.config.immutable_leo_settings_shortcuts_dict
d2 = g.app.config.immutable_my_leo_settings_shortcuts_dict
d3 = g.app.config.merge_settings_dicts(d1,d2)

if False:
    patterns = (
        'backward-find-character-extend-selection',
    )
    for pattern in patterns:
        print(dump_dict(d1,pattern,tag='d1'))
        print(dump_dict(d2,pattern,tag='d2'))
        print(dump_dict(d3,pattern,tag='d3'))

test(d1,d2,d3)
</t>
<t tx="ekr.20130503061511.4189">def dump(aList,pattern=None,tag=None):
    
    return '\n'.join([repr(z) for z in aList])
    

def dump_dict(d,pattern=None,tag=None):
    
    result = [] # '\ndump of %s...' % (tag)
    
    for key in d.keys():
        if pattern in (key,None):
            result.append(key)
            aList = d.get(key)
            for z in aList:
                result.append('    %s' % (z))
                
    return '\n'.join(result)
</t>
<t tx="ekr.20130503061511.4190">def test(old_d,new_d,result_d):
    
    '''Test that result_d is the result of upating old_d with new_d.
    
    This test is tricky: only inverted dicts have ShortcutInfo nodes as keys.'''
    
    invert,uninvert = g.app.config.invert,g.app.config.uninvert

    # Compute the inversions of all the dicts.
    inv_old,inv_new,inv_res = invert(old_d),invert(new_d),invert(result_d)
    
    # Part 1: Ensure we test all keys.
    keys = list(inv_old.keys())
    keys.extend(list(inv_new.keys()))
    keys.extend(list(inv_res.keys()))
    keys = sorted(list(set(keys)))
    assert None not in keys
    for key in inv_old.keys(): assert key in keys,key
    for key in inv_new.keys(): assert key in keys,key
    for key in inv_res.keys(): assert key in keys,key
    
    # Part 2: Carefully test the inverted result.
    def si_name_key(si): return si.commandName or ''

    for key in keys:
        # Compute the *sorted* list of 
        res_list = sorted(inv_res.get(key,[]),key=si_name_key)
        old_list = sorted(inv_old.get(key,[]),key=si_name_key)
        new_list = sorted(inv_new.get(key,[]),key=si_name_key)
        assert res_list,'no res_list.get(%s)' % (key)
        # if new_list: print(key,dump(new_list))
        if new_list:
            assert new_list == res_list,'key %s\nnew:\n%s\nres:\n%s' % (
                key,dump(new_list),dump(res_list))
        else:
            assert old_list == res_list,'key %s\nold:\n%s\nres:\n%s' % (
                key,dump(old_list),dump(res_list))
    
    # Part 3: Test that result_d == uninvert(invert(result_d)).
    # A.  They must have the same keys.
    unv_res = uninvert(inv_res)
    assert sorted(list(result_d.keys())) == sorted(list(unv_res.keys()))

    # B. The values of for each key must match after being sorted.
    def si_stroke_key(si): return si.stroke or ''
        
    for key in sorted(result_d.keys()):
        res_list = sorted(result_d.get(key,[]),key=si_stroke_key)
        unv_list = sorted( unv_res.get(key,[]),key=si_stroke_key)
        assert res_list == unv_list,'key %s\nres:\n%s\nunv:\n%s' % (
            key,dump(res_list),dump(unv_list))
   
</t>
<t tx="ekr.20130503061511.4191">ks = c.k.KeyStroke

@others

a1 = ks('a')
a2 = ks('a')
b1 = ks('b')
assert a1 == a2
d = {}
d[a1] = a1.s
d[a2] = a2.s
d[b1] = b1.s

for key in sorted(d):
    print(key,d.get(key))
</t>
<t tx="ekr.20130503061511.4192">d = g.TypedDictOfLists('ks',type('s'),type(9))
d.add('a',1)
d.add('a',2)
d.add('b',3)

print(d)
for s in sorted(d.keys()):
    print(s,d.get(s,[]))

print('after replace...')
d.replace('a',[8,9,10])

for s in sorted(d.keys()):
    print(s,d.get(s,[]))
</t>
<t tx="ekr.20130503061820.4189">import leo.core.leoInspect as inspect

# g.cls()

testing = g.unitTesting

def show(o,indent=0):
    pad = ' '*4*indent
    if not testing:
        # print('\n%s\n' % o.sd.dump_ast(o.tree()))
        print('%s%s' % (pad,o.format()))
        print('token range: %s' % (repr(o.token_range())))

&lt;&lt; define s &gt;&gt;
if not testing:
    print('Input...\n%s\n' % (s.rstrip()))

m = inspect.module(s=s)

if 0:
    show(m,0)
    
if 1:
    if not testing: print('\nAssignments to a...\n')
    for o in m.assignments_to('a'):
        # print(o.format())
        show(o)
if 0:
    if not testing: print('\nAssignments using d...\n')
    for o in m.assignments_using('d'):
        # print(o.format())
        show(o)
if 0:    
    if not testing: print('\nCalls to f...\n')
    for o in m.calls_to('f'):
        # print(o.format())
        show(o)
if 0:
    for s in m.statements():
        show(s)
    
    for f in m.functions():
        show(f,0)
        for z in f.statements():
            show(z,1)
    
    for cls in m.classes():
        show(cls,0)
        for d in cls.defs():
            show(d,1)
            for z in d.statements():
                show(z,1)
</t>
<t tx="ekr.20130503061820.4190">s = '''
# x.y = b(arg1,arg2=5,*args,**args).c[1:2:3].d
a=b+c
# f(a=1,b=2,*args,**keys)
'''


# def outer_function(a,b=99,c=88,*args,**keys):
    # print('hello')
    
# class myClass:
    # def method():
        # pass
    
</t>
<t tx="ekr.20130503061820.4217">@language python
</t>
<t tx="ekr.20130503061820.4218"></t>
<t tx="ekr.20130503061820.4219">import leo.core.leoInspect as leoInspect
import os
import time

&lt;&lt; define old_s &gt;&gt;
&lt;&lt; define s &gt;&gt;

@others

aList = (
    'leoAtFile.py',
    'leoEditCommands.py',
)
test(files=aList,print_stats=False,s=None,print_times=True)
</t>
<t tx="ekr.20130503061820.4220"># import leo.core.leoGlobals
# import leo.core.leoGlobals as g
# from leo.core.leoGlobals import pr as pr2
# from leo.core.leoGlobals import trace

s_old = '''\
import sys

aGlobal = 5
# aGlobal2 is not explicitly defined.

c = [z for z in 'abc']

def myFunc():
    n1,n2,n3,junk,junk=sys.version_info
    a = self.b
    for z in a:
        print(z)
    with A() as a:
        print(a,b)
        
def test():
    a = b # UnboundLocalError.
    b = 1
    c = 2 # Any def will do at present.
    print(g)
    print(c.frame.body)
    print(c.frame.body.xxx.yyy)
    print(b.yyy) # no check will be made.
    print(xxx.yyy)
    for c in 'abc':
        print(c,b)
        print(g)


class myClass:
    
    def __init__(self,c):
        self.a = True
        self.b = None
        c.frame.xxxx
        
    def spam(self,a,b,c=5,*args,**keys):
        global aGlobal2
        aGlobal2 = 'abc'
        self.a = b
        self.a = x
        
    def no_self(a):
        pass
        
    def test_lambda(self):
        f = lambda a,b: a

    def test_comprehension(self):
        z2 = [z for z in 'abc']
        
aGlobal3 = 4 # This should be defined everywhere.

def test():
    # a = ','.join(['a','b'])
    p = 5
    # print(p.parent().h)
    # print(g.app.windowList[0])
    print(p)
    print(g)

'''

# import leo.core.leoCommands as leoCommands
</t>
<t tx="ekr.20130503061820.4221">s = '''\

import leo.core.leoGlobals as g

def test(c):
    a = 5
    f = c.frame
    c.frame.body.bodyCtrl = w

'''

s = g.adjustTripleString(s,-4)
# print(s)
</t>
<t tx="ekr.20130503061820.4222">def test(files,print_stats=True,s=None,print_times=True):
   
    t1 = time.time()
    sd = leoInspect.SemanticData(controller=None)

    if s: # Use test string.
        fn = '&lt;test file&gt;'
        leoInspect.InspectTraverser(fn,sd).traverse(s)
    else:
        for fn in files:
            print(g.shortFileName(fn))
            s = leoInspect.LeoCoreFiles().get_source(fn)
            if s:
                leoInspect.InspectTraverser(fn,sd).traverse(s)
            else:
                print('file not found: %s' % (fn))
           
    sd.total_time = time.time()-t1
    
    if print_times: sd.print_times()
    if print_stats: sd.print_stats()
</t>
<t tx="ekr.20130503061820.4223">import leo.core.leoInspect as leoInspect

dump_classes = False
print_modules = True
print_functions = True
print_stats = False
print_times = False

# if dump_modules or print_stats:
    # g.cls()

m = leoInspect.module(fn='leoApp.py',sd=None,
    print_stats=print_stats,print_times=print_times)
    
if 0:
    print(m)
    for o in m.classes():
        if dump_classes:
            o.dump()
        if print_modules:
            print(o)
        if print_functions:
            for f in o.functions():
                print('  %s' % f)
</t>
<t tx="ekr.20130503061820.4224">import leo.core.leoInspect as leoInspect

# g.cls()

m = leoInspect.module(fn='leoEditCommands.py')
    #,sd=None,print_stats=False,print_times=False)
    
if 0:
    print(m)
    for z in m.classes():
        print(z)
        for z2 in z.defs():
            name = z2.tree_ptr.name
            aList = z2.call_args_of(name)
            args = ','.join(aList)
            print(' %s(%s)' % (name,args))
</t>
<t tx="ekr.20130503061820.4225">import leo.core.leoInspect as leoInspect

# g.cls()

m = leoInspect.module(fn='leoEditCommands.py')
    #,sd=None,print_stats=False,print_times=False)
    
if 0:
    for z in m.classes():
        print(z)
</t>
<t tx="ekr.20130503061820.4226">import leo.core.leoInspect as leoInspect

# g.cls()

m = leoInspect.module(fn='leoEditCommands.py')
    #,sd=None,print_stats=False,print_times=False)

if 0:
    print(m)
    for z in m.classes():
        print(z)
        for z2 in z.defs():
            print(z2)
</t>
<t tx="ekr.20130503061820.4227">import leo.core.leoInspect as leoInspect

# g.cls()

m = leoInspect.module(fn='leoEditCommands.py')

def show(o):
    print('%-5s %s' % (o.line_number(),o.format()))

var = '.widget'
func = 'w.insert'

if 0:
    print('\nAssignments to %s...\n' % (var))
    for o in m.assignments_to(var):
        show(o)
        
    print('\nAssignments using %s...\n' % (var))
    for o in m.assignments_using(var):
        show(o)
        
    print('\nCalls to %s...\n' % (func))
    for o in m.calls_to(func):
        show(o)
        
    if 1:
        classes = m.classes()
        for d in classes[0].defs():
            print('')
            print(d)
            for z in d.statements():
                # print(z.tree())
                # print(z.sd.dump_ast(z.tree()))
                lines = g.splitLines(z.format())
                for line in lines:
                    print('  %s' % (line))
</t>
<t tx="ekr.20130503061820.4228">import leo.core.leoInspect as leoInspect

def show(o,indent=0):
    # print('\n%s\n' % o.sd.dump_ast(o.tree()))
    print('%s%s' % (' '*4*indent,o.format()))

&lt;&lt; define s &gt;&gt;
print('Input...\n%s\n' % (s.rstrip()))

m = leoInspect.module(s=s)

# print(show(m,0))

print('\nStatements...\n')
for o in m.statements():
    print(o.format())
    
if 0:
    print('\nAssignments...\n')
    for o in m.assignments():
        print(o.format())

print('\nAssignments to a...\n')
for o in m.assignments_to('a'):
    print(o.format())
    
print('\nAssignments using d...\n')
for o in m.assignments_using('d'):
    print(o.format())
    
print('\nCalls to f...\n')
for o in m.calls_to('f'):
    print(o.format())

if 0:
    for f in m.functions():
        show(f,0)
        for z in f.statements():
            show(z,1)
    
    for cls in m.classes():
        show(cls,0)
        for d in cls.defs():
            show(d,1)
            for z in d.statements():
                show(z,1)
</t>
<t tx="ekr.20130503061820.4229">s = '''
x.y = b(arg1,arg2=5,*args,**args).c[1:2:3].d
a=b+c
p,d,q[5]=f(a=1,b=2,*args,**keys)
'''


# def outer_function(a,b=99,c=88,*args,**keys):
    # print('hello')
    
# class myClass:
    # def method():
        # pass
    
</t>
<t tx="ekr.20130503061820.4230"></t>
<t tx="ekr.20130503061820.4231">import leo.core.leoInspect as leoInspect
import time

t1 = time.time()

sd = leoInspect.SemanticData()
count = 0
for fn in leoInspect.LeoCoreFiles().files:
    # print(fn)
    m = leoInspect.module(fn,sd=sd)
    count += 1

t2 = time.time()

print('file: %s time: %2.2f sec' % (count,t2-t1))

if 0:
    sd.print_stats()
if 1:
    sd.print_times()
</t>
<t tx="ekr.20130503061820.4232">import leo.core.leoGlobals as g
import leo.core.leoInspect as leoInspect
import ast
import time

read_time,parse_time,traverse_time = 0.0,0.0,0.0
t_start = time.time()
count = 0
for fn in leoInspect.LeoCoreFiles().files:
    count += 1
    t2 = time.time()
    s = open(fn,'r').read()
    t3 = time.time()
    tree = ast.parse(s,filename=fn,mode='exec')
    t4 = time.time()
    leoInspect.AstTraverser(fn).visit(tree)
    t5 = time.time()

    read_time += t3-t2
    parse_time += t4-t3
    traverse_time += t5-t4
t_end = time.time()
total_time = t_end-t_start
if 1:
    print('files:     %s' % (count))
    print('read:      %2.3f sec.' % (read_time))
    print('ast.parse: %2.3f sec.' % (parse_time))
    print('traverse:  %2.3f sec.' % (traverse_time))
    print('total:     %2.3f sec.' % (total_time))

</t>
<t tx="ekr.20130503061820.4233">import imp
import time

import leo.core.leoInspect as li
imp.reload(li)
g_dump,g_format,g_kind = li.g_dump,li.g_format,li.g_kind

t1 = time.time()

print('starting pass 1...')

# Globals...
sd = li.SemanticData(controller=None)
g_d = {} # Keys are ivars, values are lists of classes.
n_files = 0

for fn in li.LeoCoreFiles().files:

    # Most of the time is spent creating the context objects.
    m = li.module(fn=fn,sd=sd)
    n_files += 1
    
    ### To do: create global assignments list.
    
    if 1: # Look for all targets. Takes about 0.15 sec.
        for class_ in m.classes():
            for def_ in class_.defs():
                for a in def_.assignments():
                    tree = a.tree()
                    kind = g_kind(tree)
                    # if g_kind(tree.value) == 'ListComp':
                        # print(a.format())
                        # print(g_dump(tree.value))
                    # print(a.format())
                    if kind == 'Assign':
                        for target in tree.targets:
                            # if False and g_kind(target) not in ('Attribute','Name','Tuple','Subscript'):
                                # print('assn target: %s' % g_format(target))
                                # print('assn target: %s' % g_dump(target))
                            name = g_format(target)
                            if name.startswith('self.'):
                                name = name[5:]
                            i = name.find('[')
                            if i &gt; -1:
                                name = name[:i]
                            aList = g_d.get(name,[])
                            if class_.name() not in aList:
                                aList.append(class_.name())
                                g_d[name] = aList
                    else:
                        assert kind == 'AugAssign',kind
                        name = g_format(tree.target)
                        aList = g_d.get(name,[])
                        if class_.name() not in aList:
                            aList.append(class_.name())
                            g_d[name] = aList

    # Takes about 0.1 sec. cumulative.
    if 0: # Look for all ivars.
        for class_ in m.classes():
            for def_ in class_.defs():
                if def_.name() == '__init__':
                    for a in def_.assignments_to('self'):
                        # Not all targets are ivars.
                        for target in a.tree().targets:
                            name = g_format(target)
                            if name.startswith('self.'):
                                name = name[5:]
                                aList = g_d.get(name,[])
                                if class_.name() not in aList:
                                    aList.append(class_.name())
                                    g_d[name] = aList
                       

t2 = time.time()

print('files: %s time: %2.2f sec, total ivars: %s' % (
    n_files,t2-t1,len(list(g_d.keys()))))

if 0:
    ambiguous,total = 0,0
    for key in sorted(g_d.keys()):
        aList = sorted(g_d.get(key))
        if 1 and len(aList) &gt; 1:
            w = 30 # Width of left column
            if total == 0: print('Global ivars dict...')
            if len(key) + 3 &gt; w: key = key[:w-3]+'...'
            aList2 = aList[:3]
            if len(aList2) &lt; len(aList): aList2.append('...')
            print('%30s %2s %s' % (key,len(aList),aList2))
        total += 1
        if len(aList) &gt; 1: ambiguous += 1
    print('total ivars: %s ambiguous: %s' % (total,ambiguous))

if 0:
    sd.print_stats()
</t>
<t tx="ekr.20130503061820.4234">g.cls()

import imp
import time

import leo.core.leoInspect as li
imp.reload(li)
g_dump,g_format,g_kind = li.g_dump,li.g_format,li.g_kind

t1 = time.time()

# Globals...
sd = li.SemanticData(controller=None)
d = sd.modules_dict

# Pass 1: Load all modules.
print('starting pass 1...')
for fn in li.LeoCoreFiles().files:
    li.module(fn=fn,sd=sd)

t2 = time.time()
print('pass 1: %2.3f sec files: %s' % (t2-t1,len(list(d.keys()))))
    
# Pass 2: compute all class names.
classes = set()
for fn in sorted(d):
    m = d.get(fn)
    for class_ in m.classes():
        classes.add(class_.name())
        
t3 = time.time()
print('pass 2: %2.3f sec' % (t3-t2))

classes = sorted(list(classes))

if 0:
    for z in classes:
        print(z)
        
# Pass 3: Find all calls to ctors.
ctors = set()
ctors_assns = []
for fn in sorted(d):
    m = d.get(fn)
    for class_ in m.classes():
        for def_ in class_.defs():
            for a in def_.assignments():
                rhs = a.tree().value
                if m.tree_kind(rhs) == 'Call':
                    s = li.g_find_function_call(rhs.func)
                    if s in classes:
                        ctors.add(s)
                        ctors_assns.append(a.format())
 
t4 = time.time()                            

if 0:
    for z in sorted(list(ctors)):
        print(z)
if 0:
    for s in ctors_assns:
        aList = s.split('=')
        print('%30s = %s' % (aList[0],'='.join(aList[1:])[:80]))

print('pass 3: %2.3f sec ctors assigns: %s' % (t4-t3,len(ctors_assns)))

if 1:
    sd.print_stats()
if 1:
    sd.print_times()
</t>
<t tx="ekr.20130503061820.4235"># g.cls()

import imp
import pickle
import time

import leo.core.leoInspect as li
imp.reload(li)
    
# Works, because TestPickleClass is a top-level class.
o = li.TestPickleClass()

try:
    s = pickle.dumps(o)
    print(len(s),o)
except pickle.PicklingError:
    print('can not pickle: %s' % repr(o))
</t>
<t tx="ekr.20130503061820.4236"># g.cls()

import imp
import pickle
import time

import leo.core.leoInspect as li
imp.reload(li)
g_dump,g_format,g_kind = li.g_dump,li.g_format,li.g_kind

# Pass 1: Load all modules.
t1 = time.time()
sd = li.SemanticData(controller=None)
files = li.LeoCoreFiles().files

print('starting pass 1...')
for fn in files:
    li.module(fn=fn,sd=sd)

t2 = time.time()
print('pass 1: %2.3f sec files: %s' % (t2-t1,len(list(sd.modules_dict.keys()))))

# Pass 2: pickle all modules.
for fn in sorted(sd.modules_dict.keys()):
    m = sd.modules_dict.get(fn)
    try:
        s = pickle.dumps(m)
        print('%6s %s' % (len(s),fn))
    except pickle.PicklingError:
        print('can not pickle: %s' % repr(m))
        
t3 = time.time()
print('pass 2: %2.3f sec' % (t3-t2))
</t>
<t tx="ekr.20130503061820.4237">g.cls()

import imp

import leo.core.leoInspect as li
imp.reload(li)
g_format = li.g_format

# Pass 1: Load all modules.
sd = li.SemanticData(controller=None)
files = li.LeoCoreFiles().files # [0:2]

s = '''
def spam():
    """This is a docstring"""
    a = 2
    try:
        pass
    except Exception as message: ###
        pass
    if f(1):
        g('a')
    else:
        g(2)
    while 1 &lt; 2:
        pass
    raise AttributeError ###
    return 2
'''

if 0: # String
    li.module(s=s,sd=sd)
else:
    print('starting pass 1...')
    for fn in files:
        li.module(fn=fn,sd=sd)
    
# Pass 2: format the module.
for fn in sorted(sd.modules_dict.keys()):
    m = sd.modules_dict.get(fn)
    # print(m.format())
    m.format() # Run for warnings.
</t>
<t tx="ekr.20130503061820.4238">import imp
import leo.core.leoInspect as li
imp.reload(li)

g.cls()

aList = li.g_files_in_dir(r'C:\Python26\Lib\lib2to3',
    extList = ['.py'],
    excludeDirs= ['tests'])

for z in aList:
    print(z)

print('files: %s' % (len(z)))
</t>
<t tx="ekr.20130503061820.4239">import ast
import imp
import time
import leo.core.leoInspect as li
imp.reload(li)

t1 = time.time()

g.cls()

last = c.rootPosition()
while last.hasNext():
    last = last.next()
    
parent = last.insertAfter()
parent.h = 'Chains: %s' % time.strftime('%Y/%m/%d/%H:%M:%S',time.localtime())
parent.b = '@killcolor'

count, total_chains,unusual_chains = 0,0,0
for fn in li.LeoCoreFiles().files: # [:2]:
    # print()
    # print(fn)
    s = open(fn,'r').read()
    tree = ast.parse(s,filename=fn,mode='exec')
    cp = li.ChainPrinter(fn)
    cp.visit(tree)
    p2 = parent.insertAsLastChild()
    p2.h = g.shortFileName(fn)
    n1,n2 = cp.showChains(p2)
    total_chains += n1
    unusual_chains += n2
    # print('chains: %s' % (n))
    count += 1
    
c.redraw(parent)

t2 = time.time()

print('files: %s total chains: %s unusual_chains: %s time: %2.2f sec' % (
    count,total_chains,unusual_chains,t2-t1))

# if 0:
    # sd.print_stats()
# if 0:
    # sd.print_times()
</t>
<t tx="ekr.20130503061820.4240">import ast
import imp
import time
import leo.core.leoInspect as li
imp.reload(li)

g.cls()

t1 = time.time()

last = c.rootPosition()
while last.hasNext():
    last = last.next()
    
parent = last.insertAfter()
parent.h = 'Calls: %s' % time.strftime('%Y/%m/%d/%H:%M:%S',time.localtime())
parent.b = '@killcolor'

g_d = {}
count=0
for fn in li.LeoCoreFiles().files: # [:3]:
    # print()
    # print(fn)
    s = open(fn,'r').read()
    tree = ast.parse(s,filename=fn,mode='exec')
    cp = li.CallPrinter(fn)
    cp.visit(tree)
    p2 = parent.insertAsLastChild()
    p2.h = g.shortFileName(fn)
    cp.showCalls(p2)
    for key in cp.d.keys():
        aList = g_d.get(key,[])
        aList.extend(cp.d.get(key))
        g_d[key] = sorted(list(set(aList)))
    count += 1
    
p2 = parent.insertAsLastChild()
p2.h = 'global calls'
cp.showCalls(p2,d=g_d)
c.selectPosition(parent)
c.redraw()

t2 = time.time()

print('files: %s time: %2.2f sec' % (count,t2-t1))
</t>
<t tx="ekr.20130503061820.4241">import ast
import imp
import time
import leo.core.leoInspect as li
imp.reload(li)

g.cls()

t1 = time.time()

last = c.rootPosition()
while last.hasNext():
    last = last.next()
    
project_name,verbose = 'leo',False # False: only print defs with more than one return.
files = li.g_get_files_by_project_name(project_name)

parent = last.insertAfter()
parent.h = 'Returns: %s verbose=%s %s' % (
    project_name, verbose,
    time.strftime('%Y/%m/%d/%H:%M:%S',time.localtime()))
parent.b = '@killcolor'

g_d = {}
count=0
for fn in files:
    # print(fn)
    s = open(fn,'r').read()
    try:
        tree = ast.parse(s,filename=fn,mode='exec')
    except SyntaxError:
        print('Syntax error in %s' % (fn))
        continue
    rp = li.ReturnPrinter(fn)
    rp.visit(tree)
    p2 = parent.insertAsLastChild()
    p2.h = g.shortFileName(fn)
    p2.b = rp.showReturns(verbose=verbose)
    for key in rp.d.keys():
        aList = g_d.get(key,[])
        aList2 = rp.d.get(key)
        if aList2:
            aList.extend(aList2)
            g_d[key] = aList
    count += 1
    
if 0:
    p2 = parent.insertAsLastChild()
    p2.h = 'global returns'
    rp.showReturns(p2,d=g_d)

c.redraw(parent)

t2 = time.time()

print('files: %s time: %2.2f sec' % (
    count,t2-t1))
</t>
<t tx="ekr.20130503061820.4242"># import ast
import imp
import time
import leo.core.leoInspect as li
imp.reload(li)

g.cls()

project_name,verbose = 'leo',False
files = li.g_get_files_by_project_name(project_name)
result = []

def put(s):
    result.append(s)
    # print(s)
    
t1 = time.time()

# Globals...
sd = li.SemanticData(controller=None)
m_d = sd.modules_dict

# Pass 1: Load all modules.
print('starting pass 1...')
for fn in files: ### [:2]:
    li.module(fn=fn,sd=sd)

t2 = time.time()
put('pass 1: %2.3f sec files: %s' % (t2-t1,len(list(m_d.keys()))))

# Pass 2: Update g_d.
g_d = {} # Keys are names, values are sets of Context names.
contexts = 0
for fn in sorted(m_d):
    m = m_d.get(fn)
    for cx in m.contexts(include_temp=True):
        # put(' '*len(cx.parent_contexts()),cx)
        contexts += 1
        d = cx.st.d # Keys are names, values are symbol table entries.
        for key in d.keys():
            e = d.get(key)
            name = e.name
            aSet = g_d.get(name,set())
            aSet.add(cx)
            g_d[name] = aSet
            
names = sorted(g_d.keys())
distribution = {} # Keys are lengths of context sets; values are number of ids with that length.
for key in names:
    aSet = g_d.get(key)
    context_list = sorted(list(set([repr(z) for z in aSet])))
    n = len(context_list)
    distribution[n] = distribution.get(n,0) + 1
    if verbose or n &gt; 9:
        if n &gt; 3:
            put('%20s %4s %s...' % (key,len(context_list),context_list[:3]))
        else:
            put('%20s %4s %s' % (key,len(context_list),context_list))
ids = len(names)
        
t3 = time.time()
put('pass 2: contexts: %s ids: %s %2.2f sec' % (contexts,ids,t3-t2))

if 1:
    put('\nDistribution of context lengths...')
    for key in sorted(distribution.keys()):
        put('%4s %s' % (key,distribution.get(key)))
    
if 1:
    last = c.rootPosition()
    while last.hasNext():
        last = last.next()
    parent = last.insertAfter()
    parent.h = 'Global names: %s verbose=%s %s' % (
        project_name, verbose,
        time.strftime('%Y/%m/%d/%H:%M:%S',time.localtime()))
    parent.b = '@killcolor\n\n%s' % '\n'.join(result)
    c.redraw(parent)

if 0:
    sd.print_stats()
if 0:
    sd.print_times()

</t>
<t tx="ekr.20131111155107.4239">c.testManager.runVimTest(p)

</t>
<t tx="ekr.20131111155107.4240">first line
</t>
<t tx="ekr.20131111155107.4241">first line
</t>
<t tx="ekr.20131111155107.4242">first line
</t>
<t tx="ekr.20131111155830.4249"></t>
<t tx="ekr.20131111155830.4250"># Not yet...

    &lt;BS&gt;        delete the character in front of the cursor
N   &lt;Del&gt;       delete N characters under and after the cursor
    &lt;Del&gt;       delete the character under the cursor
    &lt;Del&gt;       while entering a count: delete last character
    &lt;Down&gt;      recall newer command-line that starts with current command
    &lt;Esc&gt;       abandon command-line (if 'wildchar' is &lt;Esc&gt;, type it twice)
    &lt;Left&gt;      (motion) cursor left
    &lt;Right&gt;     (motion) cursor right
    &lt;S-Down&gt;    recall newer command-line from history
    &lt;S-Left&gt;    (motion) cursor one word left
    &lt;S-Right&gt;   (motion) cursor one word right
    &lt;S-Up&gt;      recall older command-line from history
    &lt;Up&gt;        recall older command-line that starts with current command

N   CTRL-^                  Edit alternate file N (equivalent to ":e #N").
N   CTRL-A                  add N to the number at or after the cursor
N   CTRL-B                  window N pages Backwards (upwards)
    CTRL-B                  (motion?) cursor to beginning of command-line
    CTRL-BREAK              MS-DOS: during searches: interrupt the search
    CTRL-C                  during searches: interrupt the search
N   CTRL-D                  window N lines Downwards (default: 1/2 window)
N   CTRL-E                  window N lines downwards (default: 1)
    CTRL-E                  (motion?) cursor to end of command-line
N   CTRL-F                  (motion) window N pages Forwards (downwards)
    CTRL-G                  show current file name (with path) and cursor position
N   CTRL-I                  (motion) go to Nth newer position in jump list
    CTRL-K {char1} {char2}  enter digraph
    CTRL-L                  Clear and redraw the screen.
N   CTRL-O                  (motion) go to Nth older position in jump list
N   CTRL-R                  redo last N undone changes
    CTRL-R &lt;0-9a-z"%:-&gt;     insert contents of register &lt;0-9a-z"%:-&gt;
N   CTRL-T                  (motion) Jump back from Nth older tag in tag list
N   CTRL-U                  window N lines Upwards (default: 1/2 window)
    CTRL-U                  remove all characters
    CTRL-V                  highlight blockwise or stop highlighting
    CTRL-V                  start highlighting blockwise   }  highlighted text
    CTRL-V {char}           insert {char} literally
    CTRL-V {number}         enter decimal value of character (up to three digits)
    CTRL-W                  delete the word in front of the cursor
    CTRL-W +                Increase current window height
    CTRL-W -                Decrease current window height
    CTRL-W =                Make all windows equal height
    CTRL-W CTRL-W           Move cursor to window below (wrap)
    CTRL-W CTRL-^           Split window and edit alternate file
    CTRL-W R                Rotate windows upwards
    CTRL-W W                Move cursor to window above (wrap)
    CTRL-W ]                Split window and jump to tag under cursor
    CTRL-W _                Set current window height (default: very high)
    CTRL-W b                Move cursor to bottom window
    CTRL-W c  or :cl[ose]   Make buffer hidden and close window
    CTRL-W f                Split window and edit file name under the cursor
    CTRL-W j                Move cursor to window below
    CTRL-W k                Move cursor to window above
    CTRL-W n  or :new       Create new empty window
    CTRL-W o  or :on[ly]    Make current window only one on the screen
    CTRL-W p                Move cursor to previous active window
    CTRL-W q  or :q[uit]    Quit editing and close window
    CTRL-W r                Rotate windows downwards
    CTRL-W s                Split window into two parts
    CTRL-W t                Move cursor to top window
    CTRL-W x                Exchange current window with next one
N   CTRL-X                  subtract N from the number at or after the cursor
N   CTRL-Y                  window N lines upwards (default: 1)
    CTRL-Z                  Same as ":stop!"
    CTRL-]                  Jump to the tag under cursor, unless changes have been made</t>
<t tx="ekr.20131111155830.4251">char F
char T
char f
char r
char t
letter m
letter q
motion &lt;
motion &gt;
motion c
motion d
motion gU
motion gq
motion gu
motion g~
motion y
pattern /
pattern ?
register @
</t>
<t tx="ekr.20131111155830.4252"># http://tnerual.eriogerg.free.fr/vimqrc.html
vim_0 0
vim_tilda ~
vim_plus +
vim_underscore _
vim_minus -
vim_comma ,
vim_dot .
vim_semicolon ;
vim_lparen (
vim_rparen )
vim_lcurly {
vim_rcurly }
vim_vertical |
vim_backtick `
vim_dollar $
vim_caret ^
vim_percent %
vim_langle &lt;
vim_langle &lt;&lt;
vim_rangle &gt;
vim_rangle &gt;&gt;
vim_pound #
vim_star *
vim_slash /\\n
vim_slash /
vim_question ?\\n
vim_question ?
vim_at @
vim_at @@
vim_dquote "
vim_lsquare [#
vim_lsquare [(
vim_lsquare [*
vim_lsquare [[
vim_lsquare []
vim_lsquare [p
vim_lsquare [{
vim_rsquare ]#
vim_rsquare ])
vim_rsquare ]*
vim_rsquare ][
vim_rsquare ]]
vim_rsquare ]p
vim_rsquare ]}
vim_A A
vim_B B
vim_C C
vim_D D
vim_E E
vim_F F
vim_G G
vim_H H
vim_I I
vim_J J
vim_K K
vim_M M
vim_L L
vim_N N
vim_O O
vim_P P
vim_R R
vim_S S
vim_T T
vim_U U
vim_V V
vim_W W
vim_X X
vim_Y Y
vim_Z ZQ
vim_Z ZZ
vim_a a
vim_b b
vim_c c
vim_d dd
vim_d d
vim_g g~
vim_g g^
vim_g g#
vim_g g$
vim_g g*
vim_g g0
vim_g gD
vim_g gE
vim_g gI
vim_g gU
vim_g ga
vim_g gd
vim_g ge
vim_g gf
vim_g gg
vim_g gj
vim_g gk
vim_g gq
vim_g gs
vim_g gu
vim_g gv
vim_h h
vim_i i
vim_j j
vim_k k
vim_l l
vim_n n
vim_m m
vim_o o
vim_p p
vim_q q
vim_r r
vim_s s
vim_t t
vim_u u
vim_v v
vim_w w
vim_x x
vim_y y
vim_y yy
vim_z z-
vim_z z.
vim_z z&lt;CR&gt;
vim_z zb
vim_z zh
vim_z zl
vim_z zt
vim_z zz
</t>
<t tx="ekr.20131111155830.4253"># CR
# Ctrl-End
# Ctrl-Home
# Ctrl-Left
# Ctrl-M
# Ctrl-N
# Ctrl-P
# Ctrl-Right
# End
# Home
# Shift-Left
# Shift-Right

( 	
)
{
}
[[
[]
][
]]
$
^	
+
,
-
;
_
0
B
E
F
G
T
W
b
e
f
g$
g^
g0
gE
# gEnd
# gHome	
ge
gg
h
j
k
t
w
</t>
<t tx="ekr.20131111155830.4254">char F
char T
char f
char t
</t>
<t tx="ekr.20131111160618.4261"></t>
<t tx="ekr.20131111162157.4270">@language python
# http://docs.python.org/2/library/re.html
import re
# g.cls()
trace = False
n =     r'(?P&lt;n&gt;[0-9]*)'    # Optional digits
cmd =   r'(?P&lt;cmd&gt;[^0-9]+)' # Required: anything *except* digits.
n2 =    r'(?P&lt;n2&gt;[0-9]*)'   # Optional digits
cmd2 =  r'(?P&lt;cmd2&gt;[a-zA-Z]?)' # Optional letter.
n_c = n+cmd+n2+cmd2
tables = (
    (n_c,('35N','N','2d2','d2d','gg',)),
)
for pat,aList in tables:
    fields = re.findall('\(\?P&lt;([a-z_A-Z0-9]+)&gt;',pat)
    if trace: print('pattern: %s\n fields: %s' % (pat,','.join(fields)))
    for s in aList:
        if trace: print('  %s' % s)
        m = re.search(pat,s)
        for field in fields:
            try:
                val = m.group(field)
            except Exception:
                g.es_exception()
                val = None
            if trace: print('    %7s %s' % (field,val or 'None'))
</t>
<t tx="ekr.20131111162157.4271">@language python
# g.cls()

# Unknown:
# N   H  (motion?) go to the Nth line in the window, on the first non-blank
# N   J  (motion?) join N-1 lines (delete newlines)
# VIS J  (motion?) join the highlighted lines
    # M  (motion?) go to the middle line in the window, on the first non-blank
# N   L  (motion?) go to the Nth line from the bottom, on the first non-blank
# o      (motion?) exchange cursor position with start of highlighting

# Not used:
# N %    goto line N percentage down in the file.
#        N must be given, otherwise it is the % command.

#   0    to first character in the line (also: &lt;Home&gt; key)
#   ^    go to first non-blank character in the line
#   %    find the next brace, bracket, comment,
#        or "#if"/ "#else"/"#endif" in this line and go to its match
# N +    down N lines, on the first non-blank character (also: CTRL-M and &lt;CR&gt;)
# N _    down N-1 lines, on the first non-blank character
# N -    up N lines, on the first non-blank character
# N ,    repeat the last "f", "F", "t", or "T" N times in opposite direction
# N ;    repeat the last "f", "F", "t", or "T" N times
# N (    N sentences backward
# N )    N sentences forward
# N {    N paragraphs backward
# N }    N paragraphs forward
# N |    to column N (default: 1)
# N $    go to the last character in the line (N-1 lines lower) (also: &lt;End&gt; key)
# N #    search backward for the identifier under the cursor
# N *    search forward  for the identifier under the cursor
# N B    N blank-separated WORDS backward
# N E    forward to the end of the Nth blank-separated WORD
# N G    goto line N (default: last line), on the first non-blank character
# N N    repeat last search, in opposite direction
# N W    N blank-separated WORDS forward
# N b    N words backward
# N e    forward to the end of the Nth word
# N h    left (also: CTRL-H, &lt;BS&gt;, or &lt;Left&gt; key)
# N j    down N lines (also: CTRL-J, CTRL-N, &lt;NL&gt;, and &lt;Down&gt;)
# N k    up N lines (also: CTRL-P and &lt;Up&gt;)
# N l    right (also: &lt;Space&gt; or &lt;Right&gt; key)
# N n    repeat last search
# N w    N words forward
single_char_motions = [ch for ch in '0^%_+-,;(){}|$#*BEGNWbehjklnw']
# N [#   N times back to unclosed "#if" or "#else"
# N [(   N times back to unclosed '('
# N [*   N times back to start of comment "/*"
# N [[   N sections backward, at start of section
# N []   N sections backward, at end of section
# N [{   N times back to unclosed '{'
m1  = ['['+ ch for ch in '#(*[]{']
# N ]#   N times forward to unclosed "#else" or "#endif"
# N ])   N times forward to unclosed ')'
# N ]*   N times forward to end of comment "*/"
# N ][   N sections forward, at end of section
# N ]]   N sections forward, at start of section
# N ]}   N times forward to unclosed '}'
m2 = [']'+ch for ch in '#)*[]}']
#   gD   goto global declaration of identifier under the cursor
#   gd   goto local declaration of identifier under the cursor
# N g^   to first non-blank character in screen line (differs from "^" when lines wrap)
# N g#   like "#", but also find partial matches
# N g$   to last character in screen line (differs from "$" when lines wrap)
# N g*   like "*", but also find partial matches
# N g0   to first character in screen line (differs from "0" when lines wrap)
# N gE   backward to the end of the Nth blank-separated WORD
# N ge   backward to the end of the Nth word
# N gg   goto line N (default: first line), on the first non-blank character
# N gj   down N screen lines (differs from "j" when line wraps)
# N gk   up N screen lines (differs from "k" when line wraps)
m3 = ['g'+ch for ch in '^#$*0DEdegjk']
# N /&lt;CR&gt;  repeat last search, in the forward direction
m4 = ['/\\n',]
# N F&lt;char&gt;  to the Nth occurrence of &lt;char&gt; to the left
# N T&lt;char&gt;  till before the Nth occurrence of &lt;char&gt; to the left
# N f&lt;char&gt;  to the Nth occurrence of &lt;char&gt; to the right
# N t&lt;char&gt;  till before the Nth occurrence of &lt;char&gt; to the right
char_motions = [ch for ch in 'FTft']
multi_char_leadins = '/g[]'
multi_char_motions = m1+m2+m3+m4
print('\n'.join(single_char_motions))
print('\n'.join(multi_char_motions))
print('\n'.join(['%s&lt;char&gt;' % (ch) for ch in char_motions]))
</t>
<t tx="ekr.20131111162157.4272">@language python

# http://docs.python.org/2/library/re.html
import re
# g.cls()

def escape(ch):
    return ch if ch.isalnum() else '\\%s' % ch
# Not yet.
# N /&lt;CR&gt; (motion) repeat last search, in the forward direction

# 0 (motion) to first character in the line (also: &lt;Home&gt; key)
# ^ (motion) go to first non-blank character in the line
# % (motion) find the next brace, bracket, comment,
#            or "#if"/ "#else"/"#endif" in this line and go to its match
plain_motion_chars = '0^%'
plain_motion =   '|'.join([escape(ch) for ch in plain_motion_chars])
# N + (motion) down N lines, on the first non-blank character (also: CTRL-M and &lt;CR&gt;)
# N _ (motion) down N-1 lines, on the first non-blank character
# N - (motion) up N lines, on the first non-blank character
# N , (motion) repeat the last "f", "F", "t", or "T" N times in opposite direction
# N ; (motion) repeat the last "f", "F", "t", or "T" N times
# N ( (motion) N sentences backward
# N ) (motion) N sentences forward
# N { (motion) N paragraphs backward
# N } (motion) N paragraphs forward
# N | (motion) to column N (default: 1)
# N $ (motion) go to the last character in the line (N-1 lines lower) (also: &lt;End&gt; key)
# N % (motion) goto line N percentage down in the file.  N must be given, otherwise it is the % command.
# N # (motion) search backward for the identifier under the cursor
# N * (motion) search forward for the identifier under the cursor
n_motion_chars = '+_-,;(){}|$%#*'
n_motion_alts = ' | '.join([escape(ch) for ch in n_motion_chars])
# N [#  (motion) N times back to unclosed "#if" or "#else"
# N [(  (motion) N times back to unclosed '('
# N [*  (motion) N times back to start of comment "/*"
# N [[  (motion) N sections backward, at start of section
# N []  (motion) N sections backward, at end of section
# N [{  (motion) N times back to unclosed '{'
open_bracket_chars  = ['[%s' % (ch) for ch in '#(*[]{']
# N ]#  (motion) N times forward to unclosed "#else" or "#endif"
# N ])  (motion) N times forward to unclosed ')'
# N ]*  (motion) N times forward to end of comment "*/"
# N ][  (motion) N sections forward, at end of section
# N ]]  (motion) N sections forward, at start of section
# N ]}  (motion) N times forward to unclosed '}'
close_bracket_chars = [']%s' % (ch) for ch in '#)*[]}']
bracket_chars = open_bracket_chars + close_bracket_chars
bracket_motion = ' | '.join(['%s%s' % (escape(s[0]),escape(s[1])) for s in bracket_chars])
bracket_alts =      r'(?P&lt;bracket_alt&gt;%s)' % (bracket_motion)
# print(bracket_alts)
# gD (motion) goto global declaration of identifier under the cursor
# gd (motion) goto local declaration of identifier under the cursor
g_bare_alts =   r'(?P&lt;bare_g_alts&gt;(gD|gd))'
# N g^      (motion) to first non-blank character in screen line (differs from "^" when lines wrap)
# N g#      (motion) like "#", but also find partial matches
# N g$      (motion) to last character in screen line (differs from "$" when lines wrap)
# N g*      (motion) like "*", but also find partial matches
# N g0      (motion) to first character in screen line (differs from "0" when lines wrap)
# N gE      (motion) backward to the end of the Nth blank-separated WORD
# N ge      (motion) backward to the end of the Nth word
# N gg      (motion) goto line N (default: first line), on the first non-blank character
# N gj      (motion) down N screen lines (differs from "j" when line wraps)
# N gk      (motion) up N screen lines (differs from "k" when line wraps)
g_alt_chars =   ' | '.join([escape(ch) for ch in '^#$*0Eegjk'])
g_alts =        r'(?P&lt;g_n&gt;[0-9]*)(?P&lt;g_alt&gt;g(%s))' % (g_alt_chars)
g_motion = 'g(%s | %s)' % (g_bare_alts,g_alts)
print(g_motion)
</t>
<t tx="ekr.20131111162157.4275">import leo.core.leoVim as leoVim
if 0: # When running from leoPy.leo
    import imp
    imp.reload(leoVim)
vc = leoVim.VimCommands(c)
table = (
    # 'gg','gk','#','dd','d3j',
    'h', # works
    # 'l', # works
    # 'j', # Not yet.
    # 'ggg',
)
for s in table:
    status,n1,command,n2,motion = vc.scan(s)
    # print('status',status,'command',command)
    if status == 'done':
        vc.exec_(command,n1,n2,motion)
    else:
        print('status: %s %s' % (status,s))
        vc.command = s
        vc.n1 = n1
        vc.n2 = n2
        vc.motion = motion
        vc.oops()

if g.unitTesting:
    # Unit testing messes up the focus.
    vc.runAtIdle(c.bodyWantsFocusNow)
</t>
<t tx="ekr.20131111162157.4276"></t>
<t tx="ekr.20131113071911.4281">import leo.core.leoVim as leoVim
if 0: # When running from leoPy.leo
    import imp
    imp.reload(leoVim)
import time
trace = False
trace_time = False
&lt;&lt; define test tables &gt;&gt;
vc = leoVim.VimCommands(c)
test_table = (
    ('done',complete_table),
    ('scan',incomplete_table),
    ('oops',error_table),
)
if trace_time: t1 = time.clock()
n = 0
for i in range(1):
    for expected,table in test_table:
        for s in table:
            if table == complete_table:
                command = s
                for expected,command2 in vc.simulate_typing(command):
                    status,n1,command3,n2,motion = vc.scan(command2)
                    n += 1
                    if trace:
                        err = '   ' if status == expected else '***'
                        print('%s%s %s' % (err,status,command2))
                    else:
                        assert status == expected,'expected %s, got %s command: %s' % (
                        expected,status,command2)
            else:
                for prefix in ('','1023456789'):
                    command = prefix + s
                    status,n1,command2,n2,motion = vc.scan(command)
                    n += 1
                    if trace:
                        err = '   ' if status == expected else '***'
                        print('%s%s %s' % (err,status,command))
                    else:
                        assert status == expected,'expected %s, got %s command: %s' % (
                        expected,status,command)
if trace_time:
    delta = time.clock()-t1
    print("%s %6.6f sec." % (n,delta/n))

</t>
<t tx="ekr.20131113071911.4282"># To do: handle d2d, 2dd, etc.
if 0: # Individual test:
    complete_table = ('ta',)
        # Note: gu is complete, so gu[] is an invalid test.
    incomplete_table = () # 'd3','d4t','dt',
    error_table = ()
else:
    complete_table = (
        '0',
        'N',
        '#',
        'gg','gk','dd',
        'd3j',
        '2dta', # d is not (yet) a motion
        'dFb',
        'gu',
        'g[]',
        'ta',
        't!',
    )
    incomplete_table = (
        'g',
        '[',
        ']',
        '25',
        'd3t',
        'd3',
    )
    error_table = (
        'gX','ZA',
    )
</t>
<t tx="ekr.20131231093529.3984"></t>
<t tx="ekr.20140103102956.4142">vc = c.viewController
clones = g.findNodeInTree(c,p,'@clones')
root = g.findNodeInTree(c,p,'root')
node1 = g.findNodeInTree(c,p,'node1')
assert clones and root and node1
root.deleteAllChildren()
new_node1 = root.insertAsLastChild()
new_node1.h = 'node1'
clones.b = 'gnx: %s\nunl: %s\n' % (node1.v.gnx,'node1')
try:
    ok = vc.create_clone_links(clones,root)
    assert ok
    # Important: p._relinkAsCloneOf leaves new_node1 unchanged,
    # but new_node1 should not be used.
finally:
    c.redraw()
</t>
<t tx="ekr.20140103102956.4143">gnx: ekr.20140211085929.5552
unl: node1
</t>
<t tx="ekr.20140103102956.4145"></t>
<t tx="ekr.20140103102956.4146">vc = c.viewController
root = c.rootPosition().insertAfter()
root.h = 'root'
child1 = root.insertAsLastChild()
child1.h = 'child1'
child2 = child1.insertAfter()
child2.h = 'child2'
child11 = child1.insertAsLastChild()
child11.h = 'child11'
try:
    for unl in ('root','root--&gt;child1','root--&gt;child2','root--&gt;child1--&gt;child11'):
        p = vc.find_absolute_unl_node(unl)
        parts = unl.split('--&gt;')
        assert p,unl
        assert p.h == parts[-1],p.h
finally:
    root.doDelete()
    c.selectPosition(p)
    c.redraw()
</t>
<t tx="ekr.20140103102956.4147">vc = c.viewController
parent = p.copy()
node1 = p.firstChild()
node2 = node1.next()
assert node1 and node2
child11 = node1.firstChild()
child12 = child11.next()
assert child11 and child12
child21 = node2.firstChild()
child22 = child21.next()
assert child21 and child22
table = (
    # ('node1',node1),
    ('',parent), # This special case is important.
    ('node1--&gt;child11',child11),
    ('node1--&gt;child12',child12),
    ('node2',node2),
    ('node2--&gt;child21',child21),
    ('node2--&gt;child22',child22),
    ('node3',None),
    ('node1--&gt;childx',None),
    ('node3--&gt;childx',None),
)
for unl,expected in table:
    got = vc.find_position_for_relative_unl(parent,unl)
    assert got == expected,'unl: %s expected: %s got: %s' % (
        unl,expected and expected.h,got and got.h)
</t>
<t tx="ekr.20140103102956.4148"></t>
<t tx="ekr.20140103102956.4149"></t>
<t tx="ekr.20140103102956.4150"></t>
<t tx="ekr.20140103102956.4151"></t>
<t tx="ekr.20140103102956.4152"></t>
<t tx="ekr.20140103102956.4153"></t>
<t tx="ekr.20140103102956.4154">vc = c.viewController
root = g.findNodeInTree(c,p,'root')
assert root
root.h = '@auto root'
try:
    clone = root.next()
    assert clone and clone.h == 'clone'
    inner_clone = root.firstChild()
    assert inner_clone
    assert clone.v == inner_clone.v
    rep = vc.find_representative_node(root,inner_clone)
    # Careful: cloning this test can cause problems.
    oops = '\n  rep: %s\nparent:%s\nclone: %s\nparent:%s\ninner: %s\nparent: %s' % (
        rep,rep.parent(),clone,clone.parent(),inner_clone,inner_clone.parent())
    if True: ### p.isCloned():
        assert rep.v == clone.v and rep.parent().v == clone.parent().v,oops
    else:
        assert rep == clone
finally:
    root.h = 'root' # root must not be an @auto node.
    c.redraw()
</t>
<t tx="ekr.20140103102956.4155"></t>
<t tx="ekr.20140103102956.4157"></t>
<t tx="ekr.20140103102956.4158"># Also a test of find_at_views_node, find_at_organizers_node and find_at_clones_node.
vc = c.viewController
root = g.findNodeInTree(c,p,'root')
assert root
views = g.findNodeAnywhere(c,'@views')
assert views,'1'
if views:
    views.deleteAllChildren()
try:
    root.h = '@auto root' # root must look like an @auto node.
    views = vc.find_at_views_node()
    assert views,'2'
    views2 = vc.find_at_views_node()
    assert views2 == views
    assert vc.find_at_clones_node(root)
    assert vc.find_at_organizers_node(root)
finally:
    root.h = 'root' # Make sure root is *not* an @auto node.
    # views.deleteAllChildren()
    c.selectPosition(p)
    c.redraw()
</t>
<t tx="ekr.20140103102956.4159"></t>
<t tx="ekr.20140103102956.4160">class aClass:
    @others
</t>
<t tx="ekr.20140103102956.4162"></t>
<t tx="ekr.20140103102956.4163">def spam():
    pass
</t>
<t tx="ekr.20140103102956.4164"></t>
<t tx="ekr.20140103102956.4165">vc = c.viewController
tag = '@views'
views = g.findNodeAnywhere(c,tag)
assert views
views2 = vc.has_at_views_node()
assert views == views2,(views,views2)
</t>
<t tx="ekr.20140103102956.4166">vc = c.viewController
p.deleteAllChildren()
auto = p.insertAsLastChild()
auto.h = '@auto test.py'
auto2 = p.insertAsLastChild()
auto2.h = '@auto-rst test2.py'
try:
    assert vc.is_at_auto_node(auto)
    assert not vc.is_at_auto_node(auto2)
finally:
    # This is required.
    p.deleteAllChildren()
    c.redraw()
</t>
<t tx="ekr.20140103102956.4167">vc = c.viewController
redraw_flag = False
for child in p.children():
    # Add a child so the test doesn't depend on that.
    if not child.hasChildren():
        child2 = child.insertAsLastChild()
        child2.h = 'child'
        redraw_flag = True
        
    expected = child.h.strip().endswith('True')
    got = vc.is_organizer_node(child,child)
    assert expected == got,'expected: %s in: %s body...\n%s' % (
        expected,child.h,child.b)
if redraw_flag:
    c.redraw()
</t>
<t tx="ekr.20140103102956.4168">@language python

# An organizer node

# Another line.
</t>
<t tx="ekr.20140103102956.4169"></t>
<t tx="ekr.20140103102956.4170">@language python

def spam():
    pass
</t>
<t tx="ekr.20140103102956.4171"></t>
<t tx="ekr.20140103102956.4172">@language html

&lt;!-- comment --&gt;

&lt;!-- comment
continued comment
--&gt;

</t>
<t tx="ekr.20140103102956.4173"></t>
<t tx="ekr.20140103102956.4174">@language html

&lt;!-- comment --&gt;

&lt;p&gt; oops &lt;/p&gt;

&lt;!-- comment
continued comment
--&gt;

</t>
<t tx="ekr.20140103102956.4175"></t>
<t tx="ekr.20140103102956.4176">vc = c.viewController
unl = vc.unl(p)
assert unl.endswith('--&gt;'+p.h),repr(unl)
</t>
<t tx="ekr.20140103102956.4184">vc = c.viewController
views = g.findNodeAnywhere(c,'@views')
assert views
views.deleteAllChildren()
view = g.findNodeInTree(c,p,'@view test')
assert view
assert c.positionExists(view)
try:
    c.selectPosition(view)
    v_b = view.b
    vc.pack()
    assert c.p.v == view.v
    vc.unpack()
    assert view.b == v_b,view.b
    assert view.lastChild().isCloned()
finally:
    # views.deleteAllChildren()
    c.undoer.clearUndoState()
    c.redraw()
</t>
<t tx="ekr.20140103102956.4186">view body
</t>
<t tx="ekr.20140103102956.4187">not a clone text
</t>
<t tx="ekr.20140103102956.4188">clone body
</t>
<t tx="ekr.20140105185509.4140">vc = c.viewController
views = g.findNodeAnywhere(c,'@views')
if views: views.deleteAllChildren()
root_restore = g.findNodeInTree(c,p,'root_restore')
assert root_restore
root_before = g.findNodeInTree(c,p,'root_before')
assert root_before
root_after = g.findNodeInTree(c,p,'root_after')
if root_after: root_after.doDelete()
    # Root after: the results of the previous test.
c.selectPosition(root_restore)
c.copyOutline()
c.selectPosition(root_before)
c.pasteOutline()
root_after = c.p
try:
    # The roots must look like @auto nodes.
    root_before.h = '@auto root_before'
    root_after.h = '@auto root_after'
    vc.init() # Required.
    vc.update_before_write_at_auto_file(root_before)
    organizers = vc.has_at_organizers_node(root_before)
    assert organizers
    vc.create_organizer_nodes(organizers,root_after)
    ok = vc.compare_test_trees(root_before,root_after)
    assert ok,'\n\nexpected...\n%s\ngot...\n%s' % (
        vc.trial_write(root_before),vc.trial_write(root_after))
finally:
     # Make sure the roots are *not* @auto nodes.
    root_before.h = 'root_before'
    root_after.h = 'root_after'
    # Replace root_after by a copy of root_restore.
    # This ensures that the unit test can be run more than once.
    if 0:
        root_after.doDelete()
        c.selectPosition(root_restore)
        c.copyOutline()
        c.selectPosition(root_before)
        c.pasteOutline()
        assert c.p.h == 'root_restore'
        c.p.h = 'root_after'
        c.redraw()
</t>
<t tx="ekr.20140105185509.4141">@others
</t>
<t tx="ekr.20140105185509.4142">class aClass:
    @others
</t>
<t tx="ekr.20140105185509.4143">def before():
    pass
</t>
<t tx="ekr.20140105185509.4144"></t>
<t tx="ekr.20140105185509.4145">def child1():
    pass
</t>
<t tx="ekr.20140105185509.4146">def child2():
    pass
</t>
<t tx="ekr.20140105185509.4147">def after():
    pass
</t>
<t tx="ekr.20140105185509.4181">vc = c.viewController
root = g.findNodeInTree(c,p,'root')
assert root
views = g.findNodeAnywhere(c,'@views')
if views:
    views.deleteAllChildren()
try:
    root.h = '@auto root' # root must look like an @auto node.
    vc.update_before_write_at_auto_file(root)
    views = g.findNodeAnywhere(c,'@views')
    assert views
    clones = g.findNodeInTree(c,views,'@clones')
    assert clones
    assert clones.b.endswith('aClass--&gt;clone\n'),repr(clones.b)
    organizer = g.findNodeInTree(c,views,'@organizer: organizer node')
    assert organizer
    s1 = 'unl: organizer node--&gt;child1'
    s2 = 'unl: organizer node--&gt;child2'
    assert organizer.b == '\n'.join([s1,s2]),organizer.b
finally:
    root.h = 'root' # Make sure root is *not* an @auto node.
    if False and views:
        views.deleteAllChildren()
    c.redraw()
</t>
<t tx="ekr.20140105185509.4182"></t>
<t tx="ekr.20140105185509.4183">class aClass:
    @others
</t>
<t tx="ekr.20140105185509.4185"></t>
<t tx="ekr.20140105185509.4186">def spam():
    pass
</t>
<t tx="ekr.20140105185509.4187"></t>
<t tx="ekr.20140105185509.4198"># Test vc.has_at_auto_view_node, vc.has_at_clones_node and vc.has_at_organizers_node.
vc = c.viewController
views = g.findNodeAnywhere(c,'@views')
if views:
    assert vc.has_at_views_node()
    views.deleteAllChildren()
else:
    assert not vc.has_at_views_node()
    views = vc.find_at_views_node()
assert views
root = g.findNodeInTree(c,p,'root')
assert root
# The representative of clone_test node must appear outside of root's tree.
clone_test = g.findNodeInTree(c,p,'clone-test')
assert clone_test
assert clone_test.v == root.next().v,(clone_test.v,root.next().v)
try:
    root.h = '@auto root' # root must look like an @auto node.
    vc.update_before_write_at_auto_file(root)
    auto_view = g.findNodeInTree(c,views,'@auto-view:root')
    assert auto_view
    auto_view2 = vc.has_at_auto_view_node(root)
    assert auto_view2
    assert auto_view2 == auto_view,(auto_view,auto_view2)
    clones = g.findNodeInTree(c,auto_view,'@clones')
    assert clones
    clones2 = vc.has_at_clones_node(root)
    assert clones2
    assert clones2 == clones
    organizers = g.findNodeInTree(c,auto_view,'@organizers')
    assert organizers
    organizers2 = vc.has_at_organizers_node(root)
    assert organizers2
    assert organizers2 == organizers
finally:
    root.h = 'root' # Make sure root is *not* an @auto node.
    c.redraw()
</t>
<t tx="ekr.20140105185509.4199">@others
</t>
<t tx="ekr.20140105185509.4200">class aClass:
    @others
</t>
<t tx="ekr.20140105185509.4202"></t>
<t tx="ekr.20140105185509.4203">def spam():
    pass
</t>
<t tx="ekr.20140105185509.4204">def clone_test():
    pass
</t>
<t tx="ekr.20140105185509.4216"></t>
<t tx="ekr.20140105190941.4170">@others
</t>
<t tx="ekr.20140105190941.4171">class aClass:
    @others
</t>
<t tx="ekr.20140105190941.4172">def before():
    pass
</t>
<t tx="ekr.20140105190941.4174">def child1():
    pass
</t>
<t tx="ekr.20140105190941.4175">def extra2():
    pass
</t>
<t tx="ekr.20140105190941.4176">def child2():
    pass
</t>
<t tx="ekr.20140105190941.4178">def after():
    pass
</t>
<t tx="ekr.20140105222052.4170">vc = c.viewController
views = g.findNodeAnywhere(c,'@views')
assert views
views.deleteAllChildren()
views.b = None ####
root1 = g.findNodeInTree(c,p,'root1')
assert root1
try:
    root1.h = '@auto root1'
finally:
    root1.h = 'root1'
</t>
<t tx="ekr.20140105222052.4171"></t>
<t tx="ekr.20140105222052.4172"></t>
<t tx="ekr.20140106094713.4176">vc = c.viewController
organizer_unls = [
    'a--&gt;O1',
    'a--&gt;O1--&gt;O2',
    'a--&gt;O3',
    'a--&gt;O3--&gt;b--&gt;O4',
    'z',
]
table = (
    ('z--&gt;x','x'), # Test of dropping a leading --&gt;.
    ('a--&gt;O1--&gt;unl1','a--&gt;unl1'),
    ('a--&gt;O1--&gt;O2--&gt;unl2','a--&gt;unl2'),
    ('a--&gt;O3--&gt;unl3','a--&gt;unl3'),
    ('a--&gt;O3--&gt;b--&gt;O4--&gt;unl4','a--&gt;b--&gt;unl4'),
)
for unl,expected in table:
    got = vc.drop_all_organizers_in_unl(organizer_unls,unl)
    assert expected == got,'\nunl:      %s\nexpected: %s\ngot:      %s' % (unl,expected,got)
</t>
<t tx="ekr.20140106135225.4203">vc = c.viewController
views = g.findNodeAnywhere(c,'@views')
if views: views.deleteAllChildren()
    # Start with a pristine @views tree.
root_before  = g.findNodeInTree(c,p,'root_before')
    # Root before: used to generate @auto-view tree.
root_restore = g.findNodeInTree(c,p,'root_restore')
    # Create root_after from root_restore.
assert root_before,root_restore
root_after  = g.findNodeInTree(c,p,'root_after')
if root_after: root_after.doDelete()
    # Root after: the results of the previous test.
c.selectPosition(root_restore)
c.copyOutline()
c.selectPosition(root_before)
c.pasteOutline()
# The roots must look like @auto nodes.
root_after = c.p
assert root_after.h == 'root_restore',root_after.h
root_before.h = '@auto root_before'
root_after.h = '@auto root_after' 
try:
    vc.init() # Required.
    vc.update_before_write_at_auto_file(root_before)
    at_organizers = vc.has_at_organizers_node(root_before)
    assert at_organizers
    vc.create_organizer_nodes(at_organizers,root_after)
    ok = vc.compare_test_trees(root_before,root_after)
    assert ok,'\n\nexpected...\n%s\ngot...\n%s' % (
        vc.trial_write(root_before),vc.trial_write(root_after))
finally:
     # Make sure the roots are *not* @auto nodes.
    root_before.h = 'root_before'
    root_after.h = 'root_after'
    c.redraw()
</t>
<t tx="ekr.20140106135225.4204">@others
</t>
<t tx="ekr.20140106135225.4213">@others
</t>
<t tx="ekr.20140106135225.4214">class aClass:
    @others
</t>
<t tx="ekr.20140106135225.4215">def before(self):
    pass
</t>
<t tx="ekr.20140106135225.4216"></t>
<t tx="ekr.20140106135225.4217">def child11(self):
    pass
</t>
<t tx="ekr.20140106135225.4218">def child12(self):
    pass
</t>
<t tx="ekr.20140106135225.4219">def after(self):
    pass
</t>
<t tx="ekr.20140106135225.4229"></t>
<t tx="ekr.20140106135225.4233"></t>
<t tx="ekr.20140106135225.4234">def child21(self):
    pass
</t>
<t tx="ekr.20140106135225.4235">def child22(self):
    pass
</t>
<t tx="ekr.20140106135225.4285">class aClass:
    @others
</t>
<t tx="ekr.20140106135225.4286">def before(self):
    pass
</t>
<t tx="ekr.20140106135225.4289">def child11(self):
    pass
</t>
<t tx="ekr.20140106135225.4290">def child12(self):
    pass
</t>
<t tx="ekr.20140106135225.4292">def child21(self):
    pass
</t>
<t tx="ekr.20140106135225.4293">def child22(self):
    pass
</t>
<t tx="ekr.20140106135225.4294">def after(self):
    pass
</t>
<t tx="ekr.20140108143431.4248">def middle():
    pass
</t>
<t tx="ekr.20140108143431.4249">def middle():
    pass
</t>
<t tx="ekr.20140109035139.4274"></t>
<t tx="ekr.20140109035139.4276">def last1():
    pass
</t>
<t tx="ekr.20140109035139.4277">def last1():
    pass
</t>
<t tx="ekr.20140109162112.4219">aList = [p.copy() for p in c.all_positions()]
aList2 = sorted(reversed(aList),key=p.sort_key)
i = 0
for p in aList2:
    p2 = aList[i]
    i += 1
    assert p == p2,'\n%s:%s\n%s:%s' % (
        p.sort_key(p),p.h,p2.sort_key(p2),p2.h)
</t>
<t tx="ekr.20140109180433.4248">def top1():
    pass
</t>
<t tx="ekr.20140109180433.4249">def top2():
    pass
</t>
<t tx="ekr.20140109180433.4253"></t>
<t tx="ekr.20140109180433.4254">def top1():
    pass
</t>
<t tx="ekr.20140109180433.4255">def top2():
    pass
</t>
<t tx="ekr.20140110044125.4362"># To remind ourselves of the status of new_import.
import leo.core.leoAtFile as atFile
print('new_import: %s' % atFile.new_auto)
</t>
<t tx="ekr.20140110141116.4267">vc = c.viewController
views = g.findNodeAnywhere(c,'@views')
if views: views.deleteAllChildren()
    # Start with a pristine @views tree.
root_before  = g.findNodeInTree(c,p,'root_before')
    # Root before: used to generate @auto-view tree.
root_restore = g.findNodeInTree(c,p,'root_restore')
    # Create root_after from root_restore.
assert root_before,root_restore
root_after  = g.findNodeInTree(c,p,'root_after')
if root_after: root_after.doDelete()
    # Root after: the results of the previous test.
c.selectPosition(root_restore)
c.copyOutline()
c.selectPosition(root_before)
c.pasteOutline()
# The roots must look like @auto nodes.
root_after = c.p
assert root_after.h == 'root_restore',root_after.h
root_before.h = '@auto root_before'
root_after.h = '@auto root_after' 
try:
    vc.update_before_write_at_auto_file(root_before)
    at_organizers = vc.has_at_organizers_node(root_before)
    assert at_organizers
    # Called by vc.create_organizer_nodes(organizers,root_after):
    root = root_after
    vc.create_organizer_data(at_organizers,root)
    vc.create_actual_organizer_nodes()
    vc.create_tree_structure(root)
    # The body of demote_organized_nodes:
    for od in vc.all_ods:
        # Called by vc.update_helper.
        od_list = vc.find_all_organizer_nodes(od)
        assert od in od_list,od_list
    d = {
        'organizer node': ['intermediate node','inner org1','inner org2'],
        'intermediate node': ['inner org1','inner org2'],
    }
    for od in vc.organizer_data_list:
        aList = d.get(od.h,[])
        aList2 = [z.h for z in od.descendants or []]
        assert sorted(aList) == sorted(aList2),(aList,aList2)
finally:
    # Make sure the roots are *not* @auto nodes.
    vc.temp_node.doDelete()
    root_before.h = 'root_before'
    root_after.h = 'root_after'
    c.redraw()
</t>
<t tx="ekr.20140110141116.4322">@others
</t>
<t tx="ekr.20140110141116.4323">class aClass:
    @others
</t>
<t tx="ekr.20140110141116.4324">def spam_before(self):
    pass
</t>
<t tx="ekr.20140110141116.4325">def spam11(self):
    pass
</t>
<t tx="ekr.20140110141116.4326">def spam12(self):
    pass
</t>
<t tx="ekr.20140110141116.4327">def middle_spam():
    pass
</t>
<t tx="ekr.20140110141116.4328">def spam21(self):
    pass
</t>
<t tx="ekr.20140110141116.4329">def spam22(self):
    pass
</t>
<t tx="ekr.20140110141116.4330">def spam_after(self):
    pass
</t>
<t tx="ekr.20140110141116.4331">def spam_last1():
    pass
</t>
<t tx="ekr.20140110141116.4332">def spam_top1():
    pass
</t>
<t tx="ekr.20140110141116.4333">def spam_top2():
    pass
</t>
<t tx="ekr.20140110141116.4351">@others
</t>
<t tx="ekr.20140110141116.4352">class aClass:
    @others
</t>
<t tx="ekr.20140110141116.4353">def spam_before(self):
    pass
</t>
<t tx="ekr.20140110141116.4354"></t>
<t tx="ekr.20140110141116.4355"></t>
<t tx="ekr.20140110141116.4356">def spam11(self):
    pass
</t>
<t tx="ekr.20140110141116.4357">def spam12(self):
    pass
</t>
<t tx="ekr.20140110141116.4358">def middle_spam():
    pass
</t>
<t tx="ekr.20140110141116.4359"></t>
<t tx="ekr.20140110141116.4360">def spam21(self):
    pass
</t>
<t tx="ekr.20140110141116.4361">def spam22(self):
    pass
</t>
<t tx="ekr.20140110141116.4362">def spam_after(self):
    pass
</t>
<t tx="ekr.20140110141116.4363"></t>
<t tx="ekr.20140110141116.4364">def spam_last1():
    pass
</t>
<t tx="ekr.20140110141116.4365"></t>
<t tx="ekr.20140110141116.4366">def spam_top1():
    pass
</t>
<t tx="ekr.20140110141116.4367">def spam_top2():
    pass
</t>
<t tx="ekr.20140110141116.4368"></t>
<t tx="ekr.20140111164124.4414">vc = c.viewController
views = g.findNodeAnywhere(c,'@views')
if views: views.deleteAllChildren()
    # Start with a pristine @views tree.
root_before  = g.findNodeInTree(c,p,'root_before')
    # Root before: used to generate @auto-view tree.
root_restore = g.findNodeInTree(c,p,'root_restore')
    # Create root_after from root_restore.
assert root_before,root_restore
root_after  = g.findNodeInTree(c,p,'root_after')
if root_after: root_after.doDelete()
    # Root after: the results of the previous test.
c.selectPosition(root_restore)
c.copyOutline()
c.selectPosition(root_before)
c.pasteOutline()
# The roots must look like @auto nodes.
root_after = c.p
assert root_after.h == 'root_restore',root_after.h
root_before.h = '@auto root_before'
root_after.h = '@auto root_after' 
try:
    vc.init() # Required.
    vc.update_before_write_at_auto_file(root_before)
    at_organizers = vc.has_at_organizers_node(root_before)
    assert at_organizers
    vc.create_organizer_nodes(at_organizers,root_after)
    ok = vc.compare_test_trees(root_before,root_after)
    assert ok,'\n\nexpected...\n%s\ngot...\n%s' % (
        vc.trial_write(root_before),vc.trial_write(root_after))
finally:
     # Make sure the roots are *not* @auto nodes.
    root_before.h = 'root_before'
    root_after.h = 'root_after'
    c.redraw()
</t>
<t tx="ekr.20140111164124.4415">@others
</t>
<t tx="ekr.20140111164124.4416">class aClass:
    @others
</t>
<t tx="ekr.20140111164124.4417">def before(self):
    pass
</t>
<t tx="ekr.20140111164124.4418">def child11(self):
    pass
</t>
<t tx="ekr.20140111164124.4419">def child12(self):
    pass
</t>
<t tx="ekr.20140111164124.4420">def middle():
    pass
</t>
<t tx="ekr.20140111164124.4421">def child21(self):
    pass
</t>
<t tx="ekr.20140111164124.4422">def child22(self):
    pass
</t>
<t tx="ekr.20140111164124.4423">def after(self):
    pass
</t>
<t tx="ekr.20140111164124.4424">def last1():
    pass
</t>
<t tx="ekr.20140111164124.4425">def top1():
    pass
</t>
<t tx="ekr.20140111164124.4426">def top2():
    pass
</t>
<t tx="ekr.20140111164124.4427">@others
</t>
<t tx="ekr.20140111164124.4428">class aClass:
    @others
</t>
<t tx="ekr.20140111164124.4429">def before(self):
    pass
</t>
<t tx="ekr.20140111164124.4430"></t>
<t tx="ekr.20140111164124.4431"></t>
<t tx="ekr.20140111164124.4432">def child11(self):
    pass
</t>
<t tx="ekr.20140111164124.4433">def child12(self):
    pass
</t>
<t tx="ekr.20140111164124.4434">def middle():
    pass
</t>
<t tx="ekr.20140111164124.4435"></t>
<t tx="ekr.20140111164124.4436">def child21(self):
    pass
</t>
<t tx="ekr.20140111164124.4437">def child22(self):
    pass
</t>
<t tx="ekr.20140111164124.4438">def after(self):
    pass
</t>
<t tx="ekr.20140111164124.4439"></t>
<t tx="ekr.20140111164124.4440">def last1():
    pass
</t>
<t tx="ekr.20140111164124.4441"></t>
<t tx="ekr.20140111164124.4442">def top1():
    pass
</t>
<t tx="ekr.20140111164124.4443">def top2():
    pass
</t>
<t tx="ekr.20140113034711.4461">def extra2():
    pass
</t>
<t tx="ekr.20140121160228.4834">@others
</t>
<t tx="ekr.20140121160228.4835">class aClass:
    @others
</t>
<t tx="ekr.20140121160228.4836">def spam_before(self):
    pass
</t>
<t tx="ekr.20140121160228.4837">def spam11(self):
    pass
</t>
<t tx="ekr.20140121160228.4838">def spam12(self):
    pass
</t>
<t tx="ekr.20140121160228.4839">def middle_spam():
    pass
</t>
<t tx="ekr.20140121160228.4840">def spam21(self):
    pass
</t>
<t tx="ekr.20140121160228.4841">def spam22(self):
    pass
</t>
<t tx="ekr.20140121160228.4842">def spam_after(self):
    pass
</t>
<t tx="ekr.20140121160228.4843">def spam_last1():
    pass
</t>
<t tx="ekr.20140121160228.4844">def spam_top1():
    pass
</t>
<t tx="ekr.20140121160228.4845">def spam_top2():
    pass
</t>
<t tx="ekr.20140211090146.4438"></t>
<t tx="ekr.20140211090146.4446">@others
</t>
<t tx="ekr.20140211090146.4447">class aClass:
    @others
</t>
<t tx="ekr.20140211090146.4448">def before():
    pass
</t>
<t tx="ekr.20140211090146.4452">def after():
    pass
</t>
<t tx="ekr.20140211090146.4459"></t>
<t tx="ekr.20140211090146.4460">def child1():
    pass
</t>
<t tx="ekr.20140211090146.4461">def extra2():
    pass
</t>
<t tx="ekr.20140211090146.4462">def child2():
    pass
</t>
<t tx="ekr.20140211090146.4494">@others
</t>
<t tx="ekr.20140211090146.4495">class aClass:
    @others
</t>
<t tx="ekr.20140211090146.4496">def before(self):
    pass
</t>
<t tx="ekr.20140211090146.4502">def after(self):
    pass
</t>
<t tx="ekr.20140211090146.4516"></t>
<t tx="ekr.20140211090146.4518"></t>
<t tx="ekr.20140211090146.4520"></t>
<t tx="ekr.20140211090146.4522"></t>
<t tx="ekr.20140211090146.4525">def middle():
    pass
</t>
<t tx="ekr.20140211090146.4526">def child11(self):
    pass
</t>
<t tx="ekr.20140211090146.4527">def child12(self):
    pass
</t>
<t tx="ekr.20140211090146.4528">def child21(self):
    pass
</t>
<t tx="ekr.20140211090146.4529">def child22(self):
    pass
</t>
<t tx="ekr.20140211090146.4530">def last1():
    pass
</t>
<t tx="ekr.20140211090146.4545">@others
</t>
<t tx="ekr.20140211090146.4546">class aClass:
    @others
</t>
<t tx="ekr.20140211090146.4547">def before(self):
    pass
</t>
<t tx="ekr.20140211090146.4553">def after(self):
    pass
</t>
<t tx="ekr.20140211090146.4567"></t>
<t tx="ekr.20140211090146.4569"></t>
<t tx="ekr.20140211090146.4571"></t>
<t tx="ekr.20140211090146.4573"></t>
<t tx="ekr.20140211090146.4576">def middle():
    pass
</t>
<t tx="ekr.20140211090146.4577">def child11(self):
    pass
</t>
<t tx="ekr.20140211090146.4578">def child12(self):
    pass
</t>
<t tx="ekr.20140211090146.4579">def child21(self):
    pass
</t>
<t tx="ekr.20140211090146.4580">def child22(self):
    pass
</t>
<t tx="ekr.20140211090146.4581">def last1():
    pass
</t>
<t tx="ekr.20140217055617.4231"># For a unit test.</t>
<t tx="ekr.20140716121225.4354">print(p.v.gnx)</t>
<t tx="ekr.20140902101931.4478"></t>
<t tx="ekr.20140906072925.5224"></t>
<t tx="ekr.20141111092038.12">s = '''

# Header

After header text

## Subheader

After subheader text

'''

g.app.unitTestDict ['expectedErrors'] = 0
c.importCommands.markdownUnitTest(p,s=s,showTree=False)
</t>
<t tx="ekr.20150208213643.12">def spam():
    pass</t>
<t tx="ekr.20150208213643.13">def eggs():
    pass</t>
<t tx="ekr.20150208213643.15">def spam():
    pass</t>
<t tx="ekr.20150208213643.16">def eggs():
    pass</t>
<t tx="ekr.20150208213643.18"># node 1 text A.
</t>
<t tx="ekr.20150208213643.19"># node 2 text B.
</t>
<t tx="ekr.20150214063940.11"></t>
<t tx="ekr.20150216110251.11"># Do not delete this node.
# It is used by unit tests.</t>
<t tx="ekr.20150321155210.11"></t>
<t tx="ekr.20150529183247.1">import leo.core.leoBeautify as leoBeautify
for p in p.children():
    b = leoBeautify.PythonTokenBeautifier(c)
    s1 = p.b
    comment,s = b.comment_leo_lines(p)
    s2 = b.uncomment_leo_lines(comment,p,s)
    assert s1 == s2,('\ns...\n%s\ns2...\n%s' % (s,s2))
</t>
<t tx="ekr.20150529183259.1">def f ():
    pass
@ Line 1
    Line 2
</t>
<t tx="ekr.20150529184545.1">def f(): 
    pass
@ The following could be added to the 'else' clause::
    # Accumulate everything else.
</t>
<t tx="ekr.20150602215639.1">True: Automatically beautify all @&lt;file&gt; nodes when saving an outline.

# This *must* be False in unitTest.leo!</t>
<t tx="ekr.20150625052701.1">gnx: ekr.20080904084223.1
</t>
<t tx="ekr.20150625091937.3">gnx: ekr.20110610122533.3407
</t>
<t tx="ekr.20150625101047.1"># Not valid for external tests: uses @&lt;file&gt; node.
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    trace = False
    root = p.parent().parent()
    # h = '@auto unittest/at-auto-line-number-test.py'
    h = '@auto unittest/at-auto-unit-test.py'
    target = g.findNodeAnywhere(c, h)
    assert target, 'no target'
    s = c.gotoCommands.get_external_file_with_sentinels(target)
    if trace:
        g.cls()
        print(''.join(['%3s %s' % (i, s) for i, s in enumerate(g.splitLines(s))]))
    for n in range(25):
        p, offset, found = c.gotoCommands.find_file_line(n, p=target)
        if found:
            if trace: print('found %2s %2s %s' % (n, offset, p and p.h))
        else:
            assert n == 13, n
            if trace: print('not found: %s' % n)
            break
</t>
<t tx="ekr.20150625134618.1">gnx: ekr.20150625134601.13
unl: at_auto_child
</t>
<t tx="ekr.20150626093653.1"># Not valid for external tests: uses @&lt;file&gt; node.
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    trace = False
    h = '@auto-rst unittest/at-auto-rst-line-number-test.py'
    root = g.findNodeAnywhere(c, h)
    assert root
    assert root.isAtAutoRstNode(), root
    s = c.gotoCommands.get_external_file_with_sentinels(root)
    if trace:
        g.cls()
        print(''.join(['%3s %s' % (i, s) for i, s in enumerate(g.splitLines(s))]))
    for n in range(20):
        p, offset, found = c.gotoCommands.find_file_line(n, p=root)
        if found:
            if trace: print('found: %2s %2s %s' % (n, offset, p and p.h))
        else:
            if trace: print('not found: %s' % n)
            assert n == 9, n
            break
</t>
<t tx="ekr.20150626093952.1">gnx: ekr.20150626093745.1
</t>
<t tx="ekr.20150626100652.1"># Not valid for external tests: uses @&lt;file&gt; node.
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    trace = False
    h = '@auto-otl unittest/at-auto-otl-line-number-test.py'
    root = g.findNodeAnywhere(c, h)
    assert root
    s = c.gotoCommands.get_external_file_with_sentinels(root)
    if trace:
        g.cls()
        print(''.join(['%3s %s' % (i, s) for i, s in enumerate(g.splitLines(s))]))
    for n in range(20):
        p, offset, found = c.gotoCommands.find_file_line(n, p=root)
        if found:
            if trace: print('found: %2s %2s %s' % (n, offset, p and p.h))
        else:
            if trace: print('not found: %s' % n)
            assert n == 5, n
            break
</t>
<t tx="ekr.20150626100832.1">gnx: ekr.20150626100719.1
</t>
<t tx="ekr.20150626101643.1"># Not valid for external tests: uses @&lt;file&gt; node.
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    trace = False
    h = '@auto-org unittest/at-auto-org-line-number-test.py'
    root = g.findNodeAnywhere(c, h)
    assert root
    s = c.gotoCommands.get_external_file_with_sentinels(root)
    if trace:
        g.cls()
        print(''.join(['%3s %s' % (i, s) for i, s in enumerate(g.splitLines(s))]))
    for n in range(20):
        p, offset, found = c.gotoCommands.find_file_line(n, p=root)
        if found:
            if trace: print('found: %2s %2s %s' % (n, offset, p and p.h))
        else:
            if trace: print('not found: %s' % n)
            assert n == 5, n
            break
</t>
<t tx="ekr.20150626101730.1">gnx: ekr.20150626101627.1
</t>
<t tx="ekr.20150626101920.1"># Not valid for external tests: uses @&lt;file&gt; node.
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    trace = False
    h = '@auto unittest/at-auto-md-line-number-test.md'
    root = g.findNodeAnywhere(c, h)
    assert root
    s = c.gotoCommands.get_external_file_with_sentinels(root)
    if trace:
        g.cls()
        print(''.join(['%3s %s' % (i, s) for i, s in enumerate(g.splitLines(s))]))
    for n in range(20):
        p, offset, found = c.gotoCommands.find_file_line(n, p=root)
        if found:
            if trace: print('found: %2s %2s %s' % (n, offset, p and p.h))
        else:
            if trace: print('not found: %s' % n)
            assert n == 7, n
            break
</t>
<t tx="ekr.20150626102601.1">gnx: ekr.20150626101842.1
</t>
<t tx="ekr.20160318094009.1">if not g.isPython3:
    self.skipTest('python 3 test')
else:
    import leo.core.leoAst as leoAst
    import leo.external.make_stub_files as msf
    import leo.external.py2cs as py2cs
    import ast, tokenize
    path = g.os_path_finalize_join(g.app.loadDir,
        '..', 'test', 'unittest', 'python3_test.py')
    assert g.os_path_exists(path), path
    fn = g.shortFileName(path)
    source = open(path, 'r').read()
    node = ast.parse(source, filename=fn, mode='exec')
    src = open(path, 'r').read()
    readlines = g.ReadLinesClass(src).next
    tokens = list(tokenize.generate_tokens(readlines))
    leoAst.AstFullTraverser().visit(node)
    s = leoAst.HTMLReportTraverser(debug=True).main(fn, node)
    assert s
    s = leoAst.AstFormatter().format(node)
    assert s
    s = py2cs.CoffeeScriptTraverser(controller=g.NullObject()).format(node, src, tokens)
    assert s
    controller = msf.StandAloneMakeStubFile()
    msf.StubTraverser(controller).visit(node)
</t>
<t tx="ekr.20160327132053.1"># Mimic the code in g.get_directives_dict
import re
pat = g.compute_directives_re()
pat = re.compile(pat, re.MULTILINE)
table = (
    '@wrap', # The failure case.
    '@wrap ',
    '@wrap\n',
    '@wrap\t',
)
for s in table:
    m = pat.search(s)
    assert m, repr(s)
</t>
<t tx="ekr.20160330182418.1"></t>
<t tx="ekr.20160403123650.1"># Not valid for external tests: uses @&lt;file&gt; node.
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    trace = False
    root = p.parent().parent()
    h = '@file unittest/at-file-line-number-test.c'
    target = g.findNodeAnywhere(c, h)
    assert target, 'no target'
    s = c.gotoCommands.get_external_file_with_sentinels(target)
    if trace:
        g.cls()
        print(''.join(['%3s %s' % (i, s) for i, s in enumerate(g.splitLines(s))]))
    for n in range(20):
        p, offset, found = c.gotoCommands.find_file_line(n, p=target)
        if found:
            if trace: print('found %2s %2s %s' % (n, offset, p and p.h))
        else:
            assert n == 10, n
            if trace: print('not found: %s' % n)
            break
</t>
<t tx="ekr.20160403143048.1">@language c
@tabwidth -4
// before @others // line 1
@others
// last line: line 6
</t>
<t tx="ekr.20160403143048.2">@nocolor-node
def spam(): // line 2
    pass
</t>
<t tx="ekr.20160403143130.1">@language python
@tabwidth -4
# Before @others: line 1
@others
# Last line: line 6
</t>
<t tx="ekr.20160403143348.1">gnx: ekr.20111214104615.3942
</t>
<t tx="ekr.20160403143348.2">gnx: ekr.20160403142841.9
unl: at-auto-section-ref-test declarations
</t>
<t tx="ekr.20160403143351.1">gnx: ekr.20090704085350.5056
</t>
<t tx="ekr.20160403143351.2">gnx: ekr.20160403142841.10
unl: spam
gnx: ekr.20160403142841.11
unl: eggs
</t>
<t tx="ekr.20160403143643.1"># Not valid for external tests: uses @&lt;file&gt; node.
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    trace = False
    root = p.parent().parent()
    h = '@clean unittest/at-clean-line-number-test.c'
    target = g.findNodeAnywhere(c, h)
    assert target, 'no target'
    s = c.gotoCommands.get_external_file_with_sentinels(target)
    lines = g.splitLines(s)
    stripped_lines = [z for z in lines if not z.startswith('//@')]
    if trace:
        g.cls()
        print(''.join(['%3s %s' % (i, s) for i, s in enumerate(lines)]))
    table = (
        # n is the 1-based offset
        (3, 4,  '// before @others // line 1'),
        (2, 8,  'def spam(): // line 2'),
        (3, 9,  '    pass'),
        (1, 11, 'def eggs(): // line 4'),
        (2, 12, '    pass'),
        (5, 14, '// last line: line 6'),
    )
    for i, data in enumerate(table):
        expected_offset, target_offset, expected_line = data
        p, offset, found = c.gotoCommands.find_file_line(i+1, p=target)
        assert expected_offset == offset, (
            'i: %s expected offset %s, got %s' % (i, expected_offset, offset))
        expected_line = expected_line.rstrip()
        got_line = stripped_lines[i].rstrip()
        assert expected_line == got_line, 'i: %s expected line:\n%s\ngot line:\n%s' % (
            i, expected_line, got_line)
        got_line2 = lines[target_offset].rstrip()
        assert expected_line == got_line2, 'i: %s expected line:\n%s\ngot line2:\n%s' % (
            i, expected_line, got_line)
    i = len(table)
    p, offset, found = c.gotoCommands.find_file_line(i+1, p=target)
    assert not found
</t>
<t tx="ekr.20160403143655.1"># Not valid for external tests: uses @&lt;file&gt; node.
if g.app.isExternalUnitTest:
    self.skipTest('Can not be run externally')
else:
    trace = False
    root = p.parent().parent()
    h = '@clean unittest/at-clean-line-number-test.py'
    target = g.findNodeAnywhere(c, h)
    assert target, 'no target'
    s = c.gotoCommands.get_external_file_with_sentinels(target)
    lines = g.splitLines(s)
    stripped_lines = [z for z in lines if not z.startswith('#@')]
    if trace:
        print(''.join(['%3s %s' % (i, s) for i, s in enumerate(lines)]))
        # print('')
        # print(''.join(['%3s %s' % (i, s) for i, s in enumerate(stripped_lines)]))
    table = (
        # n is the 1-based offset
        (3, 4,  '# Before @others: line 1'),
        (2, 8,  'def spam(): # line 2'),
        (3, 9,  '    pass'),
        (1, 11, 'def eggs(): # line 4'),
        (2, 12, '    pass'),
        (5, 14, '# Last line: line 6'),
    )
    for i, data in enumerate(table):
        expected_offset, target_offset, expected_line = data
        p, offset, found = c.gotoCommands.find_file_line(i+1, p=target)
        assert expected_offset == offset, (
            'i: %s expected offset %s, got %s' % (i, expected_offset, offset))
        expected_line = expected_line.rstrip()
        got_line = stripped_lines[i].rstrip()
        assert expected_line == got_line, 'i: %s expected line:\n%s\ngot line:\n%s' % (
            i, expected_line, got_line)
        got_line2 = lines[target_offset].rstrip()
        assert expected_line == got_line2, 'i: %s expected line:\n%s\ngot line2:\n%s' % (
            i, expected_line, got_line)
    i = len(table)
    p, offset, found = c.gotoCommands.find_file_line(i+1, p=target)
    assert not found
</t>
<t tx="ekr.20160403150121.1">def eggs(): // line 4
    pass</t>
<t tx="ekr.20160403150216.1">@nocolor-node
def spam(): # line 2
    pass
</t>
<t tx="ekr.20160403150222.1">def eggs(): # line 4
    pass
</t>
<t tx="ekr.20160403152507.1">def eggs(): # line 4
    pass</t>
<t tx="ekr.20160403165231.9">gnx: ekr.20160403164217.4
unl: section 1
gnx: ekr.20160403164217.5
unl: section 2
</t>
<t tx="ekr.20160403165232.2">gnx: ekr.20160403164217.15
unl: section 1
gnx: ekr.20160403164217.16
unl: section 2
</t>
<t tx="ekr.20160403165232.24">gnx: ekr.20160403164217.9
unl: class child1
gnx: ekr.20160403164217.10
unl: class child1--&gt;child1_method1
gnx: ekr.20160403164217.11
unl: class child1--&gt;child1_method2
gnx: ekr.20160403164217.12
unl: class child2
gnx: ekr.20160403164217.13
unl: class child2--&gt;child2_method1
gnx: ekr.20160403164217.14
unl: class child2--&gt;child2_method2
</t>
<t tx="ekr.20160403165232.9">gnx: ekr.20160403164217.17
unl: section 1
gnx: ekr.20160403164217.18
unl: section 2
</t>
<t tx="ekr.20160403165233.11">gnx: ekr.20160403164217.19
unl: section 1
gnx: ekr.20160403164217.20
unl: section 2
</t>
<t tx="ekr.20160410152100.1"></t>
<t tx="ekr.20160410152100.2">&lt;&lt; define s &gt;&gt;
g.app.unitTestDict ['expectedErrors'] = 0
g.app.unitTestDict ['expectedMismatchLine'] = None
try:
    c.importCommands.markdownUnitTest(p,s=s,showTree=True)
    table = (
        (1, 'Top'),
        (2, 'Section 1#'),
        (2, 'Section 2'),
        (3, 'Section 2.1'),
        (4, 'Section 2.1.1'),
        (3, 'Section 2.2'),
        (2, 'Section 3'),
    )
    after = p.nodeAfterTree()
    root = p.firstChild().next()
    assert root.h.startswith('@auto-m'), root.h
    p = root.firstChild()
    for n, h in table:
        n2 = p.level() - root.level()
        assert h == p.h, (h, p.h)
        assert n == n2, (n, n2, p.h)
        p.moveToThreadNext()
    assert p == after, p.h
finally:
    if 1:
        root.doDelete()
        c.redraw()
</t>
<t tx="ekr.20160411033840.1">&lt;&lt; define s &gt;&gt;
g.app.unitTestDict ['expectedErrors'] = 0
g.app.unitTestDict ['expectedMismatchLine'] = None
try:
    c.importCommands.markdownUnitTest(p,s=s,showTree=True)
    table = (
        (1, 'Top'),
        (2, 'Section 1'),
        (2, 'Section 2'),
        (3, 'Section 2.1'),
        (4, 'Section 2.1.1'),
        (3, 'Section 2.2'),
        (2, 'Section 3'),
    )
    after = p.nodeAfterTree()
    root = p.firstChild().next()
    assert root.h.startswith('@auto-m'), root.h
    p = root.firstChild()
    for n, h in table:
        n2 = p.level() - root.level()
        assert h == p.h, (h, p.h)
        assert n == n2, (n, n2, p.h)
        p.moveToThreadNext()
    assert p == after, p.h
finally:
    if 1:
        root.doDelete()
        c.redraw()
</t>
<t tx="ekr.20160411034540.1">s = '''\
#Top
The top section

##Section 1#
section 1, line 1
section 1, line 2

##Section 2
section 2, line 1

###Section 2.1
section 2.1, line 1

####Section 2.1.1
section 2.2.1 line 1

###Section 2.2

##Section 3
Section 3, line 1

'''
</t>
<t tx="ekr.20160411044042.1">s = '''\
Top
====

The top section

Section 1
---------

section 1, line 1
-- Not an underline
selction 1, line 2

Section 2
---------

section 2, line 1

###Section 2.1

section 2.1, line 1

####Section 2.1.1

section 2.2.1 line 1

###Section 2.2
section 2.2, line 1.

Section 3
---------

section 3, line 1

'''
</t>
<t tx="ekr.20160419061017.1">import leo.core.leoGui as leoGui # LeoKeyEvent
import leo.core.leoVim as leoVim # VimEvent.
import leo.plugins.qt_frame as qt_frame # EventWrapper
event = func = next_w = parent = None
char = shortcut = stroke = w = x = y = None
x_root = y_root = None
# The EventWrapper class is buried too deep to test easily.
# I'll try harder if it ever become a problem ;-)
    # dw = qt_frame.DynamicWindow(c, parent)
    # event_wrapper = dw.EventWrapper(c, w, next_w, func)
key_event = leoGui.LeoKeyEvent(
    c, char, event, shortcut,
    w, x, y, x_root, y_root)
vim_event = leoVim.VimEvent(c, char, stroke, w)
# assert hasattr(event_wrapper, 'c')
assert hasattr(key_event, 'c')
assert hasattr(vim_event, 'c')
</t>
</tnodes>
</leo_file>
