<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>learning python &#187; PyLan</title>
	<atom:link href="http://www.learningpython.com/category/python/pylan/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.learningpython.com</link>
	<description>one man's journey into python...</description>
	<lastBuildDate>Mon, 26 Apr 2010 01:21:51 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=abc</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>PyLan a GTD todo application written in python and PyGTK &#8211; part four context menus!</title>
		<link>http://www.learningpython.com/2007/09/23/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-four-context-menus/</link>
		<comments>http://www.learningpython.com/2007/09/23/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-four-context-menus/#comments</comments>
		<pubDate>Sun, 23 Sep 2007 18:18:35 +0000</pubDate>
		<dc:creator>selsine</dc:creator>
				<category><![CDATA[PyGTK]]></category>
		<category><![CDATA[PyLan]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://www.learningpython.com/?p=65</guid>
		<description><![CDATA[
			
				
			
		
PyLan Four
Hello welcome to the fourth installment of the PyLan tutorial. This will be a quick tutorial to introduce one feature: context (or popup) menus. I&#8217;ve had many questions regarding this so I thought I would take a quick stab at it.
If you want to follow along with the code in detail, and have not [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.learningpython.com%2F2007%2F09%2F23%2Fpylan-a-gtd-todo-application-written-in-python-and-pygtk-part-four-context-menus%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.learningpython.com%2F2007%2F09%2F23%2Fpylan-a-gtd-todo-application-written-in-python-and-pygtk-part-four-context-menus%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<h2>PyLan Four</h2>
<p>Hello welcome to the fourth installment of the PyLan tutorial. This will be a quick tutorial to introduce one feature: context (or popup) menus. I&#8217;ve had many questions regarding this so I thought I would take a quick stab at it.</p>
<p>If you want to follow along with the code in detail, and have not done so already, you should read <a href="http://www.learningpython.com/2007/02/17/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-one/">part one</a>, <a href="http://www.learningpython.com/2007/03/11/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-two/">part two</a> and <a href="http://www.learningpython.com/2007/07/04/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-three/">part three</a> of this series. </p>
<p>You can download the full source to this tutorial <a href="http://www.learningpython.com/sources/PyLan_04.tar.gz">here</a>.</p>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_04/pylan_04_02.png" alt="Python GTD pyGTK" border="0"/></p>
<p><span id="more-65"></span></p>
<p>This tutorial is organized into the following sections:</p>
<ol>
<li><a href="#Glade">Adding the menu in Glade</a></li>
<li><a href="#Python">Showing the menu in Python</a></li>
</ol>
<h2><a href="#Glade">Adding the menu in Glade</a></h2>
<p>So let&#8217;s startup glade and create a new popup menu item. Add the following four items to the menu:</p>
<ol>
<li>New Category. Name &#8211; &#8220;new_category_menu&#8221; Handler &#8211; &#8220;on_add_category&#8221;</li>
<li>New Task. Name &#8211; &#8220;new_task_menu&#8221; Handler &#8211; &#8220;on_add_task&#8221;</li>
<li>_Edit. Name &#8211; &#8220;edit_context_menu&#8221; Handler &#8211; &#8220;on_edit_object&#8221;</li>
<li>_Remove. Name &#8211; &#8220;remove_context_menu&#8221; Handler &#8211; &#8220;on_remove_item&#8221;</li>
</ol>
<p>Call the menu itself: contextMenu</p>
<p>That&#8217;s it for glade.</p>
<h2><a href="#Python">Showing the menu in Python</a></h2>
<p>The first thing that we need to do is get the menu widget in our initialize_widgets() function:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-comment">#load the menu from the glade file
</span><span class="hl-identifier">wTree</span><span class="hl-default"> = </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">glade</span><span class="hl-default">.</span><span class="hl-identifier">XML</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">gladefile</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">contextMenu</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
</span><span class="hl-comment">#connect the menu with the signals
</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">signal_autoconnect</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)
</span><span class="hl-comment">#Get the menu dialog widget
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">context_menu</span><span class="hl-default"> = </span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">contextMenu</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span></pre></div></div>
<p>Now that we have the widget we need to actually show it when people right-click on our TreeView. We didn&#8217;t have to add a button press handler to our TreeView because we added one in the last tutorial, but we will have to edit it.</p>
<p>Here is the original function:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">on_todoTree_button_press_event</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-code">, </span><span class="hl-identifier">event</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">There has been a button press on the TodoTree
	for now we use this as a quick hack to remove
	the selection.  Perhaps there is a better way?
	@param widget - gtk.TreeView - The Tree View
	@param event - gtk.gdk.event - Event information
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-comment">#Get the path at the specific mouse position
	</span><span class="hl-identifier">path</span><span class="hl-default"> = </span><span class="hl-identifier">widget</span><span class="hl-default">.</span><span class="hl-identifier">get_path_at_pos</span><span class="hl-brackets">(</span><span class="hl-builtin">int</span><span class="hl-brackets">(</span><span class="hl-identifier">event</span><span class="hl-code">.</span><span class="hl-identifier">x</span><span class="hl-brackets">)</span><span class="hl-code">, </span><span class="hl-builtin">int</span><span class="hl-brackets">(</span><span class="hl-identifier">event</span><span class="hl-code">.</span><span class="hl-identifier">y</span><span class="hl-brackets">))
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">path</span><span class="hl-code"> == </span><span class="hl-reserved">None</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">If we didn't get apath then we don't want anything
		to be selected.</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">selection</span><span class="hl-default"> = </span><span class="hl-identifier">widget</span><span class="hl-default">.</span><span class="hl-identifier">get_selection</span><span class="hl-brackets">()
		</span><span class="hl-identifier">selection</span><span class="hl-default">.</span><span class="hl-identifier">unselect_all</span><span class="hl-brackets">()</span></pre></div></div>
<p>We will have to change this function to show our menu widget, which is a pretty simple addition to the end of the function:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">event</span><span class="hl-code">.</span><span class="hl-identifier">button</span><span class="hl-code"> == </span><span class="hl-number">3</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-comment">#This is a right-click
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">context_menu</span><span class="hl-default">.</span><span class="hl-identifier">popup</span><span class="hl-brackets">( </span><span class="hl-reserved">None</span><span class="hl-code">, </span><span class="hl-reserved">None</span><span class="hl-code">, </span><span class="hl-reserved">None</span><span class="hl-code">
		, </span><span class="hl-identifier">event</span><span class="hl-code">.</span><span class="hl-identifier">button</span><span class="hl-code">, </span><span class="hl-identifier">event</span><span class="hl-code">.</span><span class="hl-identifier">time</span><span class="hl-brackets">)</span></pre></div></div>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_04/pylan_04_01.png" alt="Python GTD pyGTK" border="0"/></p>
<p>So far so good, you&#8217;ll notice that since the menu handlers are the same as our toolbar handlers everything already works!  The only problem is that the sensitive state of the menu items does not match the sensitive state of the toolbar buttons.</p>
<p>Thankfully since we added this feature to the buttons in the last tutorial doing this is pretty easy.</p>
<p>The first thing that we need to do is get the menu items and disable them in the same way that we do the buttons in the initialize_widgets() function:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-comment">#Get the menu widgets
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">new_category_menu</span><span class="hl-default"> = </span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">new_category_menu</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">new_task_menu</span><span class="hl-default"> = </span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">new_task_menu</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">edit_context_menu</span><span class="hl-default"> = </span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">edit_context_menu</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">remove_context_menu</span><span class="hl-default"> = </span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">remove_context_menu</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)

</span><span class="hl-comment">#disable them like the buttons
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">new_task_menu</span><span class="hl-default">.</span><span class="hl-identifier">set_sensitive</span><span class="hl-brackets">(</span><span class="hl-reserved">False</span><span class="hl-brackets">)
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">edit_context_menu</span><span class="hl-default">.</span><span class="hl-identifier">set_sensitive</span><span class="hl-brackets">(</span><span class="hl-reserved">False</span><span class="hl-brackets">)
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">remove_context_menu</span><span class="hl-default">.</span><span class="hl-identifier">set_sensitive</span><span class="hl-brackets">(</span><span class="hl-reserved">False</span><span class="hl-brackets">)</span></pre></div></div>
<p>Then in the on_tree_selection_changed() function we need to update the menu items sensitive state:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">new_task_menu</span><span class="hl-default">.</span><span class="hl-identifier">set_sensitive</span><span class="hl-brackets">((</span><span class="hl-identifier">selection_iter</span><span class="hl-code"> != </span><span class="hl-reserved">None</span><span class="hl-brackets">))
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">edit_context_menu</span><span class="hl-default">.</span><span class="hl-identifier">set_sensitive</span><span class="hl-brackets">((</span><span class="hl-identifier">selection_iter</span><span class="hl-code"> != </span><span class="hl-reserved">None</span><span class="hl-brackets">))
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">remove_context_menu</span><span class="hl-default">.</span><span class="hl-identifier">set_sensitive</span><span class="hl-brackets">((</span><span class="hl-identifier">selection_iter</span><span class="hl-code"> != </span><span class="hl-reserved">None</span><span class="hl-brackets">))</span></pre></div></div>
<p>Now we have nice context menus!</p>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_04/pylan_04_02.png" alt="Python GTD pyGTK" border="0"/></p>
<p>You can download the full source to this tutorial <a href="http://www.learningpython.com/sources/PyLan_04.tar.gz">here</a>.</p>
<div style="float:right;margin:0px 0px 0px 0px;"><a href="http://www.google.com/reader/link?url=http://www.learningpython.com/2007/09/23/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-four-context-menus/&title=PyLan a GTD todo application written in python and PyGTK - part four context menus!&srcTitle=learning python&srcURL=http://www.learningpython.com"target="_blank" rel=""><img border="0" src="http://www.learningpython.com/wp-content/plugins/wp-google-buzz/icon/12.png" style="opacity:1;filter:alpha(opacity=100)" onmouseover="this.style.opacity=0.8;this.filters.alpha.opacity=70" onmouseout="this.style.opacity=1;this.filters.alpha.opacity=100"/> </a></div>]]></content:encoded>
			<wfw:commentRss>http://www.learningpython.com/2007/09/23/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-four-context-menus/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>PyLan a GTD todo application written in python and PyGTK &#8211; part three</title>
		<link>http://www.learningpython.com/2007/07/04/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-three/</link>
		<comments>http://www.learningpython.com/2007/07/04/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-three/#comments</comments>
		<pubDate>Thu, 05 Jul 2007 01:20:31 +0000</pubDate>
		<dc:creator>selsine</dc:creator>
				<category><![CDATA[PyGTK]]></category>
		<category><![CDATA[PyLan]]></category>
		<category><![CDATA[glade]]></category>
		<category><![CDATA[gui]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://www.learningpython.com/?p=62</guid>
		<description><![CDATA[
			
				
			
		
PyLan three
Hello welcome to the long-time-coming third article in this tutorial.  I apologize to everyone (anyone?) that was waiting for it.  I have been very busy as of late and have had much of my time taken up by a few other python projects, that I hope to be able to show you [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.learningpython.com%2F2007%2F07%2F04%2Fpylan-a-gtd-todo-application-written-in-python-and-pygtk-part-three%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.learningpython.com%2F2007%2F07%2F04%2Fpylan-a-gtd-todo-application-written-in-python-and-pygtk-part-three%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<h2>PyLan three</h2>
<p>Hello welcome to the long-time-coming third article in this tutorial.  I apologize to everyone (anyone?) that was waiting for it.  I have been very busy as of late and have had much of my time taken up by a few other python projects, that I hope to be able to show you all soon.</p>
<p>If you want to follow along with the code in detail, and have not done so already, you should read <a href="http://www.learningpython.com/2007/02/17/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-one/">part one</a> and <a href="http://www.learningpython.com/2007/02/17/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-two/">part two</a> of this series. </p>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_03/pylan_03_01.png" alt="Python GTD pyGTK" border="0"/></p>
<p>You can download the full source to this tutorial <a href="http://www.learningpython.com/sources/PyLan_03.tar.gz">here</a>.</p>
<p>This tutorial will teach you the following things:</p>
<ol>
<li>How to construct a simple theme engine, or at least how I would, hopefully it will give you some ideas!</li>
<li>How to display icons in a gtk.TreeView</li>
<li>How to catch the selection event in a gtk.TreeView.</li>
<li>How to enable or disable widgets.</li>
<li>How to remove the selection from a gtk.TreeView if the user clicks on the gtk.TreeView but not on a tree item.</li>
</ol>
<p><span id="more-62"></span><br />
This tutorial is organized into the following sections:</p>
<ol>
<li><a href="#Theme">A Simple Theme Engine</a></li>
<li><a href="#ShowingIcons">Showing Icons</a></li>
<li><a href="#EnablingWidgets">Enabling and Disabling Widgets</a></li>
<li><a href="#RemoveSelection">Removing Unwanted Selection</a></li>
<li><a href="#Conclusion">Conclusion</a></li>
</ol>
<p>As with other tutorial in this series this will not go into all details and changes that were made in the code, instead it will deal with a few main subjects that will hopefully provide ideas and sample code to others interested in python and PyGtk programming.</p>
<h2><a href="#Theme">A Simple Theme Engine</a></h2>
<p>Now a while back I had an interesting idea that I would like to create a simple theme engine for the PyLan application.  I thought that it would be easy and let me (or other people) change the icons or colours that are used.</p>
<p>So my idea was to use a dictionary object indexed by constant keys, whose values would be &#8220;theme objects.&#8221;</p>
<p>I thought that this would be a simple enough idea that I could implement quickly and then expand in the future to have more features like the ability to save and load the theme from xml.</p>
<p>So to start we create a file called theme.py and filled it with all of the basics and some imports and some constants:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">try</span><span class="hl-default">:
	</span><span class="hl-reserved">import </span><span class="hl-identifier">gtk
	</span><span class="hl-reserved">import </span><span class="hl-identifier">helper
</span><span class="hl-reserved">except</span><span class="hl-default">:
  	</span><span class="hl-reserved">print </span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">import Error</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
  	
</span><span class="hl-identifier">PIXMAP</span><span class="hl-default"> = </span><span class="hl-number">0
</span><span class="hl-identifier">COLOUR</span><span class="hl-default"> = </span><span class="hl-number">1</span></pre></div></div>
<p>Next we create our Theme object that will serve as the applications theme.  In this version the Theme object is still very simple, here is it in its entirety:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">class </span><span class="hl-identifier">Theme</span><span class="hl-brackets">(</span><span class="hl-identifier">dict</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This object represents all of the necessary information needed
	to properly present information in a pyLan application...or any
	application
	</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-reserved">def </span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">theme_dict</span><span class="hl-code"> = </span><span class="hl-reserved">None</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">initialize the theme
		@param theme_dict - dictionary of values.  If None it is
		ignored, if not none, it's values will be stored in the internal
		theme_dictionary.</span><span class="hl-quotes">&quot;&quot;&quot;

		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">load_from_dictionary</span><span class="hl-brackets">(</span><span class="hl-identifier">theme_dict</span><span class="hl-brackets">)

	</span><span class="hl-reserved">def </span><span class="hl-identifier">load_from_dictionary</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">theme_dict</span><span class="hl-code">, </span><span class="hl-identifier">initialize</span><span class="hl-code"> = </span><span class="hl-reserved">False</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function loads all of the theme values
		from the theme_dict into the internal theme dictionary.
		@param theme_dict - dictionary - A theme dictionary that
		describes theme items.
		@param initialize = False - boolean, do we want to blank
		out the internal dictionary before we load the items?
		</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-comment">#Make sure that the dict is not None
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-reserved">not </span><span class="hl-identifier">theme_dict</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-reserved">return
		</span><span class="hl-comment">#clear yourself out
		</span><span class="hl-identifier">dict</span><span class="hl-default">.</span><span class="hl-identifier">clear</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)

		</span><span class="hl-reserved">for </span><span class="hl-identifier">key</span><span class="hl-default">,</span><span class="hl-identifier">value </span><span class="hl-reserved">in </span><span class="hl-identifier">theme_dict</span><span class="hl-default">.</span><span class="hl-identifier">iteritems</span><span class="hl-brackets">()</span><span class="hl-default">:
			</span><span class="hl-identifier">self</span><span class="hl-brackets">[</span><span class="hl-identifier">key</span><span class="hl-brackets">]</span><span class="hl-default"> = </span><span class="hl-identifier">value</span></pre></div></div>
<p>So what is happening here?  Not that much, the Theme object uses the dict object as a base class and then lets you initialize the Theme using a dictionary, which is done using a helper function.  This was put for future usage and is not used yet.</p>
<p>The next item in the Theme setup is the ThemeItem object.  This is the object that will be used as the value for each item in our Theme dictionary.</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre>class ThemeItem(object):
	&quot;&quot;&quot;An item in the theme.  This is used to store all of the
	necessary theme information.
	&quot;&quot;&quot;

	&quot;&quot;&quot;Type property - Cannot be set, only set in the
	initializer.&quot;&quot;&quot;
	def __get_type(self):
		return self._m_type
	type = property(__get_type)

	&quot;&quot;&quot;Data Property&quot;&quot;&quot;
	def __get_data(self):
		return self._m_data
	data = property(__get_data)

	def __init__(self, type):
		&quot;&quot;&quot;Initialize yourself.
		@param type - number - The type of theme item.
		&quot;&quot;&quot;
		self._m_type = type
		self._m_data = None
		#now load the data
		self.load_data()

	def load_data(self):
		&quot;&quot;&quot;This function is call when the Theme item
		should load any data that it needs. i.e. if it
		is a pixmap it should load the image file.
		it should create the data.
		&quot;&quot;&quot;
		pass</pre></div></div>
<p>First you can see that there are two date members in the ThemeItem base class, the _m_type and _m_data.  The _m_type is simply used to let interested parties know what the type of theme object is.  I&#8217;m not sure if the _m_type is still needed, originally I was using it but after changing a few things it doesn&#8217;t really do much (anything?) anymore.</p>
<p>The next data member is that _m_data item that is meant to be private and accessed through the data property.  As you can see the data property cannot be set it can only be read.  This was done this way so that only the ThemeItem would be able to set its data.</p>
<p>Now the data member can be anything, it could be an image, a colour, whatever you want it to be.  The data member will generally be set by a subclass of the ThemeItem.  You&#8217;ll also notice that the data is &#8220;loaded&#8221; in the __init__ function.  By default the load_data() function does nothing, and should be overridden in the base class.</p>
<p>The only type that I have in use so far is the ThemePixmap object.  This is a ThemeItem that sets its data to be a <a href="http://www.pygtk.org/docs/pygtk/class-gdkpixbuf.html">gtk.gdk.pixbuf</a>:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">class </span><span class="hl-identifier">ThemePixmap</span><span class="hl-brackets">(</span><span class="hl-identifier">ThemeItem</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">A Them item that represents a pixmap to be displayed.</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-reserved">def </span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">file_name</span><span class="hl-code"> = </span><span class="hl-quotes">&quot;&quot;</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Initialize the pixmap theme item.
		@param file_name - string - the path to the
		pixmap file.
		</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">file_name</span><span class="hl-default"> = </span><span class="hl-identifier">file_name
		ThemeItem</span><span class="hl-default">.</span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">PIXMAP</span><span class="hl-brackets">)

	</span><span class="hl-reserved">def </span><span class="hl-identifier">load_data</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This is where we load the pixmap based on the file name</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-reserved">try</span><span class="hl-default">:
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">_m_data</span><span class="hl-default"> = </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">gdk</span><span class="hl-default">.</span><span class="hl-identifier">pixbuf_new_from_file</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">file_name</span><span class="hl-brackets">)
		</span><span class="hl-reserved">except </span><span class="hl-identifier">gerror</span><span class="hl-default">, </span><span class="hl-identifier">e</span><span class="hl-default">:
			</span><span class="hl-identifier">helper</span><span class="hl-default">.</span><span class="hl-identifier">show_error_dlg</span><span class="hl-brackets">(</span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Error loading pixmap %s = %s</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-code">
				% </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">file_name</span><span class="hl-code">, </span><span class="hl-identifier">e</span><span class="hl-brackets">))
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">_m_data</span><span class="hl-default"> = </span><span class="hl-reserved">None</span></pre></div></div>
<p>Pretty straightforward here, a simple subclass of the ThemeItem object that overrides the load_data() function and adds a new class member.  The load_data function simply loads a pixmap into the data using the <a href="http://www.pygtk.org/docs/pygtk/class-gdkpixbuf.html#function-gdk--pixbuf-new-from-file">gtk.gdk.pixbuf_new_from_file</a> function.</p>
<p>Now how do we use this?</p>
<p>In the main pyLan.py file I added the following function to initalize the theme, it is called from the __init__ function and could theoretically be called from other locations:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">initialize_theme</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function is used to initialise the
	theme.</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">app_theme</span><span class="hl-default"> = </span><span class="hl-identifier">theme</span><span class="hl-default">.</span><span class="hl-identifier">Theme</span><span class="hl-brackets">()
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">app_theme</span><span class="hl-brackets">[</span><span class="hl-identifier">CATEGORY_ICON</span><span class="hl-brackets">]</span><span class="hl-default"> = </span><span class="hl-identifier">theme</span><span class="hl-default">.</span><span class="hl-identifier">ThemePixmap</span><span class="hl-brackets">(
		</span><span class="hl-identifier">os</span><span class="hl-code">.</span><span class="hl-identifier">path</span><span class="hl-code">.</span><span class="hl-identifier">join</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">pixmaps</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">stock_book_blue.png</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">))
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">app_theme</span><span class="hl-brackets">[</span><span class="hl-identifier">TASK_ICON</span><span class="hl-brackets">]</span><span class="hl-default"> = </span><span class="hl-identifier">theme</span><span class="hl-default">.</span><span class="hl-identifier">ThemePixmap</span><span class="hl-brackets">(
		</span><span class="hl-identifier">os</span><span class="hl-code">.</span><span class="hl-identifier">path</span><span class="hl-code">.</span><span class="hl-identifier">join</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">pixmaps</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">stock_task.png</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">))</span></pre></div></div>
<p>So this is how I use the theme in the main PyLan application, I&#8217;m using it to determine what icon to display for tasks and what icon to use for categories.</p>
<p>As you can see I simply create a theme member in the PyLan class and the add two ThemePixmap items to the Theme, each index by constants that will be used to identify them later.  In the future I hope to use this function to load the information from a file.</p>
<p>The constants used in the function are defined as follows:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-identifier">CATEGORY_ICON</span><span class="hl-default"> 			= </span><span class="hl-number">1
</span><span class="hl-identifier">TASK_ICON</span><span class="hl-default">				= </span><span class="hl-number">2</span></pre></div></div>
<p>I will show you how the theme is used in the next section.</p>
<h2><a name="ShowingIcons"></a>Showing Icons</h2>
<p>So now that we have a simple theme engine that load graphics for us we need to figure out how to show images in our gtk.TreeView.</p>
<p>What we will do is we will use the <a href="http://www.pygtk.org/docs/pygtk/class-gtkcellrendererpixbuf.html">gtk.CellRendererPixbuf</a> to render our image.  We will also pack the image into the same column as the Title column.  We do this so that the icon isn&#8217;t in a column of it&#8217;s own, which would seem quite strange.</p>
<p>Basically what we will do is create the gtk.TreeViewColumn in our normal way, using the gtk.CellRenberPixbuf, then when we use the <a href="http://www.pygtk.org/docs/pygtk/class-gtktreeviewcolumn.html#method-gtktreeviewcolumn--pack-start">gtk.TreeViewColumn.pack_start</a> function to add the <a href="http://www.pygtk.org/docs/pygtk/class-gtkcellrenderertext.html">gtk.CellRendererText</a> (representing the Title Text) to add the text to column.  This means that we will have two cell renderers in the same column.</p>
<p>The actual code to accomplish this in the pyLan program is quite complicated as I attempted to use the todoColumn object as a generic way to order the columns.  This worked fine before but now it has become a more complicated and slightly hackish now that we want to be able to pack items into the same column.</p>
<p>Sufficed to say I accomplished this by adding a new share_column member to the totoColum that allows you to Pack Widgets.</p>
<p>We also have to update the get_column_list() function in the todo.Task and todo.Category items so that they returns the pixbuf from the theme.  This also means that we need to add a new member to the todo.todoBase object:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">type</span><span class="hl-code">, </span><span class="hl-identifier">app_theme</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">The only way to set the type is through the
	initialization</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_type</span><span class="hl-default"> = </span><span class="hl-identifier">type
	self</span><span class="hl-default">.</span><span class="hl-identifier">app_theme</span><span class="hl-default"> = </span><span class="hl-identifier">app_theme</span></pre></div></div>
<p>Where app_theme is an instance of our Theme object described in the previous section.</p>
<p>Then in the get_column_list() the todo.Category objects need to add the following:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-identifier">elif </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">COL_ICON</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">app_theme</span><span class="hl-brackets">[</span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">CATEGORY_ICON</span><span class="hl-brackets">]</span><span class="hl-code">.</span><span class="hl-identifier">data</span><span class="hl-brackets">)</span></pre></div></div>
<p>and the todo.Theme object needs to add the following:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-identifier">elif </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">COL_ICON</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">app_theme</span><span class="hl-brackets">[</span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">TASK_ICON</span><span class="hl-brackets">]</span><span class="hl-code">.</span><span class="hl-identifier">data</span><span class="hl-brackets">)</span></pre></div></div>
<p>Pretty simple, all we do is we get that Theme item in the applications theme and then return its data.  If this seems strange or you cannot understand it, please take a look at the previous tutorial and you you will be able to understand what the get_column_list() function does.</p>
<h2><a name="EnablingWidgets"></a>Enabling and Disabling Widgets</h2>
<p>One of the things that has been bothering me about the PyLan application was that all of the buttons on the toolbar were always enabled even when they cannot perform their function.</p>
<p>Now I&#8217;m used to the Enable/Disabled terminology except in GTK the terms sensitive and insensitive are used, so I will try to use them from now on, but if an enabled or a disabled slips in there please forgive me.</p>
<p>The first thing that we need to add is an initialize_widgets() function to the PyLan class, this function will gather widgets that we need and will set their default state.  This needs to be called early in the __init__ function before initialize_todo_tree() is called.  The function is as follows:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">initialize_widgets</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Initialize any widgets that we want.  Basically
	grab widgets that you want to have access to later
	on in the program.
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-comment">#Get the widgets
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">edit_button</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">btnEdit</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">delete_button</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">btnRemoveCategory</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">add_task_button</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">btnAddTask</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-comment">#disable them
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">edit_button</span><span class="hl-default">.</span><span class="hl-identifier">set_sensitive</span><span class="hl-brackets">(</span><span class="hl-reserved">False</span><span class="hl-brackets">)
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">delete_button</span><span class="hl-default">.</span><span class="hl-identifier">set_sensitive</span><span class="hl-brackets">(</span><span class="hl-reserved">False</span><span class="hl-brackets">)
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">add_task_button</span><span class="hl-default">.</span><span class="hl-identifier">set_sensitive</span><span class="hl-brackets">(</span><span class="hl-reserved">False</span><span class="hl-brackets">)</span></pre></div></div>
<p>The code is pretty simple, we grab the widgets from the widget tree, and then we simply call the <a href="http://www.pygtk.org/docs/pygtk/class-gtkwidget.html#method-gtkwidget--set-sensitive">set_sensitive</a> function and tell them to be insensitive by passing False to the function.</p>
<p>The next step is to connect the application to the <a href="http://www.pygtk.org/docs/pygtk/class-gtktreeselection.html#signal-gtktreeselection--changed">&#8220;changed&#8221; signal</a> that is emitted by the <a href="http://www.pygtk.org/docs/pygtk/class-gtktreeselection.html">gtk.TreeSelection</a> that is associated with our gtk.TreeView.  To do so we need to add the following code to the initialize_todo_tree() function:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-comment">#Enable the selection callback
</span><span class="hl-identifier">selection</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todoTreeView</span><span class="hl-default">.</span><span class="hl-identifier">get_selection</span><span class="hl-brackets">()
</span><span class="hl-identifier">selection</span><span class="hl-default">.</span><span class="hl-identifier">connect</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">changed</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">on_tree_selection_changed</span><span class="hl-brackets">)</span></pre></div></div>
<p>Pretty simple, we get the gtk.TreeSelection from the gtk.TreeView and then we connect the on_tree_selection_changed() function with the changed signal.</p>
<p>The on_tree_selection_changed() function is relatively simple as well:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">on_tree_selection_changed</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">selection</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when the selection has changed in the
	tree.
	@param selection - gtk.TreeSelection - The selection
	object associated with the gtk.TreeView.
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">model</span><span class="hl-default">, </span><span class="hl-identifier">selection_iter</span><span class="hl-default"> = </span><span class="hl-identifier">selection</span><span class="hl-default">.</span><span class="hl-identifier">get_selected</span><span class="hl-brackets">()
	</span><span class="hl-comment">#If there is a selection then enable these
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">edit_button</span><span class="hl-default">.</span><span class="hl-identifier">set_sensitive</span><span class="hl-brackets">((</span><span class="hl-identifier">selection_iter</span><span class="hl-code"> != </span><span class="hl-reserved">None</span><span class="hl-brackets">))
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">delete_button</span><span class="hl-default">.</span><span class="hl-identifier">set_sensitive</span><span class="hl-brackets">((</span><span class="hl-identifier">selection_iter</span><span class="hl-code"> != </span><span class="hl-reserved">None</span><span class="hl-brackets">))
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">add_task_button</span><span class="hl-default">.</span><span class="hl-identifier">set_sensitive</span><span class="hl-brackets">((</span><span class="hl-identifier">selection_iter</span><span class="hl-code"> != </span><span class="hl-reserved">None</span><span class="hl-brackets">))</span></pre></div></div>
<p>First we get the selection_iter from the gtk.TreeSelection and then we enable the edit, delete, and add_task buttons based on whether or not there is a selection in the gtk.TreeView.  If nothing is selected then we make the buttons insensitive.</p>
<h2><a href="#RemoveSelection">Removing Unwanted Selection</a></h2>
<p>One feature that I wanted to implement in the application was the ability to remove selection from the tree by clicking on an empty space in the tree.  As far as I can tell there is no simple method to enable a feature like this in PyGTK, which I found quite surprising.</p>
<p>As a result what I needed to do was connect to the gtk.TreeView&#8217;s <a href="http://www.pygtk.org/docs/pygtk/class-gtkwidget.html#signal-gtkwidget--button-press-event">button-press-event</a>.  Then we use the location where the user clicked and see if they clicked on an item in the tree.  If they did not click on an item in the tree then we remove the selection from the tree.  If they did click on something then we leave the selection as is.</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">on_todoTree_button_press_event</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-code">, </span><span class="hl-identifier">event</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">There has been a button press on the TodoTree
	for now we use this as a quick hack to remove
	the selection.  Perhaps there is a better way?
	@param widget - gtk.TreeView - The Tree View
	@param event - gtk.gdk.event - Event information
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-comment">#Get the path at the specific mouse position
	</span><span class="hl-identifier">path</span><span class="hl-default"> = </span><span class="hl-identifier">widget</span><span class="hl-default">.</span><span class="hl-identifier">get_path_at_pos</span><span class="hl-brackets">(</span><span class="hl-builtin">int</span><span class="hl-brackets">(</span><span class="hl-identifier">event</span><span class="hl-code">.</span><span class="hl-identifier">x</span><span class="hl-brackets">)</span><span class="hl-code">, </span><span class="hl-builtin">int</span><span class="hl-brackets">(</span><span class="hl-identifier">event</span><span class="hl-code">.</span><span class="hl-identifier">y</span><span class="hl-brackets">))
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">path</span><span class="hl-code"> == </span><span class="hl-reserved">None</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">If we didn't get apath then we don't want anything
		to be selected.</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">selection</span><span class="hl-default"> = </span><span class="hl-identifier">widget</span><span class="hl-default">.</span><span class="hl-identifier">get_selection</span><span class="hl-brackets">()
		</span><span class="hl-identifier">selection</span><span class="hl-default">.</span><span class="hl-identifier">unselect_all</span><span class="hl-brackets">()</span></pre></div></div>
<p>As you can see, we take position of the cursor where the button was pressed and then call the <a href="http://www.pygtk.org/docs/pygtk/class-gtktreeview.html#method-gtktreeview--get-path-at-pos">get_path_at_pos()</a> function in the gtk.TreeView which returns a tuple containing information if an item in the tree can be found at the specified x,y position, and None if nothing in the tree was hit.</p>
<p>It&#8217;s not pretty but it works!</p>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_03/pylan_03_01.png" alt="Python GTD pyGTK" border="0"/></p>
<p>You can download the full source to this tutorial <a href="http://www.learningpython.com/sources/PyLan_03.tar.gz">here</a>.</p>
<h2><a name="Conclusion"></a>Conclusion</h2>
<p>Now one of the problems that I had writing this tutorial is that it&#8217;s getting very hard to detail all of the changes that are made to the project.  So I have tried to leave out as much extraneous detail as I possibly could, but then I start to wonder how much use anyone could get out of these articles if the details are left out.</p>
<p>Hopefully there is still enough in there so that people can get ideas and at least some hints as to how things work in some of the slightly more advanced areas of PyGTK.</p>
<p>I&#8217;m not sure if I am going to continue detailing everything in this test application, I might skip a few phases since detailing everything is getting to be more of a problem.  But what I really want to focus on soon is working with things like Preferences and distributions.  Sadly time is always a factor!</p>
<p>If you have any questions please ask away as always!</p>
<div style="float:right;margin:0px 0px 0px 0px;"><a href="http://www.google.com/reader/link?url=http://www.learningpython.com/2007/07/04/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-three/&title=PyLan a GTD todo application written in python and PyGTK - part three&srcTitle=learning python&srcURL=http://www.learningpython.com"target="_blank" rel=""><img border="0" src="http://www.learningpython.com/wp-content/plugins/wp-google-buzz/icon/12.png" style="opacity:1;filter:alpha(opacity=100)" onmouseover="this.style.opacity=0.8;this.filters.alpha.opacity=70" onmouseout="this.style.opacity=1;this.filters.alpha.opacity=100"/> </a></div>]]></content:encoded>
			<wfw:commentRss>http://www.learningpython.com/2007/07/04/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-three/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>PyLan a GTD todo application written in python and PyGTK &#8211; part two</title>
		<link>http://www.learningpython.com/2007/03/11/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-two/</link>
		<comments>http://www.learningpython.com/2007/03/11/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-two/#comments</comments>
		<pubDate>Sun, 11 Mar 2007 22:48:07 +0000</pubDate>
		<dc:creator>selsine</dc:creator>
				<category><![CDATA[PyGTK]]></category>
		<category><![CDATA[PyLan]]></category>
		<category><![CDATA[glade]]></category>
		<category><![CDATA[gui]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://www.learningpython.com/?p=58</guid>
		<description><![CDATA[
			
				
			
		
PyLan two
This is part two of the PyLan tutorial series, if you want to follow along with the code in detail, and have not done so already, you should read part one of this series. 
In this tutorial I will go over the following items:

Showing a popup window
Working with a gtk.Calendar widget
Working with gtk.ComboBox widgets
Working [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.learningpython.com%2F2007%2F03%2F11%2Fpylan-a-gtd-todo-application-written-in-python-and-pygtk-part-two%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.learningpython.com%2F2007%2F03%2F11%2Fpylan-a-gtd-todo-application-written-in-python-and-pygtk-part-two%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<h2>PyLan two</h2>
<p>This is part two of the PyLan tutorial series, if you want to follow along with the code in detail, and have not done so already, you should read <a href="http://www.learningpython.com/2007/02/17/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-one/">part one</a> of this series. </p>
<p>In this tutorial I will go over the following items:</p>
<ul>
<li>Showing a popup window</li>
<li>Working with a <a href="http://www.pygtk.org/docs/pygtk/class-gtkcalendar.html">gtk.Calendar</a> widget</li>
<li>Working with <a href="http://www.pygtk.org/docs/pygtk/class-gtkcombobox.html">gtk.ComboBox</a> widgets</li>
<li>Working with Pango markup in a gtk.TreeView</li>
<li>Working with <a href="http://www.pygtk.org/docs/pygtk/class-gtkcheckbutton.html">gtk.CheckButton</a> widgets</li>
<li>Working with the <a href="http://docs.python.org/lib/module-datetime.html">DateTime</a> python module.</li>
</ul>
<p>This tutorial is organized into the following sections:</p>
<ol>
<li><a href="#TheGUI">The GUI</a></li>
<li><a href="#todoTask">The todo.Task Object</a></li>
<li><a href="#addedittodoTask">Adding a todo.Task object</a></li>
<li><a href="#calendarWindow">Showing the Calendar window</a></li>
<li><a href="#EditingItems">Editing todo.Category and todo.Task items</a></li>
<li><a href="#PangoMarkup">Pango markup in the gtk.TreeView</a></li>
<li><a href="#Conclusion">Conclusion</a></li>
</ol>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_01/pylan_01_08.png" alt="Python GTD pyGTK" border="0" /></p>
<p>You can download the full source to this tutorial <a href="http://www.learningpython.com/sources/PyLan_02.tar.gz">here</a>.</p>
<p><span id="more-58"></span></p>
<h2><a name="TheGUI"></a>The GUI</h2>
<p>I will be working with the same glade project as last time, except I will be adding a some new dialogs and buttons.  I will not go over all of the changes in the GUI since many of them are very simple changes, similar to changes that have been made in previous tutorials.  </p>
<p>For example I decided to get rid of the Dropdown menu for adding the Categories and the tasks, instead I decided to create separate buttons to do the two separate tasks.  I won&#8217;t describe the switch here, since adding toolbar buttons is pretty straightforward.  For anyone interested in why I decided to make this switch, the answer is pretty simple, I didn&#8217;t like using the drop down menu as much as I thought that I would.  Instead I found it confusing and prone to error.  As a result I made the switch to the separate buttons. </p>
<p>So here is a non-comprehensive list of the changes that I made to the GUI in case you were interested in seeing how something was done.</p>
<p><strong>The Task dialog</strong></p>
<p>This dialog is used to add or edit a todo.Task object.</p>
<ul>
<li>Create a Dialog with an Ok and a Cancel button.  Sets it&#8217;s name to be &#8220;taskItemDialog&#8221;, and its title to be &#8220;Task Item&#8221;.  Give it a width of 300 and a height of 225.</li>
<li>Add a Vertical Box to the dialog with 2 rows.  In the second row add a Check Button with the label &#8220;Completed&#8221; and the name &#8220;checkCompleted&#8221;.</li>
<li>In the first row add a table with two columns and four rows.  To the following to the table, adding vertical padding of 3 pixels to each space in the second column:
<ul>
<li>Add a label with the label &#8220;Title&#8221; in [0, 0].</li>
<li>Add a Text Entry in [0, 1] and call it enTitle</li>
<li>Add a label with the label &#8220;Details&#8221; in [1, 0], give it three pixel of horizontal padding.</li>
<li>Add a Text View in [1, 1] and call it tvDetails.  In the scrolled window&#8217;s properties set the H Policy to &#8220;Never&#8221; and the V Policy to &#8220;Automatic&#8221;.  This means that there will never be a horizontal scrollbar, and that there will be a vertical scrollbar only when one is necessary.</li>
<li>Add a label in [2, 0] with the Label &#8220;Due:&#8221;.</li>
<li>Add a horizontal box with three columns in [2, 1].  In the first add an entry labelled enDueDate, in the second add a button named btnDue add a clicked signal handler, and in the third add a combobox and give it the name &#8220;cmbTime&#8221;.  Add time entries to the combobox in the form: &#8220;&#8221;(blank),12:00AM, 12:30AM, 01:00AM&#8230;11:30PM.  Then right-click on the button and select it in the menu and then select &#8220;Remove Button Contents&#8221;.  Then add an arrow to the button and set its direction to down.  The button will be used to display a Calendar so that the people can select the due date.</li>
<li>Add a label in 3,0 and set its label to &#8220;Priority:</li>
<li>Add a Combo Box in 3,1 and set its name to &#8220;cmbPriority&#8221;.  Set its items to &#8220;High&#8221;, &#8220;Medium&#8221;, and &#8220;Low&#8221;.</li>
</ul>
</li>
</ul>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_01/pylan_01_02.png" alt="Python GTD pyGTK" border="0" /></p>
<p><strong>The Calendar Window</strong></p>
<p>This is a popup window that we will us to let the user select the due date for their tasks.</p>
<ul>
<li>Add another window, and call it &#8220;calendarWindow&#8221;.  Set its border width to 1, its title to &#8220;&#8221;, its type to &#8220;popup&#8221;, modal to &#8220;yes&#8221;, resizeable to &#8220;no&#8221;, and skip taskbar to &#8220;yes&#8221;.</li>
<li>Add a vertical box to the window with two rows.  </li>
<li>In the first row ad a calendar widget and call it &#8220;calendarWidget&#8221;</li>
<li>In the second row add a button with the name &#8220;btnNoDate&#8221;.  Set the label to be &#8220;No Date&#8221; and the icon to be gtk-no.  Add a clicked signal handler.</li>
</ul>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_01/pylan_01_03.png" alt="Python GTD pyGTK" border="0" /></p>
<h2><a name="todoTask"></a>The todo.Task object</h2>
<p>The todo.Task object is used to represent the task item in the same way that the todo.Category object represents a category item.  The astute among you will notice that I renamed the category object, I just thought that todo.Category looked so much better then todo.todoCategory.</p>
<p>Since we will be using the datetime and time python modules to represent the due date for tasks we need to import them in the todo file:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">import </span><span class="hl-identifier">datetime
</span><span class="hl-reserved">import </span><span class="hl-identifier">time</span></pre></div></div>
<p>The todo.Task class is relatively simple, if you&#8217;ve read the first tutorial it should be very easy to understand this code:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">class </span><span class="hl-identifier">Task</span><span class="hl-brackets">(</span><span class="hl-identifier">todoBase</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This is a task in the todoTree.  It represents
	something that needs to be done.
	</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-comment">#Name property
	</span><span class="hl-reserved">def </span><span class="hl-identifier">__get_name</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-reserved">return </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_name
	</span><span class="hl-reserved">def </span><span class="hl-identifier">__set_name</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">name</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_name</span><span class="hl-default"> = </span><span class="hl-identifier">name
	name</span><span class="hl-default"> = </span><span class="hl-builtin">property</span><span class="hl-brackets">(</span><span class="hl-identifier">__get_name</span><span class="hl-code">, </span><span class="hl-identifier">__set_name</span><span class="hl-brackets">)

	</span><span class="hl-comment">#Due date property
	</span><span class="hl-reserved">def </span><span class="hl-identifier">__get_due_date</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-reserved">return </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_due_date
	</span><span class="hl-reserved">def </span><span class="hl-identifier">__set_due_date</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">due_date</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_due_date</span><span class="hl-default"> = </span><span class="hl-identifier">due_date
	due_date</span><span class="hl-default"> = </span><span class="hl-builtin">property</span><span class="hl-brackets">(</span><span class="hl-identifier">__get_due_date</span><span class="hl-code">, </span><span class="hl-identifier">__set_due_date</span><span class="hl-brackets">)

	</span><span class="hl-comment">#Due time property
	</span><span class="hl-reserved">def </span><span class="hl-identifier">__get_due_time</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-reserved">return </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_due_time
	</span><span class="hl-reserved">def </span><span class="hl-identifier">__set_due_time</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">due_time</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_due_time</span><span class="hl-default"> = </span><span class="hl-identifier">due_time
	due_time</span><span class="hl-default"> = </span><span class="hl-builtin">property</span><span class="hl-brackets">(</span><span class="hl-identifier">__get_due_time</span><span class="hl-code">, </span><span class="hl-identifier">__set_due_time</span><span class="hl-brackets">)

	</span><span class="hl-comment">#priority property
	</span><span class="hl-reserved">def </span><span class="hl-identifier">__get_priority</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-reserved">return </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_priority
	</span><span class="hl-reserved">def </span><span class="hl-identifier">__set_priority</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">priority</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_priority</span><span class="hl-default"> = </span><span class="hl-identifier">priority
	priority</span><span class="hl-default"> = </span><span class="hl-builtin">property</span><span class="hl-brackets">(</span><span class="hl-identifier">__get_priority</span><span class="hl-code">, </span><span class="hl-identifier">__set_priority</span><span class="hl-brackets">)

	</span><span class="hl-reserved">def </span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">name</span><span class="hl-brackets">)</span><span class="hl-default">:

		</span><span class="hl-comment">#init variables
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_name</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;&quot;
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_due_date</span><span class="hl-default"> = </span><span class="hl-reserved">None
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_due_time</span><span class="hl-default"> = </span><span class="hl-reserved">None
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_priority</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;&quot;

		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">completed</span><span class="hl-default"> = </span><span class="hl-reserved">False
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">details</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;&quot;

		</span><span class="hl-comment">#set properties
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">name</span><span class="hl-default"> = </span><span class="hl-identifier">name
		</span><span class="hl-comment">#init base
		</span><span class="hl-identifier">todoBase</span><span class="hl-default">.</span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">TASK</span><span class="hl-brackets">)

		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Format strings so that the date and time
		formats returns can easily be changed.</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">date_format</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">%Y-%m-%d</span><span class="hl-quotes">&quot;
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">time_format</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">%I:%M%p</span><span class="hl-quotes">&quot;

	</span><span class="hl-reserved">def </span><span class="hl-identifier">__str__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-reserved">return </span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">todo .Task object: name = %s</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-default"> % </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">name</span><span class="hl-brackets">)

	</span><span class="hl-reserved">def </span><span class="hl-identifier">get_column_list</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">todoColumnList</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function is used to get the display list
		for the todoTree. The todoCOlumnList controls the
		order that the list will be returned in.
		@param todoColumnList - list - A list of todoColumn items.
		Their type member should use used to determine the order
		of the returned list.
		@returns list - A list for the todoTree.
		</span><span class="hl-quotes">&quot;&quot;&quot;

		</span><span class="hl-identifier">lst_return</span><span class="hl-default"> = </span><span class="hl-brackets">[]
		</span><span class="hl-comment"># Loop through the columns and create the return list
		</span><span class="hl-reserved">for </span><span class="hl-identifier">item_column </span><span class="hl-reserved">in </span><span class="hl-identifier">todoColumnList</span><span class="hl-default">:
			</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">COL_OBJECT</span><span class="hl-brackets">)</span><span class="hl-default">:
				</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)
			</span><span class="hl-identifier">elif </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">COL_OBJECT_TYPE</span><span class="hl-brackets">)</span><span class="hl-default">:
				</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">type</span><span class="hl-brackets">)
			</span><span class="hl-identifier">elif </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">COL_TITLE</span><span class="hl-brackets">)</span><span class="hl-default">:
				</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">name</span><span class="hl-brackets">)
			</span><span class="hl-identifier">elif </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">COL_DETAILS</span><span class="hl-brackets">)</span><span class="hl-default">:
				</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">details</span><span class="hl-brackets">)
			</span><span class="hl-identifier">elif </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">COL_DUE</span><span class="hl-brackets">)</span><span class="hl-default">:
				</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">get_datetime_string</span><span class="hl-brackets">())
			</span><span class="hl-identifier">elif </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">COL_PRIORITY</span><span class="hl-brackets">)</span><span class="hl-default">:
				</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">priority</span><span class="hl-brackets">)
			</span><span class="hl-identifier">elif </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">COL_COMPLETED</span><span class="hl-brackets">)</span><span class="hl-default">:
				</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">completed</span><span class="hl-brackets">)</span><span class="hl-default">:
					</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">True</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">))
				</span><span class="hl-reserved">else</span><span class="hl-default">:
					</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">False</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">))
			</span><span class="hl-reserved">else</span><span class="hl-default">:
				</span><span class="hl-identifier">helper</span><span class="hl-default">.</span><span class="hl-identifier">show_error_dlg</span><span class="hl-brackets">(</span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Error unknown column ID: %d</span><span class="hl-quotes">&quot;</span><span class="hl-code"> % </span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-brackets">))
				</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;&quot;</span><span class="hl-brackets">)

		</span><span class="hl-reserved">return </span><span class="hl-identifier">lst_return

	</span><span class="hl-reserved">def </span><span class="hl-identifier">get_date_string</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function is used to get the Date string. It will
		be returned in the format of self.date_format.
		@returns - string - The current Due date or &quot;&quot; if nothing
		has been set yet.
		</span><span class="hl-quotes">&quot;&quot;&quot;

		</span><span class="hl-identifier">date_string</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;&quot;
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">due_date</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-identifier">date_string</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">due_date</span><span class="hl-default">.</span><span class="hl-identifier">strftime</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">date_format</span><span class="hl-brackets">)
		</span><span class="hl-reserved">return </span><span class="hl-identifier">date_string

	</span><span class="hl-reserved">def </span><span class="hl-identifier">get_time_string</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function is used to get the time string. It will
		be returned in the format of self.time_format.
		@returns - string - The current Due time or &quot;&quot; if nothing
		has been set yet.
		</span><span class="hl-quotes">&quot;&quot;&quot;

		</span><span class="hl-identifier">date_string</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;&quot;
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">due_time</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-identifier">date_string</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">due_time</span><span class="hl-default">.</span><span class="hl-identifier">strftime</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">time_format</span><span class="hl-brackets">)
		</span><span class="hl-reserved">return </span><span class="hl-identifier">date_string

	</span><span class="hl-reserved">def </span><span class="hl-identifier">get_datetime_string</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Used to get the date and the time in their
		specified formats.
		@returns - string - the date and the time.
		</span><span class="hl-quotes">&quot;&quot;&quot;

		</span><span class="hl-identifier">date_string</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">get_date_string</span><span class="hl-brackets">()
		</span><span class="hl-identifier">time_string</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">get_time_string</span><span class="hl-brackets">()
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-builtin">len</span><span class="hl-brackets">(</span><span class="hl-identifier">time_string</span><span class="hl-brackets">)</span><span class="hl-code">&gt;</span><span class="hl-number">0</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-identifier">date_string</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">%s %s</span><span class="hl-quotes">&quot;</span><span class="hl-default"> % </span><span class="hl-brackets">(</span><span class="hl-identifier">date_string</span><span class="hl-code">, </span><span class="hl-identifier">time_string</span><span class="hl-brackets">)

		</span><span class="hl-reserved">return </span><span class="hl-identifier">date_string</span></pre></div></div>
<p>One thing that you may notice is how we use the datetime and time modules.  You should notice that we have two member variables: </p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">date_format</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">%Y-%m-%d</span><span class="hl-quotes">&quot;
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">time_format</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">%I:%M%p</span><span class="hl-quotes">&quot;</span></pre></div></div>
<p>These variable store the date and time format that we will use to display the date and time in the tree.  We will pass the format strings to the<a href="http://docs.python.org/lib/strftime-behavior.html#strftime-behavior">strftime</a> function (from the python docs):</p>
<blockquote><p>
date, datetime, and time objects all support a strftime(format) method, to create a string representing the time under the control of an explicit format string. Broadly speaking, d.strftime(fmt) acts like the time module&#8217;s time.strftime(fmt, d.timetuple()) although not all objects support a timetuple() method.
</p></blockquote>
<p>We define them as members of the class so that they can be changed easily and even pickled with the object itself.</p>
<p>I won&#8217;t go into too much other detail about this class since it&#8217;s pretty much just a data holder for now, and is very similar to the todo.Category object explained in tutorial one except that it has a few more data members.</p>
<h2><a name="addedittodoTask"></a>Adding a todo.Task object</h2>
<p>For this we are going to have to use the task dialog that we created in the GUI stage.  We are going to encapsulate the handling of displaying the dialog in a class.  It made sense to me to do this since this dialog is far more complicated then many that we have used before.</p>
<p>The class is called TaskDialog and I created it in the todo.py file:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">class </span><span class="hl-identifier">TaskDialog</span><span class="hl-brackets">(</span><span class="hl-identifier">object</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This is a class that is used to show a taskDialog.  It
	can be used to create or edit a todo.Task.  To create one
	simply initialize the class and do not pass a totoTask.  If you
	want to edit an object initialize with the object that
	you want to edit.</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-reserved">def </span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">glade_file</span><span class="hl-code">, </span><span class="hl-identifier">task</span><span class="hl-code"> = </span><span class="hl-reserved">None</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Initialize the task dialog.
		@param glade_file - string - the glade file for this
		dialog.
		@param task - todo.Task - None to create a new
		todo.Task object, or the object that you wish to
		edit.
		</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">glade_file</span><span class="hl-default"> = </span><span class="hl-identifier">glade_file
		self</span><span class="hl-default">.</span><span class="hl-identifier">task</span><span class="hl-default"> = </span><span class="hl-identifier">task

		</span><span class="hl-comment">#Get the widget tree
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default"> = </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">glade</span><span class="hl-default">.</span><span class="hl-identifier">XML</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">glade_file</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">taskDialog</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-comment">#Connect with yourself
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">signal_autoconnect</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">dialog</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">taskDialog</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-comment">#get the widgets from the dlg
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">en_title</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">enTitle</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">tv_details</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">tvDetails</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">en_due</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">enDue</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">btn_due</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">btnDue</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">cmb_Time</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">cmbTime</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">cmb_priority</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">cmbPriority</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">check_completed</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">checkCompleted</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-comment">#select the items in the combo boxes
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">cmb_Time</span><span class="hl-default">.</span><span class="hl-identifier">set_active</span><span class="hl-brackets">(</span><span class="hl-number">0</span><span class="hl-brackets">)
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">cmb_priority</span><span class="hl-default">.</span><span class="hl-identifier">set_active</span><span class="hl-brackets">(</span><span class="hl-number">2</span><span class="hl-brackets">)

		</span><span class="hl-identifier">wTreeDue</span><span class="hl-default"> = </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">glade</span><span class="hl-default">.</span><span class="hl-identifier">XML</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">glade_file</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">calendarWindow</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">calendar_window</span><span class="hl-default"> = </span><span class="hl-identifier">wTreeDue</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">calendarWindow</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-identifier">wTreeDue</span><span class="hl-default">.</span><span class="hl-identifier">signal_autoconnect</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)

		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">update_dialog_from_object</span><span class="hl-brackets">()</span></pre></div></div>
<p>As you can see what happens here is the TaskDialog is initialized with the path to the glade file that contains the taskDialog, and an optional todo.Task object.  If the todo.Task is not specified (or None) when creating the TaskDialog then the TaskDialog instance is in &#8220;add&#8221; mode, which means that it will create a todo.Task object with the settings specified on the dialog if the user presses the Ok button.</p>
<p>If an instance of a todo.Task object is used when constructing the TaskDialog then the dialog is in &#8220;edit&#8221; mode, and it will modify the object that was passed if the user presses the Ok button.</p>
<p>So not much happens in the __init__ function except we load the dialog and the calendar window from the glade file (the calendar window must be set not to be initially visible in the glade file!  Otherwise it will be shown when it is loaded.) and we auto connect the signals from the dialog and the window with the TaskDialog class.</p>
<p>Then we get access to all of the important widgets on the task dialog.  You&#8217;ll also notice that we set the active item in both the time and priority gtk.ComboBox&#8217;s using the <a href="http://www.pygtk.org/docs/pygtk/class-gtkcombobox.html#method-gtkcombobox--set-active">set_active()</a> function. </p>
<p>We do this so that the first item is selected in the time gtk.ComboBox (the blank)  and we select the third item in the priority gtk.ComboBox so that the low priority item is selected.</p>
<p>At the end of the function we call the update_dialog_from_object() function, this function is used to update what is displayed on the dialog based on the contents of the todo.Task.  There is a sister function named save_data_to_object() that is used to update the todo.Task item with the contents of the dialog:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">update_dialog_from_object</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Used to update the settings on the dialog</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">task</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-comment">#Title
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">en_title</span><span class="hl-default">.</span><span class="hl-identifier">set_text</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">task</span><span class="hl-code">.</span><span class="hl-identifier">name</span><span class="hl-brackets">)
		</span><span class="hl-comment">#Details
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">set_details</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">task</span><span class="hl-code">.</span><span class="hl-identifier">details</span><span class="hl-brackets">)
		</span><span class="hl-comment">#Due Date
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">en_due</span><span class="hl-default">.</span><span class="hl-identifier">set_text</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">task</span><span class="hl-code">.</span><span class="hl-identifier">get_date_string</span><span class="hl-brackets">())
		</span><span class="hl-comment">#Due Time
		</span><span class="hl-identifier">found_iter</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">find_text_in_combo</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">cmb_Time</span><span class="hl-code">
						, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">task</span><span class="hl-code">.</span><span class="hl-identifier">get_time_string</span><span class="hl-brackets">())
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">found_iter</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">cmb_Time</span><span class="hl-default">.</span><span class="hl-identifier">set_active_iter</span><span class="hl-brackets">(</span><span class="hl-identifier">found_iter</span><span class="hl-brackets">)
		</span><span class="hl-comment">#priority
		</span><span class="hl-identifier">found_iter</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">find_text_in_combo</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">cmb_priority</span><span class="hl-code">
									, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">task</span><span class="hl-code">.</span><span class="hl-identifier">priority</span><span class="hl-brackets">)
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">found_iter</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">cmb_priority</span><span class="hl-default">.</span><span class="hl-identifier">set_active_iter</span><span class="hl-brackets">(</span><span class="hl-identifier">found_iter</span><span class="hl-brackets">)
		</span><span class="hl-comment">#completed
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">check_completed</span><span class="hl-default">.</span><span class="hl-identifier">set_active</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">task</span><span class="hl-code">.</span><span class="hl-identifier">completed</span><span class="hl-brackets">)


</span><span class="hl-reserved">def </span><span class="hl-identifier">save_data_to_object</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function is used to read the data from the dialog
	and then store it in the todo.Task object.
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">task</span><span class="hl-code"> == </span><span class="hl-reserved">None</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">task</span><span class="hl-default"> = </span><span class="hl-identifier">Task</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">en_title</span><span class="hl-code">.</span><span class="hl-identifier">get_text</span><span class="hl-brackets">())
	</span><span class="hl-reserved">else</span><span class="hl-default">:
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">task</span><span class="hl-default">.</span><span class="hl-identifier">name</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">en_title</span><span class="hl-default">.</span><span class="hl-identifier">get_text</span><span class="hl-brackets">()

	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">task</span><span class="hl-default">.</span><span class="hl-identifier">details</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">get_details</span><span class="hl-brackets">()

	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">task</span><span class="hl-default">.</span><span class="hl-identifier">set_due_date_from_string</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">en_due</span><span class="hl-code">.</span><span class="hl-identifier">get_text</span><span class="hl-brackets">())
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">task</span><span class="hl-default">.</span><span class="hl-identifier">set_due_time_from_string</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">cmb_Time</span><span class="hl-code">.</span><span class="hl-identifier">get_active_text</span><span class="hl-brackets">())
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">task</span><span class="hl-default">.</span><span class="hl-identifier">priority</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">cmb_priority</span><span class="hl-default">.</span><span class="hl-identifier">get_active_text</span><span class="hl-brackets">()
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">task</span><span class="hl-default">.</span><span class="hl-identifier">completed</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">check_completed</span><span class="hl-default">.</span><span class="hl-identifier">get_active</span><span class="hl-brackets">()</span></pre></div></div>
<p>Over all these two functions are pretty straightforward, they simply marshal the date between the dialog and the todo.Task.  You&#8217;ll see that there are some helper functions that are used in both functions in order to make saving and loading the data from the object to the dialog easier.  For example to set the text in the gtk.TextView we use the set_details() function, and then to get the text we use the get_details() function:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">get_details</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function gets the details from the TextView
	@returns string - The text in the gtk.TextView
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">txtBuffer</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">tv_details</span><span class="hl-default">.</span><span class="hl-identifier">get_buffer</span><span class="hl-brackets">()
	</span><span class="hl-reserved">return </span><span class="hl-identifier">txtBuffer</span><span class="hl-default">.</span><span class="hl-identifier">get_text</span><span class="hl-brackets">(</span><span class="hl-code">*</span><span class="hl-identifier">txtBuffer</span><span class="hl-code">.</span><span class="hl-identifier">get_bounds</span><span class="hl-brackets">())

</span><span class="hl-reserved">def </span><span class="hl-identifier">set_details</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">details</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function sets the text in the defails gtk.TextView
	@param details - string - The text that will be
	put into the gtk.TextView.
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">txtBuffer</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">tv_details</span><span class="hl-default">.</span><span class="hl-identifier">get_buffer</span><span class="hl-brackets">()
	</span><span class="hl-identifier">txtBuffer</span><span class="hl-default">.</span><span class="hl-identifier">set_text</span><span class="hl-brackets">(</span><span class="hl-identifier">details</span><span class="hl-brackets">)</span></pre></div></div>
<p>These two function are very simple, we get the <a href="http://www.pygtk.org/docs/pygtk/class-gtktextbuffer.html">gkt.TextBuffer</a> associated with the gtk.TextView and then we use the <a href="http://www.pygtk.org/docs/pygtk/class-gtktextbuffer.html#method-gtktextbuffer--get-text">get_text()</a> and <a href="http://www.pygtk.org/docs/pygtk/class-gtktextbuffer.html#method-gtktextbuffer--set-text">set_text()</a> functions to get and set the text.</p>
<p>The next helper that we use is the find_text_in_combo() function:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">find_text_in_combo</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">combobox</span><span class="hl-code">, </span><span class="hl-identifier">text</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This is a helper function use to find text in
	a gtk.ComboBox.
	@param conbobox gtk.ComboBox - This should contain
	text.
	@param text - string - the text that we are looking
	to find.
	@returns - gtk.TreeIter - The iter at the found
	position or None if nothing was found.
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">found_iter</span><span class="hl-default"> = </span><span class="hl-reserved">None </span><span class="hl-comment">#The Iter where text is found
	#Get the gtk.TreeModel associated with the combo
	</span><span class="hl-identifier">combo_model</span><span class="hl-default"> = </span><span class="hl-identifier">combobox</span><span class="hl-default">.</span><span class="hl-identifier">get_model</span><span class="hl-brackets">()
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">combo_model</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-comment">#Get the first iter in the model
		</span><span class="hl-identifier">search_iter</span><span class="hl-default"> = </span><span class="hl-identifier">combo_model</span><span class="hl-default">.</span><span class="hl-identifier">get_iter_first</span><span class="hl-brackets">()
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Now loop through the model checking for
		matches until one is found.  Or until
		we have ran out of iters.</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">while </span><span class="hl-brackets">((</span><span class="hl-identifier">found_iter</span><span class="hl-code"> == </span><span class="hl-reserved">None</span><span class="hl-brackets">)
			</span><span class="hl-identifier">and </span><span class="hl-brackets">(</span><span class="hl-identifier">search_iter</span><span class="hl-brackets">))</span><span class="hl-default">:
			</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">text</span><span class="hl-code"> == </span><span class="hl-identifier">combo_model</span><span class="hl-brackets">[</span><span class="hl-identifier">search_iter</span><span class="hl-brackets">][</span><span class="hl-number">0</span><span class="hl-brackets">])</span><span class="hl-default">:
				</span><span class="hl-comment">#Found!
				</span><span class="hl-identifier">found_iter</span><span class="hl-default"> = </span><span class="hl-identifier">search_iter
			</span><span class="hl-reserved">else</span><span class="hl-default">:
				</span><span class="hl-identifier">search_iter</span><span class="hl-default"> = </span><span class="hl-identifier">combo_model</span><span class="hl-default">.</span><span class="hl-identifier">iter_next</span><span class="hl-brackets">(</span><span class="hl-identifier">search_iter</span><span class="hl-brackets">)
	</span><span class="hl-reserved">return </span><span class="hl-identifier">found_iter</span></pre></div></div>
<p>This function takes a gtk.ComboBox and a string as parameters and searches the gtk.TreeModel associated with the gtk.ComboBox for the text.  If the text is found then the gtk.TreeIter associated with that item is returned, otherwise None is returned.  The function is pretty simple, but I was slightly disappointed that there was no built in way to do this&#8230;perhaps I missed something or perhaps this will be addressed in a future release.</p>
<p>Then once we have the gtk.TreeIter we can use the <a href="http://www.pygtk.org/docs/pygtk/class-gtkcombobox.html#method-gtkcombobox--set-active-iter">set_active_iter()</a> to set that item as the current item in the gtk.ComboBox.  </p>
<p>To get the date and time we use the todo.Task.get_time_string() and todo.Task.get_date_string() functions that we have already touched on. The setting of the due date and due time however is slightly more complicated and I have not gone over it yet.  What we need to do is generate datetime.date and datetime.time instances from strings.</p>
<p>The following two functions in the todo.Task are used to accomplish this:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">set_due_date_from_string</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">date_string</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function is used to set the due_date based
	on a string. We will try to parse the string.  We will try
	to parse the following formats: YYYY-MM-DD
	, MM-DD-YYYY, or DD-MM-YYYY
	@param date_string - string - The string that we will
	turn into our datetime.date object.
	@returns boolean - success or failure</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">success</span><span class="hl-default"> = </span><span class="hl-reserved">False
	</span><span class="hl-comment">#Switch chars
	</span><span class="hl-identifier">date_string</span><span class="hl-default"> = </span><span class="hl-identifier">date_string</span><span class="hl-default">.</span><span class="hl-identifier">replace</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">/</span><span class="hl-quotes">&quot;</span><span class="hl-code">,</span><span class="hl-quotes">&quot;</span><span class="hl-string">-</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-identifier">date_string</span><span class="hl-default"> = </span><span class="hl-identifier">date_string</span><span class="hl-default">.</span><span class="hl-identifier">replace</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-special">\\</span><span class="hl-quotes">&quot;</span><span class="hl-code">,</span><span class="hl-quotes">&quot;</span><span class="hl-string">-</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-identifier">date_string</span><span class="hl-default"> = </span><span class="hl-identifier">date_string</span><span class="hl-default">.</span><span class="hl-identifier">replace</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot; &quot;</span><span class="hl-code">,</span><span class="hl-quotes">&quot;&quot;</span><span class="hl-brackets">)
	</span><span class="hl-comment">#All the possible formats
	</span><span class="hl-identifier">lst_formats</span><span class="hl-default"> = </span><span class="hl-brackets">[
		</span><span class="hl-quotes">&quot;</span><span class="hl-string">%Y-%m-%d</span><span class="hl-quotes">&quot;</span><span class="hl-code">
		, </span><span class="hl-quotes">&quot;</span><span class="hl-string">%m-%d-%Y</span><span class="hl-quotes">&quot;</span><span class="hl-code">
		, </span><span class="hl-quotes">&quot;</span><span class="hl-string">%d-%m-%Y</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">]
	</span><span class="hl-comment">#Now loop through the formats and try to find a match
	</span><span class="hl-identifier">date</span><span class="hl-default"> = </span><span class="hl-reserved">None
	for </span><span class="hl-identifier">format </span><span class="hl-reserved">in </span><span class="hl-identifier">lst_formats</span><span class="hl-default">:
		</span><span class="hl-reserved">try</span><span class="hl-default">:
			</span><span class="hl-identifier">date</span><span class="hl-default"> = </span><span class="hl-identifier">datetime</span><span class="hl-default">.</span><span class="hl-identifier">datetime</span><span class="hl-brackets">(</span><span class="hl-code">*</span><span class="hl-identifier">time</span><span class="hl-code">.</span><span class="hl-identifier">strptime</span><span class="hl-brackets">(</span><span class="hl-identifier">date_string</span><span class="hl-code">
						, </span><span class="hl-identifier">format</span><span class="hl-brackets">)[</span><span class="hl-number">0</span><span class="hl-code">:</span><span class="hl-number">3</span><span class="hl-brackets">])
			</span><span class="hl-comment">#We found a matching format
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">due_date</span><span class="hl-default"> = </span><span class="hl-identifier">date
			</span><span class="hl-comment">#Save the format
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">date_format</span><span class="hl-default"> = </span><span class="hl-identifier">format
			</span><span class="hl-reserved">break
		except</span><span class="hl-default">:
			</span><span class="hl-comment">#failed
			</span><span class="hl-reserved">pass
	return </span><span class="hl-identifier">success

</span><span class="hl-reserved">def </span><span class="hl-identifier">set_due_time_from_string</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">time_string</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function is used to set the due_time based
	on a string. We will try to parse the string.  We will try
	to parse some formats.
	@param time_string - string - A string representing the
	time.
	@returns - boolean success or failer
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">success</span><span class="hl-default"> = </span><span class="hl-reserved">False
	</span><span class="hl-comment">#strip whitespace
	</span><span class="hl-identifier">time_string</span><span class="hl-default"> = </span><span class="hl-identifier">time_string</span><span class="hl-default">.</span><span class="hl-identifier">replace</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot; &quot;</span><span class="hl-code">,</span><span class="hl-quotes">&quot;&quot;</span><span class="hl-brackets">)
	</span><span class="hl-comment">#All the possible formats
	</span><span class="hl-identifier">lst_formats</span><span class="hl-default"> = </span><span class="hl-brackets">[
		</span><span class="hl-quotes">&quot;</span><span class="hl-string">%I:%M%p</span><span class="hl-quotes">&quot;</span><span class="hl-code">
		, </span><span class="hl-quotes">&quot;</span><span class="hl-string">%H:%M%p</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">]
	</span><span class="hl-comment">#Now loop through the formats and try to find a match
	</span><span class="hl-identifier">due_time</span><span class="hl-default"> = </span><span class="hl-reserved">None
	for </span><span class="hl-identifier">format </span><span class="hl-reserved">in </span><span class="hl-identifier">lst_formats</span><span class="hl-default">:
		</span><span class="hl-reserved">try</span><span class="hl-default">:
			</span><span class="hl-identifier">time_struct</span><span class="hl-default"> = </span><span class="hl-identifier">time</span><span class="hl-default">.</span><span class="hl-identifier">strptime</span><span class="hl-brackets">(</span><span class="hl-identifier">time_string</span><span class="hl-code">
						, </span><span class="hl-identifier">format</span><span class="hl-brackets">)
			</span><span class="hl-identifier">due_time</span><span class="hl-default"> = </span><span class="hl-identifier">datetime</span><span class="hl-default">.</span><span class="hl-identifier">time</span><span class="hl-brackets">(</span><span class="hl-identifier">time_struct</span><span class="hl-code">.</span><span class="hl-identifier">tm_hour</span><span class="hl-code">
						, </span><span class="hl-identifier">time_struct</span><span class="hl-code">.</span><span class="hl-identifier">tm_min</span><span class="hl-brackets">)
			</span><span class="hl-comment">#Save the time
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">due_time</span><span class="hl-default"> = </span><span class="hl-identifier">due_time
			</span><span class="hl-comment">#Save the format that was used
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">time_format</span><span class="hl-default"> = </span><span class="hl-identifier">format
			success</span><span class="hl-default"> = </span><span class="hl-reserved">True
			break
		except</span><span class="hl-default">:
			</span><span class="hl-comment">#failed
			</span><span class="hl-reserved">pass
	return </span><span class="hl-identifier">success</span></pre></div></div>
<p>The functions are slightly difficult to understand I will take a little bit of time to explain how they work.  The general idea of the functions is to loop through a list of possible formats and try to create either a datetime.date or datetime.time instance using the current format.</p>
<p>If the creation throws an exception then it has failed, if it does not then it has succeeded and we need to save the format that we used (it becomes the format that we display things in, so if you type in the date in a certain way it will be displayed in that way,) and save the actual instance.</p>
<p>We use the time modules strptime function to create a struct_time, which we then use to create the date or time instance (from the <a href="http://docs.python.org/lib/module-time.html">python documentation</a>):</p>
<blockquote><p>
Parse a string representing a time according to a format. The return value is a struct_time as returned by gmtime() or localtime(). The format parameter uses the same directives as those used by strftime(); it defaults to &#8220;%a %b %d %H:%M:%S %Y&#8221; which matches the formatting returned by ctime(). If string cannot be parsed according to format, ValueError is raised. If the string to be parsed has excess data after parsing, ValueError is raised. The default values used to fill in any missing data when more accurate values cannot be inferred are (1900, 1, 1, 0, 0, 0, 0, 1, -1) .</p>
<p>Support for the %Z directive is based on the values contained in tzname and whether daylight is true. Because of this, it is platform-specific except for recognizing UTC and GMT which are always known (and are considered to be non-daylight savings timezones).
</p></blockquote>
<p>struct_time is simply a sequence of 9 integers that we can then use to create our date or time instances.  The only real difference between the two is that instead of always being able to use the first three numbers in the struct_time sequence when creating the date instance we need to reference the specific time members when creating the time object.</p>
<p>So the code is a bit complicated, but when you look the overview of what it&#8217;s doing it&#8217;s actually pretty simple.</p>
<p>The next thing we have to do is actually show do the dialog:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">run</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Show the dialog</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-identifier">break_out</span><span class="hl-default"> = </span><span class="hl-reserved">False
	</span><span class="hl-identifier">while </span><span class="hl-brackets">(</span><span class="hl-reserved">not </span><span class="hl-identifier">break_out</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">result</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">dialog</span><span class="hl-default">.</span><span class="hl-identifier">run</span><span class="hl-brackets">()
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">result</span><span class="hl-code">==</span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">RESPONSE_OK</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Save the date to the object becuase the use pressed
			ok.</span><span class="hl-quotes">&quot;&quot;&quot;
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">save_data_to_object</span><span class="hl-brackets">()
			</span><span class="hl-identifier">break_out</span><span class="hl-default"> = </span><span class="hl-reserved">True
			</span><span class="hl-comment">#Validate here eventually
		</span><span class="hl-reserved">else</span><span class="hl-default">:
			</span><span class="hl-identifier">break_out</span><span class="hl-default"> = </span><span class="hl-reserved">True

	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">dialog</span><span class="hl-default">.</span><span class="hl-identifier">hide</span><span class="hl-brackets">()

	</span><span class="hl-reserved">return </span><span class="hl-identifier">result</span><span class="hl-default">;</span></pre></div></div>
<p>Another simple function (I seem to say that a lot don&#8217;t I?) we&#8217;re just showing the dialog, and if the users clicks on the OK button we save the data to our todo.Task object and then we leave.  You might wonder why this is done in a loop, the reason is so that in the future we will be able to validate what the user has entered.</p>
<p>So when if the user clicks on the OK button and the validation fails, then we would not set break_out to True, and the dialog would be shown again.  This is just an easy way to set up the dialog for future validation.</p>
<p>The last thing that we need to do is actually use the dialog!  We do this in the on_add_task() function in our main PyLan class:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">on_add_task</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when we want to add a task.</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-identifier">model</span><span class="hl-default">, </span><span class="hl-identifier">selection_iter</span><span class="hl-default">, </span><span class="hl-identifier">todo_cat</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">get_category_selected</span><span class="hl-brackets">()
	</span><span class="hl-comment">#Make sure that a category is selected
	</span><span class="hl-identifier">if </span><span class="hl-brackets">((</span><span class="hl-identifier">model</span><span class="hl-brackets">) </span><span class="hl-identifier">and </span><span class="hl-brackets">(</span><span class="hl-identifier">selection_iter</span><span class="hl-brackets">) </span><span class="hl-identifier">and </span><span class="hl-brackets">(</span><span class="hl-identifier">todo_cat</span><span class="hl-brackets">))</span><span class="hl-default">:
		</span><span class="hl-identifier">task_dialog</span><span class="hl-default"> = </span><span class="hl-identifier">todo</span><span class="hl-default">.</span><span class="hl-identifier">TaskDialog</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">gladefile</span><span class="hl-brackets">)
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">task_dialog</span><span class="hl-code">.</span><span class="hl-identifier">run</span><span class="hl-brackets">()</span><span class="hl-code"> == </span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">RESPONSE_OK</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-comment">#Append to the tree
			</span><span class="hl-identifier">task_dialog</span><span class="hl-default">.</span><span class="hl-identifier">task</span><span class="hl-default">.</span><span class="hl-identifier">add_to_tree</span><span class="hl-brackets">(</span><span class="hl-identifier">model</span><span class="hl-code">
				, </span><span class="hl-identifier">selection_iter</span><span class="hl-code">
				, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">__tree_columns</span><span class="hl-brackets">)
			</span><span class="hl-comment">#Add to the Category
			</span><span class="hl-identifier">todo_cat</span><span class="hl-default">.</span><span class="hl-identifier">add_child</span><span class="hl-brackets">(</span><span class="hl-identifier">task_dialog</span><span class="hl-code">.</span><span class="hl-identifier">task</span><span class="hl-brackets">)</span></pre></div></div>
<p>Pretty simple stuff here again (I&#8217;m like a broken record!) we get the selected category, if all of the variables come through then we create the todo.TaskDialog in &#8220;add&#8221; mode and then we run it.  If the response is gtk.RESPONSE_OK we add the task to the tree, and then add the task to the category.</p>
<p>If you are wondering about the last two steps there, then you should check out the first tutorial where those helpers are explained.</p>
<h2><a name="calendarWindow"></a>Showing the Calendar window</h2>
<p>This next step took me a long time to figure out even though the actual code is very short.  This step is getting the calendar window, that we created in our glade project, to display when the user clicks on the Due Date &#8220;dropdown&#8221; button.</p>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_01/pylan_01_07.png" alt="Python GTD pyGTK" border="0" /></p>
<p>So here is the code:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">on_btnDue_clicked</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when the due button is clicked.</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">rect</span><span class="hl-default"> = </span><span class="hl-identifier">widget</span><span class="hl-default">.</span><span class="hl-identifier">get_allocation</span><span class="hl-brackets">()
	</span><span class="hl-identifier">x</span><span class="hl-default">, </span><span class="hl-identifier">y</span><span class="hl-default"> = </span><span class="hl-identifier">widget</span><span class="hl-default">.</span><span class="hl-identifier">window</span><span class="hl-default">.</span><span class="hl-identifier">get_origin</span><span class="hl-brackets">()
	</span><span class="hl-identifier">cal_width</span><span class="hl-default">, </span><span class="hl-identifier">cal_height</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">calendar_window</span><span class="hl-default">.</span><span class="hl-identifier">get_size</span><span class="hl-brackets">()

	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">calendar_window</span><span class="hl-default">.</span><span class="hl-identifier">move</span><span class="hl-brackets">((</span><span class="hl-identifier">x</span><span class="hl-code"> + </span><span class="hl-identifier">rect</span><span class="hl-code">.</span><span class="hl-identifier">x</span><span class="hl-code"> - </span><span class="hl-identifier">cal_width</span><span class="hl-code"> + </span><span class="hl-identifier">rect</span><span class="hl-code">.</span><span class="hl-identifier">width</span><span class="hl-brackets">)</span><span class="hl-code">
		, </span><span class="hl-brackets">(</span><span class="hl-identifier">y</span><span class="hl-code"> + </span><span class="hl-identifier">rect</span><span class="hl-code">.</span><span class="hl-identifier">y</span><span class="hl-code"> + </span><span class="hl-identifier">rect</span><span class="hl-code">.</span><span class="hl-identifier">height</span><span class="hl-brackets">))

	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">calendar_window</span><span class="hl-default">.</span><span class="hl-identifier">show</span><span class="hl-brackets">()

	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Because some window managers ignore move before
	you show a window.</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">calendar_window</span><span class="hl-default">.</span><span class="hl-identifier">move</span><span class="hl-brackets">((</span><span class="hl-identifier">x</span><span class="hl-code"> + </span><span class="hl-identifier">rect</span><span class="hl-code">.</span><span class="hl-identifier">x</span><span class="hl-code"> - </span><span class="hl-identifier">cal_width</span><span class="hl-code"> + </span><span class="hl-identifier">rect</span><span class="hl-code">.</span><span class="hl-identifier">width</span><span class="hl-brackets">)</span><span class="hl-code">
		, </span><span class="hl-brackets">(</span><span class="hl-identifier">y</span><span class="hl-code"> + </span><span class="hl-identifier">rect</span><span class="hl-code">.</span><span class="hl-identifier">y</span><span class="hl-code"> + </span><span class="hl-identifier">rect</span><span class="hl-code">.</span><span class="hl-identifier">height</span><span class="hl-brackets">))</span></pre></div></div>
<p>So the first thing we do is use the <a href="http://www.pygtk.org/docs/pygtk/class-gtkwidget.html#method-gtkwidget--get-allocation">gtk.Widget.get_allocation()</a> function to get the <a href="http://www.pygtk.org/docs/pygtk/class-gdkrectangle.html">gtk.gdk.Rectangle</a> representing the size of the btnDue button.</p>
<p>Then we get the X and Y screen coordinates of the <a href="http://www.pygtk.org/docs/pygtk/class-gdkwindow.html">gtk.gdk.Window</a> (the window where the widget is actually drawn) using the <a href="http://www.pygtk.org/docs/pygtk/class-gdkwindow.html#method-gdkwindow--get-origin">get_origin()</a> function.  This is in root window coordinates instead of being relative to the parent window.  So this is actually the top left corner of the TaskDialog.</p>
<p>Then we get the height and width of the calendar window, and finally move it into position so that the top right corner of the calendar window lines up with the bottom right corner of the btnDue widget.</p>
<p>So, we take the top left corner of the dialog, and then add onto it the x,y coordinates of the btnDue (which are relative to the top left cornet of the TaskDialog) and then we add to it the height and the width of the btnDue so that we get the X and Y of the bottom right corder of the btnDue.  Then we subtract the width of the calendar window, so that the right side of the calendar window lines up with the right side of the btnDue.</p>
<p>If this seems a bit confusing try playing with the numbers a little bit, commenting out parts of the equation, and then see where the calendar window shows up.  After playing with it a little bit it should be pretty straight forward.</p>
<p>So what happens when then calendar window is displayed?  Well it will stay visible until the user double-clicks on a date, or clicks on the &#8220;No Date&#8221; button.</p>
<p>So we need to add two signal handlers:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">on_btnNoDate_clicked</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when the now date widget is
	clicked.  This means that they do not want
	a due date.</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-comment">#Hide the calendar window
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">calendar_window</span><span class="hl-default">.</span><span class="hl-identifier">hide</span><span class="hl-brackets">()
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">en_due</span><span class="hl-default">.</span><span class="hl-identifier">set_text</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;&quot;</span><span class="hl-brackets">)

</span><span class="hl-reserved">def </span><span class="hl-identifier">on_calendarWidget_day_selected_double_click</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when the used has double-clicked on a date
	in the calendar widget</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-comment">#Hide the calendar window
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">calendar_window</span><span class="hl-default">.</span><span class="hl-identifier">hide</span><span class="hl-brackets">()

	</span><span class="hl-identifier">year</span><span class="hl-default">, </span><span class="hl-identifier">month</span><span class="hl-default">, </span><span class="hl-identifier">day</span><span class="hl-default"> = </span><span class="hl-identifier">widget</span><span class="hl-default">.</span><span class="hl-identifier">get_date</span><span class="hl-brackets">()
	</span><span class="hl-identifier">month</span><span class="hl-default"> +=</span><span class="hl-number">1 </span><span class="hl-comment">#since it's 0 based
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">en_due</span><span class="hl-default">.</span><span class="hl-identifier">set_text</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">%d-%02d-%02d</span><span class="hl-quotes">&quot;</span><span class="hl-code"> % </span><span class="hl-brackets">(</span><span class="hl-identifier">year</span><span class="hl-code">, </span><span class="hl-identifier">month</span><span class="hl-code">, </span><span class="hl-identifier">day</span><span class="hl-brackets">))</span></pre></div></div>
<p>Pretty simple stuff here, if the &#8220;No Date&#8221; button is clicked then we blank out the due date edit field, and if a date is double clicked on, we get the date from the gtk.Calendar using the <a href="http://www.pygtk.org/docs/pygtk/class-gtkcalendar.html#method-gtkcalendar--get-date">get_date()</a> function.  Then we set the date in the edit fields based on those values.</p>
<p>For now we use a standard format, but in the future we could easily work with the date_format stored in the todo.Task object.</p>
<h2><a name="EditingItems"></a>Editing todo.Category and todo.Task items</h2>
<p>The next step is letting the user edit a todo.Category or todo.Task item that they have already added to the list.  Fortunately the way that we have shown both the Category and Task dialogs makes this step very easy.</p>
<p>The first thing that we need to do is add an &#8220;edit&#8221; event handler in the PyLan class.  This function can be triggered from a menu item, or from the edit button in the main toolbar:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">on_edit_object</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when we want to edit the selected item</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-comment"># Get the selected object
	</span><span class="hl-identifier">model</span><span class="hl-default">, </span><span class="hl-identifier">selection_iter</span><span class="hl-default">, </span><span class="hl-identifier">todo_ob</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">get_selected_object</span><span class="hl-brackets">()
	</span><span class="hl-identifier">if </span><span class="hl-brackets">((</span><span class="hl-identifier">selection_iter</span><span class="hl-brackets">) </span><span class="hl-identifier">and </span><span class="hl-brackets">(</span><span class="hl-identifier">model</span><span class="hl-brackets">) </span><span class="hl-identifier">and </span><span class="hl-brackets">(</span><span class="hl-identifier">todo_ob</span><span class="hl-brackets">))</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">All right something and we have all the needed data</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">edit_object</span><span class="hl-brackets">(</span><span class="hl-identifier">todo_ob</span><span class="hl-code">, </span><span class="hl-identifier">model</span><span class="hl-code">, </span><span class="hl-identifier">selection_iter</span><span class="hl-brackets">)</span></pre></div></div>
<p>Pretty simple, we call a helper function get_selected_object() which does exactly that, gets the selected object, the gtk.TreeIter associated with it, and the gtk.TreeModel that it is displayed in.  Then we call edit object with those parameters.  </p>
<p>get_selected_object() is a lot like the get_selected_category() function:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">get_selected_object</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Just a helper function that will give you the
	selected object, whether it is a todoItem or
	a todoTask.
	@returns A 3-tuple containing a reference to the
	gtk.TreeModel and a gtk.TreeIter pointing to the
	currently selected node. Just like
	gtk.TreeSelection.get_selected but with the todoObject
	being returned as well.</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-identifier">todo_ob</span><span class="hl-default"> = </span><span class="hl-reserved">None
	</span><span class="hl-identifier">tcolumn</span><span class="hl-default">, </span><span class="hl-identifier">pos</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">find_todoColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">COL_OBJECT</span><span class="hl-brackets">)
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-reserved">not </span><span class="hl-identifier">tcolumn</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-reserved">return None</span><span class="hl-default">,</span><span class="hl-reserved">None</span><span class="hl-default">,</span><span class="hl-reserved">None

	</span><span class="hl-comment">#Get the current selection in the gtk.TreeView
	</span><span class="hl-identifier">selection</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todoTreeView</span><span class="hl-default">.</span><span class="hl-identifier">get_selection</span><span class="hl-brackets">()
	</span><span class="hl-comment"># Get the selection iter
	</span><span class="hl-identifier">model</span><span class="hl-default">, </span><span class="hl-identifier">selection_iter</span><span class="hl-default"> = </span><span class="hl-identifier">selection</span><span class="hl-default">.</span><span class="hl-identifier">get_selected</span><span class="hl-brackets">()
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">selection_iter </span><span class="hl-reserved">and </span><span class="hl-identifier">model</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-comment">#Something is selected so get the object
		</span><span class="hl-identifier">todo_ob</span><span class="hl-default"> = </span><span class="hl-identifier">model</span><span class="hl-default">.</span><span class="hl-identifier">get_value</span><span class="hl-brackets">(</span><span class="hl-identifier">selection_iter</span><span class="hl-code">, </span><span class="hl-identifier">tcolumn</span><span class="hl-code">.</span><span class="hl-identifier">pos</span><span class="hl-brackets">)
	</span><span class="hl-reserved">return </span><span class="hl-identifier">model</span><span class="hl-default">, </span><span class="hl-identifier">selection_iter</span><span class="hl-default">, </span><span class="hl-identifier">todo_ob</span></pre></div></div>
<p>The edit_object() function is equally as easy:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">edit_object</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">todo_object</span><span class="hl-code">, </span><span class="hl-identifier">model</span><span class="hl-code">, </span><span class="hl-identifier">object_iter</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Helper function used to edit an object in the tree.
	@param todo_object - todoBase - The object that we
	are editing.
	@param model - gtk.TreeModel - The model for the tree.
	@param object_iter - gtk.TreeIter representing the
	todo_object's position in the tree.
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-comment">#Just make sure that they are all correct
	</span><span class="hl-identifier">if </span><span class="hl-brackets">((</span><span class="hl-identifier">todo_object</span><span class="hl-brackets">) </span><span class="hl-identifier">and </span><span class="hl-brackets">(</span><span class="hl-identifier">model</span><span class="hl-brackets">) </span><span class="hl-identifier">and </span><span class="hl-brackets">(</span><span class="hl-identifier">object_iter</span><span class="hl-brackets">))</span><span class="hl-default">:
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">todo_object</span><span class="hl-code">.</span><span class="hl-identifier">type</span><span class="hl-code"> == </span><span class="hl-identifier">todo</span><span class="hl-code">.</span><span class="hl-identifier">CATEGORY</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-comment">#Edit category
			</span><span class="hl-identifier">name</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">show_category_dialog</span><span class="hl-brackets">(</span><span class="hl-identifier">todo_object</span><span class="hl-code">.</span><span class="hl-identifier">name</span><span class="hl-brackets">)
			</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">name</span><span class="hl-brackets">)</span><span class="hl-default">:
				</span><span class="hl-identifier">todo_object</span><span class="hl-default">.</span><span class="hl-identifier">name</span><span class="hl-default"> = </span><span class="hl-identifier">name
				todo_object</span><span class="hl-default">.</span><span class="hl-identifier">set_tree_values</span><span class="hl-brackets">(</span><span class="hl-identifier">model</span><span class="hl-code">
					, </span><span class="hl-identifier">object_iter</span><span class="hl-code">
					, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">__tree_columns</span><span class="hl-brackets">)
		</span><span class="hl-reserved">else</span><span class="hl-default">:
			</span><span class="hl-comment">#Edit task
			</span><span class="hl-identifier">task_dialog</span><span class="hl-default"> = </span><span class="hl-identifier">todo</span><span class="hl-default">.</span><span class="hl-identifier">TaskDialog</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">gladefile</span><span class="hl-code">, </span><span class="hl-identifier">todo_object</span><span class="hl-brackets">)
			</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">task_dialog</span><span class="hl-code">.</span><span class="hl-identifier">run</span><span class="hl-brackets">()</span><span class="hl-code"> == </span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">RESPONSE_OK</span><span class="hl-brackets">)</span><span class="hl-default">:
				</span><span class="hl-identifier">todo_object</span><span class="hl-default">.</span><span class="hl-identifier">set_tree_values</span><span class="hl-brackets">(</span><span class="hl-identifier">model</span><span class="hl-code">
					, </span><span class="hl-identifier">object_iter</span><span class="hl-code">
					, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">__tree_columns</span><span class="hl-brackets">)</span></pre></div></div>
<p>So what we do is ensure that the parameters passed in are valid, then we check the type of the object, and then show the correct dialog.  If the user presses the Ok button then we update the data that is stored in the model by calling a new function set_tree_values():</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">set_tree_values</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">tree_model</span><span class="hl-code">, </span><span class="hl-identifier">iter</span><span class="hl-code">, </span><span class="hl-identifier">todoColumnList</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This is used to set the values in a tree.
	For whatever reason you cannot use the same list that you
	use to append items into the tree?  I don't know why.
	@param tree - gtk.TreeStore - The tree store that we will be
	setting the values in
	@param iter - gtk.TreeIter - The item in the tree
	@param todoColumnList - list - A list of todoColumn items.
	Their type member should use used to determine the order
	of the returned list.</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">lst_values</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">get_column_list</span><span class="hl-brackets">(</span><span class="hl-identifier">todoColumnList</span><span class="hl-brackets">)
	</span><span class="hl-identifier">count</span><span class="hl-default"> = </span><span class="hl-number">0
	</span><span class="hl-reserved">for </span><span class="hl-identifier">value </span><span class="hl-reserved">in </span><span class="hl-identifier">lst_values</span><span class="hl-default">:
		</span><span class="hl-identifier">tree_model</span><span class="hl-default">.</span><span class="hl-identifier">set_value</span><span class="hl-brackets">(</span><span class="hl-identifier">iter</span><span class="hl-code">, </span><span class="hl-identifier">count</span><span class="hl-code">, </span><span class="hl-identifier">value</span><span class="hl-brackets">)
		</span><span class="hl-identifier">count</span><span class="hl-default"> += </span><span class="hl-number">1</span></pre></div></div>
<p>This function is defined in the todo.todoBase class, which is the base class for both the todo.Task and todo.Caegory.  It can be overwritten by either if they want to perform some special processing, but by default it does everything that we need.  It gets the list of values to display in the tree, and then loops through that list setting each value in the model.</p>
<p>So that&#8217;s basically editing items, not too difficult.  The only other feature that I added was allowing you to edit an item when you double-click on in the gtk.TreeView.  I was slightly surprised to find out that there was no &#8220;double-click&#8221; signal for the gtk.TreeView instead one has to handle the <a href="http://www.pygtk.org/docs/pygtk/class-gtktreeview.html#signal-gtktreeview--row-activated">row-activated</a> signal:</p>
<blockquote><p>
The &#8220;row-activated&#8221; signal is emitted when the row_activated() method is called or the user double clicks a treeview row. &#8220;row-activated&#8221; is also emitted when a non-editable row is selected and one of the keys: Space, Shift+Space, Return or Enter is pressed.
</p></blockquote>
<p>So we can handle the &#8220;row-activated&#8221; signal like this:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">on_todoTree_row_activated</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">tree_view</span><span class="hl-code">, </span><span class="hl-identifier">path</span><span class="hl-code">, </span><span class="hl-identifier">tree_column</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This is called when a row is &quot;activated&quot; in the tree
	view.  It happens when the user double clicks on an item
	in the tree.  We will use it to edit the item.
	@param tree_view gtk.TreeView - The Tree
	@param path - string - The path string
	@param tree_column - gtk.TreeViewColumn - The column that
	was clicked on.
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-comment">#Get the column of the object
	</span><span class="hl-identifier">tcolumn</span><span class="hl-default">, </span><span class="hl-identifier">pos</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">find_todoColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">COL_OBJECT</span><span class="hl-brackets">)
	</span><span class="hl-identifier">model</span><span class="hl-default"> = </span><span class="hl-identifier">tree_view</span><span class="hl-default">.</span><span class="hl-identifier">get_model</span><span class="hl-brackets">()
	</span><span class="hl-identifier">if </span><span class="hl-brackets">((</span><span class="hl-identifier">tcolumn</span><span class="hl-brackets">) </span><span class="hl-identifier">and </span><span class="hl-brackets">(</span><span class="hl-identifier">model</span><span class="hl-brackets">))</span><span class="hl-default">:
		</span><span class="hl-comment">#Now get the selection iter from the path
		</span><span class="hl-identifier">selection_iter</span><span class="hl-default"> = </span><span class="hl-identifier">model</span><span class="hl-default">.</span><span class="hl-identifier">get_iter</span><span class="hl-brackets">(</span><span class="hl-identifier">path</span><span class="hl-brackets">)
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">selection_iter</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-comment">#Now that we have the selection let's get the object
			</span><span class="hl-identifier">todo_ob</span><span class="hl-default"> = </span><span class="hl-identifier">model</span><span class="hl-default">.</span><span class="hl-identifier">get_value</span><span class="hl-brackets">(</span><span class="hl-identifier">selection_iter</span><span class="hl-code">, </span><span class="hl-identifier">tcolumn</span><span class="hl-code">.</span><span class="hl-identifier">pos</span><span class="hl-brackets">)
			</span><span class="hl-comment">#Now lets edit the object
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">edit_object</span><span class="hl-brackets">(</span><span class="hl-identifier">todo_ob</span><span class="hl-code">, </span><span class="hl-identifier">model</span><span class="hl-code">, </span><span class="hl-identifier">selection_iter</span><span class="hl-brackets">)</span></pre></div></div>
<p>First we get the model and the object column.  Then we use the path that was passed to the signal handler to get the gtk.TreeIter that matches it. Then we get the todo object and we edit it.  </p>
<p>Pretty simple, and now instead of having to find the edit button in the toolbar you can simple double-click on an item in order to edit it.</p>
<h2><a name="PangoMarkup"></a>Pango markup in the gtk.TreeView</h2>
<p>Since you currently cannot tell the difference between a category and a task I decided to make the category titles bold so that you can quickly tell the difference.</p>
<p>This is actually quite easy to do once you know <i>what</i> you need to do.  It took me a little while to find information on how to do this, but once I was able to find the information implementing it was pretty simple.</p>
<p>The first thing that we need to do is update the todoColumn object to have a new member variable: markup. This lets us know that this column will display markup instead of simple text.</p>
<p>So now the create_column() function in the todoColumn class, which was added to handle the creating of columns, looks like this:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">create_column</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:

	</span><span class="hl-identifier">column</span><span class="hl-default"> = </span><span class="hl-reserved">None
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">visible</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">markup</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-identifier">column</span><span class="hl-default"> = </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">TreeViewColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">name</span><span class="hl-code">
					, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">cellrenderer</span><span class="hl-code">
					, </span><span class="hl-identifier">text</span><span class="hl-code"> = </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">pos</span><span class="hl-brackets">)
		</span><span class="hl-reserved">else</span><span class="hl-default">:
			</span><span class="hl-identifier">column</span><span class="hl-default"> = </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">TreeViewColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">name</span><span class="hl-code">
					, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">cellrenderer</span><span class="hl-code">
					, </span><span class="hl-identifier">markup</span><span class="hl-code"> = </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">pos</span><span class="hl-brackets">)

	</span><span class="hl-reserved">return </span><span class="hl-identifier">column</span></pre></div></div>
<p>So if the member variable markup is set to True, then instead of getting the text from the specified position in the model, the column gets the markup from that position.</p>
<p>Then when the todo.Category populates the tree with it&#8217;s values in the get_coloumn_list() it returns the title with markup:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">get_column_list</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">todoColumnList</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function is used to get the display list
	for the todoTree. The todoCOlumnList controls the
	order that the list will be returned in.
	@param todoColumnList - list - A list of todoColumn items.
	Their type member should use used to determine the order
	of the returned list.
	@returns list - A list for the todoTree.
	</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-identifier">lst_return</span><span class="hl-default"> = </span><span class="hl-brackets">[]
	</span><span class="hl-comment"># Loop through the columns and create the return list
	</span><span class="hl-reserved">for </span><span class="hl-identifier">item_column </span><span class="hl-reserved">in </span><span class="hl-identifier">todoColumnList</span><span class="hl-default">:
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">COL_OBJECT</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)
		</span><span class="hl-identifier">elif </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">COL_OBJECT_TYPE</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">type</span><span class="hl-brackets">)
		</span><span class="hl-identifier">elif </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">COL_TITLE</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">&lt;b&gt;%s&lt;/b&gt;</span><span class="hl-quotes">&quot;</span><span class="hl-code"> % </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">name</span><span class="hl-brackets">)
		</span><span class="hl-reserved">else</span><span class="hl-default">:
			</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;&quot;</span><span class="hl-brackets">)
	</span><span class="hl-reserved">return </span><span class="hl-identifier">lst_return</span></pre></div></div>
<p>So pretty simple, we wrap the title in the bold tags and then it displays as bold.</p>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_01/pylan_01_08.png" alt="Python GTD pyGTK" border="0" /></p>
<h2><a name="Conclusion"></a>Conclusion</h2>
<p>You can download the full source to this tutorial <a href="http://www.learningpython.com/sources/PyLan_02.tar.gz">here</a>.</p>
<p>So that&#8217;s it for this one, not as long or drawn out as the last one, but I think some interesting ground is covered.  Again this isn&#8217;t necessarily to teach you how to do everything that I&#8217;m doing, but to provide examples of how one <i>might</i> do things.</p>
<p>If you&#8217;re ever wanting to program something that you have never done before, I always think it&#8217;s nice to see examples of how other people do it.  Even if you don&#8217;t do it in the exact same manner, you will at least have an idea of how to approach the task.  Something that I really couldn&#8217;t find for a few features.  For example the  drop-down gtk.Calendar, which, come to think of it, would make a really nice custom widget if anyone was thinking of creating one.</p>
<p>As always if you find any errors or have any questions feel free to leave a comment.  If however you have a general question about python or PyGTK I would appreciate it if you ask it in the <a href="http://www.learningpython.com/forums/">LearningPython</a> forums so that a possible solution to someone elses problem will not get buried in an unrelated area.</p>
<div style="float:right;margin:0px 0px 0px 0px;"><a href="http://www.google.com/reader/link?url=http://www.learningpython.com/2007/03/11/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-two/&title=PyLan a GTD todo application written in python and PyGTK - part two&srcTitle=learning python&srcURL=http://www.learningpython.com"target="_blank" rel=""><img border="0" src="http://www.learningpython.com/wp-content/plugins/wp-google-buzz/icon/12.png" style="opacity:1;filter:alpha(opacity=100)" onmouseover="this.style.opacity=0.8;this.filters.alpha.opacity=70" onmouseout="this.style.opacity=1;this.filters.alpha.opacity=100"/> </a></div>]]></content:encoded>
			<wfw:commentRss>http://www.learningpython.com/2007/03/11/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-two/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>PyLan a GTD todo application written in python and PyGTK &#8211; part one</title>
		<link>http://www.learningpython.com/2007/02/17/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-one/</link>
		<comments>http://www.learningpython.com/2007/02/17/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-one/#comments</comments>
		<pubDate>Sat, 17 Feb 2007 22:47:03 +0000</pubDate>
		<dc:creator>selsine</dc:creator>
				<category><![CDATA[PyGTK]]></category>
		<category><![CDATA[PyLan]]></category>
		<category><![CDATA[glade]]></category>
		<category><![CDATA[gui]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://www.learningpython.com/?p=56</guid>
		<description><![CDATA[
			
				
			
		
Introduction
All right, many of you have probably heard of, or read, David Allen&#8217;s book Getting Things Done if not it&#8217;s a pretty interesting book about how to organize the things in your life.  
As I was reading it I thought that a simple todo list could be created using Python and PyGTK pretty easily, [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;">
			<a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.learningpython.com%2F2007%2F02%2F17%2Fpylan-a-gtd-todo-application-written-in-python-and-pygtk-part-one%2F"><br />
				<img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.learningpython.com%2F2007%2F02%2F17%2Fpylan-a-gtd-todo-application-written-in-python-and-pygtk-part-one%2F&amp;style=normal" height="61" width="50" /><br />
			</a>
		</div>
<h2>Introduction</h2>
<p>All right, many of you have probably heard of, or read, David Allen&#8217;s book <a href="http://en.wikipedia.org/wiki/Getting_Things_Done">Getting Things Done</a> if not it&#8217;s a pretty interesting book about how to organize the things in your life.  </p>
<p>As I was reading it I thought that a simple todo list could be created using Python and PyGTK pretty easily, so I decided to create the application and write a tutorial surrounding it.  Since the actual application is quite large I have decided to break it up into a series of tutorials, each highlighting a few specific tasks.  The full goal of this series is to show everything that is required when creating a python/PyGTK based application, for the GUI setup  all the way to distribution.</p>
<p>These tutorials assume that you have a basic knowledge of python and PyGTK.  If you have not already done so it is recommended that you take a look at some of my previous PyGTK based tutorials as I will be glossing over much of that which is explained there:</p>
<ul>
<li><a href="http://www.learningpython.com/2006/05/07/creating-a-gui-using-pygtk-and-glade/">Creating a GUI using PyGTK and Glade</a></li>
<li><a href="http://www.learningpython.com/2006/05/30/building-an-application-with-pygtk-and-glade/">Building an Application with PyGTK and Glade</a></li>
<li><a href="http://www.learningpython.com/2006/09/02/extending-our-pygtk-application/">Extending our PyGTK Application</a></li>
<li><a href="http://www.learningpython.com/2006/12/03/translating-your-pythonpygtk-application/">Translating your Python/PyGTK application</a></li>
<li><a href="http://www.learningpython.com/2006/07/25/writing-a-custom-widget-using-pygtk/">Writing a Custom Widget Using PyGTK</a></li>
<li><a href="http://www.learningpython.com/2006/08/19/wordpress-python-library/">WordPy offline blogging tool</a></li>
<li><a href="http://www.learningpython.com/2006/10/24/wordpy-02-using-xml-to-save-and-load-data/">WordPy 0.2 &#8211; Using XML to Save and Load Data</a></li>
</ul>
<h2>PyLan &#8211; part one</h2>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_01/pylan_01_01.png" alt="Python GTD pyGTK" border="0" /></p>
<p>So the application that we will be creating will be called PyLan, pronounced: plan.  In brief it will be used to create a tree of tasks that can be organized into categories and subcategories.</p>
<p>You can download the full source to this tutorial <a href="http://www.learningpython.com/sources/PyLan_01.tar.gz">here</a>.</p>
<p>Part one of this tutorial will introduce you to the idea of the application and create the basic shell for it.  It will outline the following:</p>
<ul>
<li>Creating the basic GUI in Glade</li>
<li>Working with a <a href="http://www.pygtk.org/docs/pygtk/class-gtktreeview.html">gtk.TreeView</a></li>
<li>Working with a <a href="http://www.pygtk.org/docs/pygtk/class-gtktreestore.html">gtk.TreeStore</a></li>
<li>Saving and loading the data from the tree using <a href="http://docs.python.org/lib/module-cPickle.html">cPickle</a>.</li>
<li>Using a <a href="http://www.pygtk.org/docs/pygtk/class-gtkmenutoolbutton.html">gtk.MenuToolButton</a></li>
</ul>
<p><span id="more-56"></span></p>
<p>The tutorial is organized into the following sections:</p>
<ol>
<li><a href="#TheGUI">The GUI</a></li>
<li><a href="#SettingItAllUp">The Code: Setting it all up</a></li>
<li><a href="#InitializingTheTree">The Code: Initializing the tree</a></li>
<li><a href="#TodoItems">The Code: todo items</a></li>
<li><a href="#AddingCategories">The Code: Adding Categories</a></li>
<li><a href="#RemovingCategories">The Code: Removing Categories</a></li>
<li><a href="#SavingAndLoadingWithcPickle">The Code: Saving and Loading with cPickle</a></li>
<li><a href="#ConnectingOurMenuWithThegtk.MenuToolButton">The Code: Connecting our menu with the gtk.MenuToolButton</a></li>
<li><a href="#Conclusion">Conclusion</a></li>
</ol>
<h2><a name="TheGUI"></a>The GUI</h2>
<p>The GUI will be created using Glade, it will be a relatively simple especially in this first part.  Since the glade project file is available I won&#8217;t go into too much detail about how to create this GUI, however I will outline the major steps that one could follow in case they would like to create their own GUI, or model a GUI after this one.</p>
<p><strong>The main window:</strong></p>
<ol>
<li>Create a new Glade Project and save it as pylan a folder named PyLan that you have created.</li>
<li>Create a window, and call it &#8220;mainWindow&#8221;, set its title to be PyLan.  If you are using Glade3 make sure that you set your window to be visible.  Add the GObject destroy signal handler like usual.  On the common tab set the width to be 400 and the height to be 300.</li>
<li>Add a vertical box to the window and give it 4 rows.</li>
<li>In the first row add a menu, call it &#8220;mainMenu&#8221;.  Make the Quit menu item&#8217;s menu handler the same as the Main Windows destroy signal handler.  For the rest of the File menu items, give them signal handlers using the following format: &#8220;on_file_new&#8221;, &#8220;on_file_open&#8221;, and so on.</li>
<li>In the second row add a tool bar with two items.</li>
<li>In the first spot add a GtkMenuToolButton, and set its name to &#8220;btnAdd&#8221;.  Make it a stock gtk-add button, and add a clicked signal handler with the name &#8220;on_add_category&#8221;.
</li>
<li>In the second spot at a GtkToolButton with the name &#8220;btnRemoveCategory&#8221;, being a stock gtk-remove button.  Set its clicked signal hander to be &#8220;on_remove_item&#8221;.</li>
<li>In the fourth row add a Status Bar.</li>
<li>In the Third row add a Tree View, set its name to be &#8220;todoTree&#8221;</li>
</ol>
<p><strong>The category dialog</strong></p>
<ol>
<li>Now create a Dialog with an Ok and a Cancel button.  Sets it&#8217;s name to be &#8220;categoryDialog&#8221;, and its title to be </li>
<li>&#8220;Category&#8221;.  Give it a default width and a width of 300.  Set its named icon to be: &#8220;stock_post-message&#8221;.</li>
<li>Add a GTKHBox to the dialog with two columns.</li>
<li>In the fist column add a GtkLabel with the label &#8220;Name:&#8221;. Give it an X Pad of 3 pixels.</li>
<li>In the second column add a GtkEntry with the name: &#8220;enName&#8221;</li>
</ol>
<p><strong>The Menu for the Add button</strong></p>
<p>Since we used a GtkMenuToolButton, we need to create the menu that we are going to associate with that button.  To do that we will use a GtkMenu.</p>
<ol>
<li>Create a GtkMenu and call it: &#8220;addMenu&#8221;</li>
<li>Add one Menu item to the menu with the label &#8220;Add _Category&#8221;.  Set the menu items handler &#8220;on_add_category&#8221;</li>
</ol>
<p>After all of that you should be left with something like this:</p>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_01/pylan_01_01.png" alt="Python GTD pyGTK" border="0" /></p>
<h2><a name="SettingItAllUp">The Code: Setting it all up</a></h2>
<p>Much of this initial code is taken from previous <a href="http://www.learningpython.com/tutorial-index/">pyGTK tutorials</a>, so if you are confused about any of this starting code, I suggest you take a look at the previous PyGTK tutorials where it is explained in depth.  Create this in a file called pyLan.py in the same directory where you saved your glade project.</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-comment">#!/usr/bin/env python

# PyLan - Python + PyGTK todo list
# Copyright (C) 2007 Mark Mruss &lt;selsine @gmail.com&gt;
# http://www.learningpython.com
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Library General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# If you find any bugs or have any suggestions email: selsine@gmail.com
# URL: http://www.learningpython.com

</span><span class="hl-identifier">__author__</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">Mark Mruss &lt;/selsine&gt;&lt;selsine @gmail.com&gt;</span><span class="hl-quotes">&quot;
</span><span class="hl-identifier">__version__</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">0.1</span><span class="hl-quotes">&quot;
</span><span class="hl-identifier">__date__</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">Date: 2007/02/17</span><span class="hl-quotes">&quot;
</span><span class="hl-identifier">__copyright__</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">Copyright (c) 2007 Mark Mruss</span><span class="hl-quotes">&quot;
</span><span class="hl-identifier">__license__</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">GPL</span><span class="hl-quotes">&quot;

</span><span class="hl-identifier">_</span><span class="hl-default"> = </span><span class="hl-reserved">lambda </span><span class="hl-identifier">x</span><span class="hl-default"> : </span><span class="hl-identifier">x
</span><span class="hl-reserved">try</span><span class="hl-default">:
 	</span><span class="hl-reserved">import </span><span class="hl-identifier">pygtk
  	pygtk</span><span class="hl-default">.</span><span class="hl-identifier">require</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">2.0</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
</span><span class="hl-reserved">except</span><span class="hl-default">:
  	</span><span class="hl-reserved">pass
try</span><span class="hl-default">:
	</span><span class="hl-reserved">import </span><span class="hl-identifier">sys
	</span><span class="hl-reserved">import </span><span class="hl-identifier">gtk
	</span><span class="hl-reserved">import </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">glade
	</span><span class="hl-reserved">import </span><span class="hl-identifier">gobject
	</span><span class="hl-reserved">import </span><span class="hl-identifier">os
	</span><span class="hl-reserved">import </span><span class="hl-identifier">locale
	</span><span class="hl-reserved">import </span><span class="hl-identifier">gettext
	</span><span class="hl-reserved">import </span><span class="hl-identifier">cPickle
	</span><span class="hl-reserved">import </span><span class="hl-identifier">helper
	</span><span class="hl-reserved">import </span><span class="hl-identifier">todo
</span><span class="hl-reserved">except ImportError</span><span class="hl-default">, </span><span class="hl-identifier">e</span><span class="hl-default">:
	</span><span class="hl-reserved">print </span><span class="hl-quotes">&quot;</span><span class="hl-string">Import error pyLan cannot start:</span><span class="hl-quotes">&quot;</span><span class="hl-default">, </span><span class="hl-identifier">e
	sys</span><span class="hl-default">.</span><span class="hl-identifier">exit</span><span class="hl-brackets">(</span><span class="hl-number">1</span><span class="hl-brackets">)

</span><span class="hl-identifier">FILE_EXT</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">pylan</span><span class="hl-quotes">&quot;
</span><span class="hl-identifier">APP_NAME</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;</span><span class="hl-string">pyLan</span><span class="hl-quotes">&quot;


</span><span class="hl-reserved">class </span><span class="hl-identifier">pyLan</span><span class="hl-brackets">(</span><span class="hl-identifier">object</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">A simple python based GTD todo list</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-reserved">def </span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:

		</span><span class="hl-comment">#Get the local path
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">local_path</span><span class="hl-default"> = </span><span class="hl-identifier">os</span><span class="hl-default">.</span><span class="hl-identifier">path</span><span class="hl-default">.</span><span class="hl-identifier">realpath</span><span class="hl-brackets">(</span><span class="hl-identifier">os</span><span class="hl-code">.</span><span class="hl-identifier">path</span><span class="hl-code">.</span><span class="hl-identifier">dirname</span><span class="hl-brackets">(</span><span class="hl-identifier">sys</span><span class="hl-code">.</span><span class="hl-identifier">argv</span><span class="hl-brackets">[</span><span class="hl-number">0</span><span class="hl-brackets">]))
		</span><span class="hl-comment">#Translation stuff
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">initialize_translation</span><span class="hl-brackets">()
		</span><span class="hl-comment">#Set the Glade file
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">gladefile</span><span class="hl-default"> = </span><span class="hl-identifier">os</span><span class="hl-default">.</span><span class="hl-identifier">path</span><span class="hl-default">.</span><span class="hl-identifier">join</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">local_path</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">pylan.glade</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-comment">#Get the Main Widget Tree
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default"> = </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">glade</span><span class="hl-default">.</span><span class="hl-identifier">XML</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">gladefile</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">mainWindow</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-comment">#Connect with yourself
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">signal_autoconnect</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)

		</span><span class="hl-comment">#init todo file
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todo_file</span><span class="hl-default"> = </span><span class="hl-reserved">None
		</span><span class="hl-comment">#Get the Main Window
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">main_window</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">mainWindow</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">set_window_title_from_file</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">todo_file</span><span class="hl-brackets">)

	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">&quot;
	************************************************************
	* Initialize
	************************************************************
	</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-reserved">def </span><span class="hl-identifier">initialize_translation</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function initializes the possible translations</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-comment"># Init the list of languages to support
		</span><span class="hl-identifier">langs</span><span class="hl-default"> = </span><span class="hl-brackets">[]
		</span><span class="hl-comment">#Check the default locale
		</span><span class="hl-identifier">lc</span><span class="hl-default">, </span><span class="hl-identifier">encoding</span><span class="hl-default"> = </span><span class="hl-identifier">locale</span><span class="hl-default">.</span><span class="hl-identifier">getdefaultlocale</span><span class="hl-brackets">()
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">lc</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-comment">#If we have a default, it's the first in the list
			</span><span class="hl-identifier">langs</span><span class="hl-default"> = </span><span class="hl-brackets">[</span><span class="hl-identifier">lc</span><span class="hl-brackets">]
		</span><span class="hl-comment"># Now lets get all of the supported languages on the system
		</span><span class="hl-identifier">language</span><span class="hl-default"> = </span><span class="hl-identifier">os</span><span class="hl-default">.</span><span class="hl-identifier">environ</span><span class="hl-default">.</span><span class="hl-identifier">get</span><span class="hl-brackets">(</span><span class="hl-quotes">'</span><span class="hl-string">LANGUAGE</span><span class="hl-quotes">'</span><span class="hl-code">, </span><span class="hl-reserved">None</span><span class="hl-brackets">)
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">language</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">language comes back something like en_CA:en_US:en_GB:en
			on linuxy systems, on Win32 it's nothing, so we need to
			split it up into a list</span><span class="hl-quotes">&quot;&quot;&quot;
			</span><span class="hl-identifier">langs</span><span class="hl-default"> += </span><span class="hl-identifier">language</span><span class="hl-default">.</span><span class="hl-identifier">split</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">:</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Now add on to the back of the list the translations that we
		know that we have, our defaults</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">langs</span><span class="hl-default"> += </span><span class="hl-brackets">[</span><span class="hl-quotes">&quot;</span><span class="hl-string">en_CA</span><span class="hl-quotes">&quot;</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">en_US</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">]

		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Now langs is a list of all of the languages that we are going
		to try to use.  First we check the default, then what the system
		told us, and finally the 'known' list</span><span class="hl-quotes">&quot;&quot;&quot;

		</span><span class="hl-identifier">gettext</span><span class="hl-default">.</span><span class="hl-identifier">bindtextdomain</span><span class="hl-brackets">(</span><span class="hl-identifier">APP_NAME</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">local_path</span><span class="hl-brackets">)
		</span><span class="hl-identifier">gettext</span><span class="hl-default">.</span><span class="hl-identifier">textdomain</span><span class="hl-brackets">(</span><span class="hl-identifier">APP_NAME</span><span class="hl-brackets">)
		</span><span class="hl-comment"># Get the language to use
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">lang</span><span class="hl-default"> = </span><span class="hl-identifier">gettext</span><span class="hl-default">.</span><span class="hl-identifier">translation</span><span class="hl-brackets">(</span><span class="hl-identifier">APP_NAME</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">local_path</span><span class="hl-code">
			, </span><span class="hl-identifier">languages</span><span class="hl-code">=</span><span class="hl-identifier">langs</span><span class="hl-code">, </span><span class="hl-identifier">fallback</span><span class="hl-code"> = </span><span class="hl-reserved">True</span><span class="hl-brackets">)
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Install the language, map _() (which we marked our
		strings to translate with) to self.lang.gettext() which will
		translate them.</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">gettext</span><span class="hl-default">.</span><span class="hl-identifier">install</span><span class="hl-brackets">(</span><span class="hl-identifier">APP_NAME</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">local_path</span><span class="hl-brackets">)

	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">&quot;
	********************************************************
	* Simple Helpers
	********************************************************
	</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-reserved">def </span><span class="hl-identifier">set_window_title_from_file</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">todo_file</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Set the windows title, take it from todo_file.
		@param todo_file - string - The todo file name that we will
		base the window title off of
		</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">todo_file</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">main_window</span><span class="hl-default">.</span><span class="hl-identifier">set_title</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">PyLan - %s</span><span class="hl-quotes">&quot;</span><span class="hl-code">
				% </span><span class="hl-brackets">(</span><span class="hl-identifier">os</span><span class="hl-code">.</span><span class="hl-identifier">path</span><span class="hl-code">.</span><span class="hl-identifier">basename</span><span class="hl-brackets">(</span><span class="hl-identifier">todo_file</span><span class="hl-brackets">)))
		</span><span class="hl-reserved">else</span><span class="hl-default">:
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">main_window</span><span class="hl-default">.</span><span class="hl-identifier">set_title</span><span class="hl-brackets">(</span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">PyLan - Untitled</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">))


	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">
	************************************************************
	* Signal Handlers
	************************************************************
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-reserved">def </span><span class="hl-identifier">on_mainWindow_destroy</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when the application is going to quit</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">main_quit</span><span class="hl-brackets">()

	</span><span class="hl-reserved">def </span><span class="hl-identifier">on_add_category</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when the Add Category button is clicked.
		Can also be generally used to add a category</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-reserved">pass

	def </span><span class="hl-identifier">on_remove_item</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">called then the remove category button is clicked.
		Can also be generally used to remove a category or
		item.</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-reserved">pass

	def </span><span class="hl-identifier">on_file_new</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">File | New - Start a new project file, blank out
		the current project and start from scratch</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-reserved">pass


	def </span><span class="hl-identifier">on_file_open</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Function called to open a todo file</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-reserved">pass

	def </span><span class="hl-identifier">on_file_save</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">File | Save function - Save the Todo file</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-reserved">pass

	def </span><span class="hl-identifier">on_file_save_as</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">File | Save As function - Save the todo file</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-reserved">pass

if </span><span class="hl-identifier">__name__</span><span class="hl-default"> == </span><span class="hl-quotes">&quot;</span><span class="hl-string">__main__</span><span class="hl-quotes">&quot;</span><span class="hl-default">:
	</span><span class="hl-identifier">plan</span><span class="hl-default"> = </span><span class="hl-identifier">pyLan</span><span class="hl-brackets">()
	</span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">main</span><span class="hl-brackets">()</span></pre></div></div>
<p>If you run the code you should be greeted with the following:</p>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_01/pylan_01_04.png" alt="Python GTD pyGTK" border="0" /></p>
<p>If you are familiar with my other tutorials none of this code should be very surprising to you. The only exception is perhaps the way that we connect our functions with the signal handlers:</p>
<div class="hl-surround" style="height:28px;"><div class="hl-main"><pre><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">signal_autoconnect</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span></pre></div></div>
<p>So instead of creating a dict with our functions and then passing it to the signal_autoconnect() function we simply pass our class to the function, and then any of our functions that match the signal handlers in the widget tree will be connected.  A very slick way to handle this if you ask me.</p>
<h2><a name="InitializingTheTree">The Code: Initializing the tree</a></h2>
<p>The next thing that we have to do is initialize our tree, i.e. set up the columns, create the model for the gtk.TreeView, and so on.  I struggled with how to set up the columns for a while since I knew that I wanted them to be dynamic and for the application to function properly no matter what order the columns were in.</p>
<p>As a result I decided to use a simple class and a list of those objects to define what columns are available and what is in each column.  I&#8217;m still not sure if this is the best way to handle it, but it meets most of my requirements and was relatively simple to implement.</p>
<p>The first thing that we need to do is create some &#8220;constants&#8221; near the top of our code right underneath out APP_NAME define:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Column IDs</span><span class="hl-quotes">&quot;&quot;&quot;
</span><span class="hl-identifier">COL_OBJECT</span><span class="hl-default"> = </span><span class="hl-number">0
</span><span class="hl-identifier">COL_OBJECT_TYPE</span><span class="hl-default"> = </span><span class="hl-number">1
</span><span class="hl-identifier">COL_TITLE</span><span class="hl-default"> = </span><span class="hl-number">2
</span><span class="hl-identifier">COL_DETAILS</span><span class="hl-default"> = </span><span class="hl-number">3
</span><span class="hl-identifier">COL_DUE</span><span class="hl-default"> = </span><span class="hl-number">4
</span><span class="hl-identifier">COL_PRIORITY</span><span class="hl-default"> = </span><span class="hl-number">5
</span><span class="hl-identifier">COL_COMPLETED</span><span class="hl-default"> = </span><span class="hl-number">6</span></pre></div></div>
<p>These are the IDs of the columns that we will have in our list.  For this tutorial most of these will remain unused, but as we progress more and more will be used.  The IDs are used to let us know what each column is.  So COL_OBJECT will be the column that holds the actual python object (as we did in the PyWine tutorial).  COL_OBJECT_TYPE will hold the objects type, and so on.</p>
<p>Then we need a simple class that will contain this information:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">class </span><span class="hl-identifier">todoColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">object</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This is a class that represents a column in the todo tree.
	It is simply a helper class that makes it easier to inialize the
	tree.</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-reserved">def </span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">ID</span><span class="hl-code">, </span><span class="hl-identifier">type</span><span class="hl-code">, </span><span class="hl-identifier">name</span><span class="hl-code">, </span><span class="hl-identifier">pos</span><span class="hl-code">, </span><span class="hl-identifier">visible</span><span class="hl-code">=</span><span class="hl-reserved">False</span><span class="hl-code">, </span><span class="hl-identifier">cellrenderer</span><span class="hl-code"> = </span><span class="hl-reserved">None</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">
		@param ID - int - The Columns ID
		@param type - int  - A gobject.TYPE_ for the gtk.TreeStore
		@param name - string - The name of the column
		@param pos - int - The index of the column.
		@param visible - boolean - Is the column visible or not?
		@param cellrenderer - gtk.CellRenderer - a constructor function
		for the column
		</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">ID</span><span class="hl-default"> = </span><span class="hl-identifier">ID
		self</span><span class="hl-default">.</span><span class="hl-identifier">type</span><span class="hl-default"> = </span><span class="hl-identifier">type
		self</span><span class="hl-default">.</span><span class="hl-identifier">name</span><span class="hl-default"> = </span><span class="hl-identifier">name
		self</span><span class="hl-default">.</span><span class="hl-identifier">pos</span><span class="hl-default"> = </span><span class="hl-identifier">pos
		self</span><span class="hl-default">.</span><span class="hl-identifier">visible</span><span class="hl-default"> = </span><span class="hl-identifier">visible
		self</span><span class="hl-default">.</span><span class="hl-identifier">cellrenderer</span><span class="hl-default"> = </span><span class="hl-identifier">cellrenderer
		self</span><span class="hl-default">.</span><span class="hl-identifier">colour</span><span class="hl-default"> = </span><span class="hl-number">0

	</span><span class="hl-reserved">def </span><span class="hl-identifier">__str__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-reserved">return </span><span class="hl-quotes">&quot;</span><span class="hl-string">&lt;todocolumn object: ID = %s type = %s name = %s pos = %d visible = %s cellrenderer = %s&gt;</span><span class="hl-quotes">&quot;</span><span class="hl-default"> % </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">type</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">name</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">pos</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">visible</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">cellrenderer</span><span class="hl-brackets">)</span></pre></div></div>
<p>This class should be created before the PyLan class.  Then at the beginning of the PyLan class we will create a hidden member at the beginnig of the __init__() function:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">The colum list, at one point this could be saved and loaded
		from a file.</span><span class="hl-quotes">&quot;&quot;&quot;
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__tree_columns</span><span class="hl-default"> = </span><span class="hl-brackets">[
			</span><span class="hl-identifier">todoColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">COL_OBJECT</span><span class="hl-code">, </span><span class="hl-identifier">gobject</span><span class="hl-code">.</span><span class="hl-identifier">TYPE_PYOBJECT</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">object</span><span class="hl-quotes">&quot;</span><span class="hl-code">, </span><span class="hl-number">0</span><span class="hl-brackets">)</span><span class="hl-code">
			, </span><span class="hl-identifier">todoColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">COL_OBJECT_TYPE</span><span class="hl-code">, </span><span class="hl-identifier">gobject</span><span class="hl-code">.</span><span class="hl-identifier">TYPE_INT</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">object_type</span><span class="hl-quotes">&quot;</span><span class="hl-code">, </span><span class="hl-number">1</span><span class="hl-brackets">)</span><span class="hl-code">
			, </span><span class="hl-identifier">todoColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">COL_TITLE</span><span class="hl-code">, </span><span class="hl-identifier">gobject</span><span class="hl-code">.</span><span class="hl-identifier">TYPE_STRING</span><span class="hl-code">, </span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Title</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-code">, </span><span class="hl-number">2</span><span class="hl-code">, </span><span class="hl-reserved">True</span><span class="hl-code">, </span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">CellRendererText</span><span class="hl-brackets">())</span><span class="hl-code">
			, </span><span class="hl-identifier">todoColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">COL_DETAILS</span><span class="hl-code">, </span><span class="hl-identifier">gobject</span><span class="hl-code">.</span><span class="hl-identifier">TYPE_STRING</span><span class="hl-code">, </span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Details</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-code">, </span><span class="hl-number">3</span><span class="hl-code">, </span><span class="hl-reserved">True</span><span class="hl-code">, </span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">CellRendererText</span><span class="hl-brackets">())</span><span class="hl-code">
			, </span><span class="hl-identifier">todoColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">COL_DUE</span><span class="hl-code">, </span><span class="hl-identifier">gobject</span><span class="hl-code">.</span><span class="hl-identifier">TYPE_STRING</span><span class="hl-code">, </span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Due</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-code">, </span><span class="hl-number">4</span><span class="hl-code">, </span><span class="hl-reserved">True</span><span class="hl-code">, </span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">CellRendererText</span><span class="hl-brackets">())</span><span class="hl-code">
			, </span><span class="hl-identifier">todoColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">COL_PRIORITY</span><span class="hl-code">, </span><span class="hl-identifier">gobject</span><span class="hl-code">.</span><span class="hl-identifier">TYPE_STRING</span><span class="hl-code">, </span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Priority</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-code">, </span><span class="hl-number">5</span><span class="hl-code">, </span><span class="hl-reserved">True</span><span class="hl-code">, </span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">CellRendererText</span><span class="hl-brackets">())</span><span class="hl-code">
			, </span><span class="hl-identifier">todoColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">COL_COMPLETED</span><span class="hl-code">, </span><span class="hl-identifier">gobject</span><span class="hl-code">.</span><span class="hl-identifier">TYPE_STRING</span><span class="hl-code">, </span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Completed</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-code">, </span><span class="hl-number">6</span><span class="hl-code">, </span><span class="hl-reserved">True</span><span class="hl-code">, </span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">CellRendererText</span><span class="hl-brackets">())
				]</span></pre></div></div>
<p>So what we are doing is creating a list that defines the columns that will be added to our Tree.  As you can see when we create each todoColumn instance we specify everything that is needed to create that column in the tree.</p>
<p>Next we&#8217;ll add a function that we will use to initialize our tree.  This function will be called from our __init__() function:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-comment">#Connect with yourself
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">signal_autoconnect</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)

</span><span class="hl-comment">#Initialize the todo Tree
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">initialize_todo_tree</span><span class="hl-brackets">()</span></pre></div></div>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">initialize_todo_tree</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when we want to initialize the tree.
		</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">tree_type_list</span><span class="hl-default"> = </span><span class="hl-brackets">[] </span><span class="hl-comment">#For creating the TreeStore
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__column_dict</span><span class="hl-default"> = {} </span><span class="hl-comment">#For easy access later on

		#Get the treeView from the widget Tree
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todoTreeView</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">todoTree</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-comment">#Make it so that the colours of each row can alternate
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todoTreeView</span><span class="hl-default">.</span><span class="hl-identifier">set_rules_hint</span><span class="hl-brackets">(</span><span class="hl-reserved">True</span><span class="hl-brackets">)

		</span><span class="hl-comment"># Loop through the columns and initialize the Tree
		</span><span class="hl-reserved">for </span><span class="hl-identifier">item_column </span><span class="hl-reserved">in </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__tree_columns</span><span class="hl-default">:
			</span><span class="hl-comment">#Add the column to the column dict
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__column_dict</span><span class="hl-brackets">[</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-brackets">]</span><span class="hl-default"> = </span><span class="hl-identifier">item_column
			</span><span class="hl-comment">#Save the type for gtk.TreeStore creation
			</span><span class="hl-identifier">tree_type_list</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">type</span><span class="hl-brackets">)
			</span><span class="hl-comment">#is it visible?
			</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">visible</span><span class="hl-brackets">)</span><span class="hl-default">:
				</span><span class="hl-comment">#Create the Column
				</span><span class="hl-identifier">column</span><span class="hl-default"> = </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">TreeViewColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">name</span><span class="hl-code">
					, </span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">cellrenderer</span><span class="hl-code">
					, </span><span class="hl-identifier">text</span><span class="hl-code">=</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">pos</span><span class="hl-brackets">)

				</span><span class="hl-identifier">column</span><span class="hl-default">.</span><span class="hl-identifier">set_resizable</span><span class="hl-brackets">(</span><span class="hl-reserved">True</span><span class="hl-brackets">)
				</span><span class="hl-identifier">column</span><span class="hl-default">.</span><span class="hl-identifier">set_sort_column_id</span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">pos</span><span class="hl-brackets">)
				</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todoTreeView</span><span class="hl-default">.</span><span class="hl-identifier">append_column</span><span class="hl-brackets">(</span><span class="hl-identifier">column</span><span class="hl-brackets">)

		</span><span class="hl-comment">#Create the gtk.TreeStore Model to use with the todoTree
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todoTree</span><span class="hl-default"> = </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">TreeStore</span><span class="hl-brackets">(</span><span class="hl-code">*</span><span class="hl-identifier">tree_type_list</span><span class="hl-brackets">)
		</span><span class="hl-comment">#Attache the model to the treeView
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todoTreeView</span><span class="hl-default">.</span><span class="hl-identifier">set_model</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">todoTree</span><span class="hl-brackets">)</span></pre></div></div>
<p>So what we do in this function is first get our <a href="http://www.pygtk.org/docs/pygtk/class-gtktreeview.html">gtk.TreeView</a> widget from our widget tree. Then we loop through the column list that we created, and add the column&#8217;s type to the tree_type_list, which will be used to create our <a href="http://www.pygtk.org/docs/pygtk/class-gtktreestore.html">gtk.TreeStore</a>.  If the todoColum is visible we need to create a <a href="http://www.pygtk.org/docs/pygtk/class-gtktreeviewcolumn.html">gtk.TreeViewColum</a> and then add it to the gtk.TreeView.</p>
<p>After we have looped through the column list we create the gtk.TreeStore (our model for the gtk.TreeView) based on all the types in our column list.  Then we set that model as the model for our gtk.TreeView.</p>
<p>This may seem a bit confusing and if you have any problems understanding take a look at the <a href="http://www.learningpython.com/2006/05/30/building-an-application-with-pygtk-and-glade/">Building an Application with PyGTK and Glade</a> tutorial where the relationship between gtk.TreeViews, gtk.TreeViewColumns, gtk.CellRenderers (which we define in our todoColumn), and gtk.TreeModels is described.  Basically the model (the gtk.TreeStore in this case) is the data.  The View (gtk.TreeView, gtk.TreeViewColumn, gtk.CellRenderer) is what is used to display the data.  </p>
<p>This means that you could have multiple views for the same data.  We&#8217;re not doing that in this application so far, but the idea is quite powerful.  We could, for example, use it to create a &#8220;simple&#8221; and &#8220;advanced&#8221; view for our data, or other &#8220;filtered&#8221; views.</p>
<p>Now if we run the code we get the following:</p>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_01/pylan_01_01.png" alt="Python GTD pyGTK" border="0" /></p>
<p>It&#8217;s the same as it was before, except now we have columns in our gtk.TreeView.</p>
<h2><a name="TodoItems">The Code: todo items</a></h2>
<p>Now that we have our tree defined, we need to create the objects that will store the data.  The data will be divided into two types (for now) a category and an task.</p>
<p>A Category is simply a container for other categories or items.  An task is an actual task that you need to do.</p>
<p>So a category could be &#8220;Work&#8221; and in that category you might add another category called &#8220;Project X&#8221; and in &#8220;Project X&#8221; you may add the task &#8220;Implement feature y.&#8221;  For this tutorial we will not be working with tasks, we will simply be working with categories.</p>
<p>We will create a new file in the same directory where we created our pyLan.py file.  The file will be named todo.py.  We will start off be defining the todoBase class which we will use as the base class for both the Category and Task classes:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-comment">#!/usr/bin/env python

</span><span class="hl-reserved">import </span><span class="hl-identifier">pyLan
</span><span class="hl-reserved">import </span><span class="hl-identifier">helper

CATEGORY</span><span class="hl-default"> = </span><span class="hl-number">0
</span><span class="hl-identifier">TASK</span><span class="hl-default">= </span><span class="hl-number">1

</span><span class="hl-reserved">class </span><span class="hl-identifier">todoBase</span><span class="hl-brackets">(</span><span class="hl-identifier">object</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This is the base class for the todoCategory and
	the todoTask.
	</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-comment">#Type property
	</span><span class="hl-reserved">def </span><span class="hl-identifier">__get_type</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-reserved">return </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_type
	type</span><span class="hl-default"> = </span><span class="hl-builtin">property</span><span class="hl-brackets">(</span><span class="hl-identifier">__get_type</span><span class="hl-brackets">)

	</span><span class="hl-reserved">def </span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">type</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">The only way to set the type is through the
		initialization</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_type</span><span class="hl-default"> = </span><span class="hl-identifier">type

	</span><span class="hl-reserved">def </span><span class="hl-identifier">get_column_list</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">todoColumnList</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function is used to get the display list
		for the todoTree. The todoCOlumnList controls the
		order that the list will be returned in. Used as the
		second param in the gtk.TreeStore.append function.
		@param todoColumnList - list - A list of todoColumn items.
		Their type member should use used to determine the order
		of the returned list.
		@returns list - A list for the todoTree.
		</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-reserved">pass

	def </span><span class="hl-identifier">add_to_tree</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">tree</span><span class="hl-code">, </span><span class="hl-identifier">parent</span><span class="hl-code">, </span><span class="hl-identifier">todoColumnList</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function is used to add an item to a
		gtk.TreeStore, usually when loading.  All
		children will be added as well
		@param tree - gtk.TreeStore - The tree store that
		we wil be adding to.
		@param parent gtk.TreeIter - The parent of this
		item.
		@param todoColumnList - list - A list of todoColumn items.
		Their type member should use used to determine the order
		of the returned list.
		</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">tree</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">parent</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">get_column_list</span><span class="hl-brackets">(</span><span class="hl-identifier">todoColumnList</span><span class="hl-brackets">))</span></pre></div></div>
<p>So the todoBase is simply a class with a type property (either CATEGORY, or TASK) that can only be set in the constructor and two functions get_column_list() and add_to_tree().</p>
<p>get_column_list() is used to create the second parameter for the <a href="http://www.pygtk.org/docs/pygtk/class-gtktreestore.html#method-gtktreestore--append">gtk.TreeStore.append()</a> function &#8220;a tuple or list containing ordered column values to be set in the new row.&#8221;</p>
<p>add_to_tree() is used to add the todo item to the actual tree.  For the category class that we are going to create this is used to ensure that any children (i.e. categories or tasks) will also be added to the tree at the same time.</p>
<p>The todoCategory class is defined as follows:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">class </span><span class="hl-identifier">todoCategory</span><span class="hl-brackets">(</span><span class="hl-identifier">todoBase</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This is a category in the todoTree.  It can have child categories
	or child tasks.</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-comment">#Name property
	</span><span class="hl-reserved">def </span><span class="hl-identifier">__get_name</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-reserved">return </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_name
	</span><span class="hl-reserved">def </span><span class="hl-identifier">__set_name</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">name</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_name</span><span class="hl-default"> = </span><span class="hl-identifier">name
	name</span><span class="hl-default"> = </span><span class="hl-builtin">property</span><span class="hl-brackets">(</span><span class="hl-identifier">__get_name</span><span class="hl-code">, </span><span class="hl-identifier">__set_name</span><span class="hl-brackets">)

	</span><span class="hl-reserved">def </span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">name</span><span class="hl-brackets">)</span><span class="hl-default">:

		</span><span class="hl-comment">#init variables
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_name</span><span class="hl-default"> = </span><span class="hl-quotes">&quot;&quot;
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">name</span><span class="hl-default"> = </span><span class="hl-identifier">name
		</span><span class="hl-comment">#children
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_children</span><span class="hl-default"> = </span><span class="hl-brackets">[]
		</span><span class="hl-comment">#init base
		</span><span class="hl-identifier">todoBase</span><span class="hl-default">.</span><span class="hl-identifier">__init__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">CATEGORY</span><span class="hl-brackets">)

	</span><span class="hl-reserved">def </span><span class="hl-identifier">__str__</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-reserved">return </span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">&lt;todocategory object: name = %s num_children = %d&gt;</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-default"> % </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">name</span><span class="hl-code">, </span><span class="hl-builtin">len</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">__m_children</span><span class="hl-brackets">))

	</span><span class="hl-reserved">def </span><span class="hl-identifier">add_child</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">todo_object</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Add a child to the category.
		@param todo_object - Either a todoCategory or a
		todoTask.  This will be a child of the category.
		</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_children</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">todo_object</span><span class="hl-brackets">)

	</span><span class="hl-reserved">def </span><span class="hl-identifier">remove_child</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">todo_object</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Removes a child from the category.
		@param todo_object - Either a todoCategory or a
		todoTask.  This will be a removed.
		</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-reserved">try</span><span class="hl-default">:
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_children</span><span class="hl-default">.</span><span class="hl-identifier">remove</span><span class="hl-brackets">(</span><span class="hl-identifier">todo_object</span><span class="hl-brackets">)
		</span><span class="hl-reserved">except ValueError</span><span class="hl-default">, </span><span class="hl-identifier">e</span><span class="hl-default">:
			</span><span class="hl-identifier">helper</span><span class="hl-default">.</span><span class="hl-identifier">show_error_dlg</span><span class="hl-brackets">(</span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Error removing child %s = %s</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-code"> % </span><span class="hl-brackets">(</span><span class="hl-identifier">todo_object</span><span class="hl-code">, </span><span class="hl-identifier">e</span><span class="hl-brackets">))


	</span><span class="hl-reserved">def </span><span class="hl-identifier">get_column_list</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">todoColumnList</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function is used to get the display list
		for the todoTree. The todoCOlumnList controls the
		order that the list will be returned in.
		@param todoColumnList - list - A list of todoColumn items.
		Their type member should use used to determine the order
		of the returned list.
		@returns list - A list for the todoTree.
		</span><span class="hl-quotes">&quot;&quot;&quot;

		</span><span class="hl-identifier">lst_return</span><span class="hl-default"> = </span><span class="hl-brackets">[]
		</span><span class="hl-comment"># Loop through the columns and create the return list
		</span><span class="hl-reserved">for </span><span class="hl-identifier">item_column </span><span class="hl-reserved">in </span><span class="hl-identifier">todoColumnList</span><span class="hl-default">:
			</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">COL_OBJECT</span><span class="hl-brackets">)</span><span class="hl-default">:
				</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)
			</span><span class="hl-identifier">elif </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">COL_OBJECT_TYPE</span><span class="hl-brackets">)</span><span class="hl-default">:
				</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">type</span><span class="hl-brackets">)
			</span><span class="hl-identifier">elif </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">pyLan</span><span class="hl-code">.</span><span class="hl-identifier">COL_TITLE</span><span class="hl-brackets">)</span><span class="hl-default">:
				</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">name</span><span class="hl-brackets">)
			</span><span class="hl-reserved">else</span><span class="hl-default">:
				</span><span class="hl-identifier">lst_return</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;&quot;</span><span class="hl-brackets">)
		</span><span class="hl-reserved">return </span><span class="hl-identifier">lst_return

	</span><span class="hl-reserved">def </span><span class="hl-identifier">add_to_tree</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">tree</span><span class="hl-code">, </span><span class="hl-identifier">parent</span><span class="hl-code">, </span><span class="hl-identifier">todoColumnList</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function is used to add an item to a
		gtk.TreeStore, usually when loading.  All
		children will be added as well
		@param tree - gtk.TreeStore - The tree store that
		we will be adding to.
		@param parent gtk.TreeIter - The parent of this
		item.
		@param todoColumnList - list - A list of todoColumn items.
		Their type member should use used to determine the order
		of the returned list.
		</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">insert_iter</span><span class="hl-default"> = </span><span class="hl-identifier">tree</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">parent</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">get_column_list</span><span class="hl-brackets">(</span><span class="hl-identifier">todoColumnList</span><span class="hl-brackets">))
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">insert_iter</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-reserved">for </span><span class="hl-identifier">child </span><span class="hl-reserved">in </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__m_children</span><span class="hl-default">:
				</span><span class="hl-identifier">child</span><span class="hl-default">.</span><span class="hl-identifier">add_to_tree</span><span class="hl-brackets">(</span><span class="hl-identifier">tree</span><span class="hl-code">, </span><span class="hl-identifier">insert_iter</span><span class="hl-code">, </span><span class="hl-identifier">todoColumnList</span><span class="hl-brackets">)
		</span><span class="hl-reserved">else</span><span class="hl-default">:
			</span><span class="hl-identifier">helper</span><span class="hl-default">.</span><span class="hl-identifier">show_error_dlg</span><span class="hl-brackets">(</span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Error loading category: %s</span><span class="hl-quotes">&quot;</span><span class="hl-code"> % </span><span class="hl-identifier">self</span><span class="hl-brackets">))</span></pre></div></div>
<p>You can see that it sets its type by initializing the base class and passing it the CATEGORY constant.  It also has some additional members, the name property and the private member __m_children.  Name is the name of the category and __m_children is a list of todoBase objects that are the children of this category.</p>
<p>It implements two functions add_child() and remove_child() that are pretty self explanatory, and it overrides the get_column_list() and add_to_tree() functions from the todoBase.</p>
<p>You can see that in the get_column_list() function that the todoCategory only specifies three columns, for the rest is passes empty strings.  It should be pretty obvious what the function is doing.</p>
<p>add_to_tree() is also overridden.  What it does is add itself to the tree, if that succeeds it then loops through all of its children and then adds them to the tree as well.  If that fails it calls the show_error_dlg() function from the helper module that has not been explained yet.  All you need to know is that show_error_dlg() pops up a simple error dialog.</p>
<h2><a name="AddingCategories">The Code: Adding Categories</a></h2>
<p>Now that we have our category classes defined we need to work on adding them to the actual tree.  To do that we will want to use our categoryDialog.  We will show that to the user and let them set the name of the category.  We will create a function called show_category_dialog() to do this for us:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">show_category_dialog</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">name</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function shows the category dialog.
	@param name - string - The name to display in
	category dialog by default.
	@returns - If OK is pressed the name typed on the
	dialog. If Cancel is pressed None is returned.
	</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-comment">#init to cancel
	</span><span class="hl-identifier">name_return</span><span class="hl-default"> = </span><span class="hl-reserved">None

	</span><span class="hl-comment">#load the dialog from the glade file
	</span><span class="hl-identifier">wTree</span><span class="hl-default"> = </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">glade</span><span class="hl-default">.</span><span class="hl-identifier">XML</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">gladefile</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">categoryDialog</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-comment">#Get the actual dialog widget
	</span><span class="hl-identifier">dlg</span><span class="hl-default"> = </span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">categoryDialog</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-comment">#Get all of the Entry Widgets and set their text
	</span><span class="hl-identifier">enName</span><span class="hl-default"> = </span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">enName</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-identifier">enName</span><span class="hl-default">.</span><span class="hl-identifier">set_text</span><span class="hl-brackets">(</span><span class="hl-identifier">name</span><span class="hl-brackets">)

	</span><span class="hl-comment">#run the dialog and store the response
	</span><span class="hl-identifier">result</span><span class="hl-default"> = </span><span class="hl-identifier">dlg</span><span class="hl-default">.</span><span class="hl-identifier">run</span><span class="hl-brackets">()
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">result</span><span class="hl-code">==</span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">RESPONSE_OK</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-comment">#get the value of the entry fields
		</span><span class="hl-identifier">name_return</span><span class="hl-default"> = </span><span class="hl-identifier">enName</span><span class="hl-default">.</span><span class="hl-identifier">get_text</span><span class="hl-brackets">()
	</span><span class="hl-comment">#we are done with the dialog, destroy it
	</span><span class="hl-identifier">dlg</span><span class="hl-default">.</span><span class="hl-identifier">destroy</span><span class="hl-brackets">()

	</span><span class="hl-comment">#return the result
	</span><span class="hl-reserved">return </span><span class="hl-identifier">name_return</span></pre></div></div>
<p>This function simply shows the dialog and returns the name that the person typed or None if they cancelled.</p>
<p>We will call this function from the on_add_category() function in the PyLan class.  The on_add_category() function is called when you want to add a category to the Tree.  It is called from either the addButton or from a menu item on the menu that the addButton can display.  Here is the function:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">on_add_category</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when the Add Category button is clicked.
	Can also be generally used to add a category</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-identifier">name</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">show_category_dialog</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;&quot;</span><span class="hl-brackets">)
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">name</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-comment"># Get the selection category iter
		</span><span class="hl-identifier">model</span><span class="hl-default">, </span><span class="hl-identifier">selection_iter</span><span class="hl-default">, </span><span class="hl-identifier">todo_cat</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">get_category_selected</span><span class="hl-brackets">()
		</span><span class="hl-comment">#Create the new Category
		</span><span class="hl-identifier">category</span><span class="hl-default"> = </span><span class="hl-identifier">todo</span><span class="hl-default">.</span><span class="hl-identifier">todoCategory</span><span class="hl-brackets">(</span><span class="hl-identifier">name</span><span class="hl-brackets">)
		</span><span class="hl-comment">#Append to the tree
		</span><span class="hl-identifier">category</span><span class="hl-default">.</span><span class="hl-identifier">add_to_tree</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">todoTree</span><span class="hl-code">
			, </span><span class="hl-identifier">selection_iter</span><span class="hl-code">
			, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">__tree_columns</span><span class="hl-brackets">)
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">todo_cat</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">something was selected so add the new category
			to the old category</span><span class="hl-quotes">&quot;&quot;&quot;
			</span><span class="hl-identifier">todo_cat</span><span class="hl-default">.</span><span class="hl-identifier">add_child</span><span class="hl-brackets">(</span><span class="hl-identifier">category</span><span class="hl-brackets">)
		</span><span class="hl-reserved">else</span><span class="hl-default">:
			</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Nothing selected so add to the current project
			data</span><span class="hl-quotes">&quot;&quot;&quot;
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__categories</span><span class="hl-default">.</span><span class="hl-identifier">append</span><span class="hl-brackets">(</span><span class="hl-identifier">category</span><span class="hl-brackets">)</span></pre></div></div>
<p>The function is relatively simple as it relies on many helper functions.  The first thing that it does is show the category dialog.  If a valid name is returned then we continue adding the category.</p>
<p>We call the get_category_selected() function which is a helper function that is used to get the currently selected category, the <a href="http://www.pygtk.org/docs/pygtk/class-gtktreeiter.html">gtk.TreeIter</a> representing the selection, and the model associated with our gtk.TreeView.  The function wraps the <a href="http://www.pygtk.org/docs/pygtk/class-gtktreeview.html#method-gtktreeview--get-selection">gtk.TreeView.get_selection()</a> and the <a href="http://www.pygtk.org/docs/pygtk/class-gtktreeselection.html#method-gtktreeselection--get-selected">gtk.TreeSelection.get_selected()</a> functions ensuring that todoCategory is selected.  This means that if a todoTask is selected then its parent category will be returned.</p>
<p>We then create the category based on the name and add it to the tree.  If there is a parent category (returned by get_category_selected()) then we add it to its children, otherwise we add it to a new private member self.__categories.  self.__categories is basically a list of all of the top level todoCategories, it is our representation of the data displayed in the tree.  It is created in the __init__ function:</p>
<div class="hl-surround" ><div class="hl-main"><pre>#init todo file
self.todo_file = None
#Get the Main Window
self.main_window = self.wTree.get_widget(&quot;mainWindow&quot;)
self.set_window_title_from_file(self.todo_file)
#No categories
self.__categories = []</pre></div></div>
<p>The get_category_selected() looks like this:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">get_category_selected</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function is a wrapper for the
	gtk.TreeView.get_selection() function and the
	gtk.TreeSelection.get_selected() function. It returns
	the same as gtk.TreeSelection.get_selected(), but ensures
	that it is a category that is selected. So if a todoTask
	is selected then it's parent category will be returned.
	@returns A 3-tuple containing a reference to the
	gtk.TreeModel and a gtk.TreeIter pointing to the
	currently selected node. Just like
	gtk.TreeSelection.get_selected but with the todoObject
	being returned as well.
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-comment">#First get the object column
	</span><span class="hl-identifier">todo_ob</span><span class="hl-default"> = </span><span class="hl-reserved">None
	</span><span class="hl-identifier">tcolumn</span><span class="hl-default">, </span><span class="hl-identifier">pos</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">find_todoColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">COL_OBJECT</span><span class="hl-brackets">)
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-reserved">not </span><span class="hl-identifier">tcolumn</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-reserved">return None</span><span class="hl-default">,</span><span class="hl-reserved">None

	</span><span class="hl-comment">#Get the current selection in the gtk.TreeView
	</span><span class="hl-identifier">selection</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todoTreeView</span><span class="hl-default">.</span><span class="hl-identifier">get_selection</span><span class="hl-brackets">()
	</span><span class="hl-comment"># Get the selection iter
	</span><span class="hl-identifier">model</span><span class="hl-default">, </span><span class="hl-identifier">selection_iter</span><span class="hl-default"> = </span><span class="hl-identifier">selection</span><span class="hl-default">.</span><span class="hl-identifier">get_selected</span><span class="hl-brackets">()
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">selection_iter</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-comment">#Something is selected so get the object
		</span><span class="hl-identifier">todo_ob</span><span class="hl-default"> = </span><span class="hl-identifier">model</span><span class="hl-default">.</span><span class="hl-identifier">get_value</span><span class="hl-brackets">(</span><span class="hl-identifier">selection_iter</span><span class="hl-code">, </span><span class="hl-identifier">tcolumn</span><span class="hl-code">.</span><span class="hl-identifier">pos</span><span class="hl-brackets">)
		</span><span class="hl-identifier">if </span><span class="hl-brackets">((</span><span class="hl-identifier">todo_ob</span><span class="hl-brackets">) </span><span class="hl-identifier">and </span><span class="hl-brackets">(</span><span class="hl-identifier">todo_ob</span><span class="hl-code">.</span><span class="hl-identifier">type</span><span class="hl-code"> != </span><span class="hl-identifier">todo</span><span class="hl-code">.</span><span class="hl-identifier">CATEGORY</span><span class="hl-brackets">))</span><span class="hl-default">:
			</span><span class="hl-comment">#Alright we need the parent, this is not a category
			</span><span class="hl-identifier">selection_iter</span><span class="hl-default"> = </span><span class="hl-identifier">model</span><span class="hl-default">.</span><span class="hl-identifier">iter_parent</span><span class="hl-brackets">(</span><span class="hl-identifier">selection_iter</span><span class="hl-brackets">)
			</span><span class="hl-identifier">todo_ob</span><span class="hl-default"> = </span><span class="hl-identifier">model</span><span class="hl-default">.</span><span class="hl-identifier">get_value</span><span class="hl-brackets">(</span><span class="hl-identifier">selection_iter</span><span class="hl-code">, </span><span class="hl-identifier">tcolumn</span><span class="hl-code">.</span><span class="hl-identifier">pos</span><span class="hl-brackets">)
	</span><span class="hl-reserved">return </span><span class="hl-identifier">model</span><span class="hl-default">, </span><span class="hl-identifier">selection_iter</span><span class="hl-default">, </span><span class="hl-identifier">todo_ob</span></pre></div></div>
<p>It relies on another helper function find_todoColumn which basically loops through the self.__tree_columns list looking for the todoColumn with the matching ID.  If is found it is returned, along with the position in the list that it was returned at.  This is partly done because I am unsure whether the order in the list will matter after initialization or whether the objects in the list should keep track of their position.  If it is the objects, then they could be moved into a dictionary later on (you&#8217;ll notice that one is already created) for faster access.</p>
<p>We use find_todoColum() so that we can get the column representing the Object. (We use the Object instead of the type since we may need to get the actual object later.  If we just wanted the type we could have used COL_OBJECT_TYPE)</p>
<p>Then what we do is we get the current gtk.TreeSelection and then get what (if anything) is actually selected within it.  If something is selected (selection_iter is not None) then we check to see if the selected item is a category or not.  If it is not a category we get the parent of the selecton iter, which we know is a category since tasks cannot have children.</p>
<p>Then we simply return all of the values: the current model, the gtk.TreeIter representing the selection category (may be None) and the todoCategory object (may also be none).</p>
<p>find_todoColumn() should be self explanatory:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">find_todoColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">column_ID</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function is used to search the __tree_columns
	list to find a specific todoColumn.
	@param column_ID - The ID of the column that we
	are looking for.
	@returns todoColumn, int - The column found and
	the position in the list. If todoColumn is None
	then the column was not found.
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">count</span><span class="hl-default"> = </span><span class="hl-number">0
	</span><span class="hl-identifier">columnReturn</span><span class="hl-default"> = </span><span class="hl-reserved">None
	for </span><span class="hl-identifier">item_column </span><span class="hl-reserved">in </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__tree_columns</span><span class="hl-default">:
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">item_column</span><span class="hl-code">.</span><span class="hl-identifier">ID</span><span class="hl-code"> == </span><span class="hl-identifier">column_ID</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-identifier">columnReturn</span><span class="hl-default"> = </span><span class="hl-identifier">item_column
			</span><span class="hl-reserved">break
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">columnReturn</span><span class="hl-code"> == </span><span class="hl-reserved">None</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-comment">#Something is really wrong we did not match
		</span><span class="hl-identifier">helper</span><span class="hl-default">.</span><span class="hl-identifier">show_error_dlg</span><span class="hl-brackets">(</span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Error column data appears corrupted</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">))
	</span><span class="hl-comment">#Return the results
	</span><span class="hl-reserved">return </span><span class="hl-identifier">columnReturn</span><span class="hl-default">, </span><span class="hl-identifier">count</span></pre></div></div>
<p>After all that code, we are finally able to add things to our tree!</p>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_01/pylan_01_05.png" alt="Python GTD pyGTK" border="0" /></p>
<p>It may seem complicated or like a lot of work, but in reality it&#8217;s simply a large process broken up into smaller reusable bits that make more sense when looked at as a whole.</p>
<h2><a name="RemovingCategories">The Code: Removing Categories</a></h2>
<p>Now that we can add categories let&#8217;s add some code so that we can remove them.  We will do this in the on_remove_item() function which is triggered by the btnRemoveCategory button&#8217;s clicked signal:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">on_remove_item</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">called then the remove category button is clicked.
	Can also be generally used to remove a category or
	item.</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-comment">#Get the column of the object
	</span><span class="hl-identifier">tcolumn</span><span class="hl-default">, </span><span class="hl-identifier">pos</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">find_todoColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">COL_OBJECT</span><span class="hl-brackets">)
	</span><span class="hl-comment">#Get the current selection in the gtk.TreeView
	</span><span class="hl-identifier">selection</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todoTreeView</span><span class="hl-default">.</span><span class="hl-identifier">get_selection</span><span class="hl-brackets">()
	</span><span class="hl-comment"># Get the selection iter
	</span><span class="hl-identifier">model</span><span class="hl-default">, </span><span class="hl-identifier">selection_iter</span><span class="hl-default"> = </span><span class="hl-identifier">selection</span><span class="hl-default">.</span><span class="hl-identifier">get_selected</span><span class="hl-brackets">()
	</span><span class="hl-identifier">if </span><span class="hl-brackets">((</span><span class="hl-identifier">selection_iter</span><span class="hl-brackets">) </span><span class="hl-identifier">and </span><span class="hl-brackets">(</span><span class="hl-identifier">tcolumn</span><span class="hl-brackets">))</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">All right we have something to remove and we have the
		column that represents the todo object, first
		let's get the object from the selection_iter</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">todo_ob</span><span class="hl-default"> = </span><span class="hl-identifier">model</span><span class="hl-default">.</span><span class="hl-identifier">get_value</span><span class="hl-brackets">(</span><span class="hl-identifier">selection_iter</span><span class="hl-code">, </span><span class="hl-identifier">tcolumn</span><span class="hl-code">.</span><span class="hl-identifier">pos</span><span class="hl-brackets">)
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">todo_ob</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Allright everything worked, time to remove. Does
			this item have a parent</span><span class="hl-quotes">&quot;&quot;&quot;
			</span><span class="hl-identifier">todo_parent</span><span class="hl-default">, </span><span class="hl-identifier">iter</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">get_parent_category</span><span class="hl-brackets">(
				</span><span class="hl-identifier">selection_iter</span><span class="hl-code">, </span><span class="hl-identifier">tcolumn</span><span class="hl-code">.</span><span class="hl-identifier">pos</span><span class="hl-brackets">)
			</span><span class="hl-comment">#Remove from the tree
			</span><span class="hl-identifier">model</span><span class="hl-default">.</span><span class="hl-identifier">remove</span><span class="hl-brackets">(</span><span class="hl-identifier">selection_iter</span><span class="hl-brackets">)
			</span><span class="hl-comment">#if there is a parent, remove from the parent
			</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">todo_parent</span><span class="hl-brackets">)</span><span class="hl-default">:
				</span><span class="hl-identifier">todo_parent</span><span class="hl-default">.</span><span class="hl-identifier">remove_child</span><span class="hl-brackets">(</span><span class="hl-identifier">todo_ob</span><span class="hl-brackets">)
			</span><span class="hl-reserved">else</span><span class="hl-default">:
				</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">There is no parent so remove from
				base list</span><span class="hl-quotes">&quot;&quot;&quot;
				</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__categories</span><span class="hl-default">.</span><span class="hl-identifier">remove</span><span class="hl-brackets">(</span><span class="hl-identifier">todo_ob</span><span class="hl-brackets">)</span></pre></div></div>
<p>If you understood how we added the columns, how we remove them should be pretty straight forward.  First we get the object todoColumn and the gtk.TreeSelection.  Then if they are both valid we get the object that is selected.  If nothing is selected then we can return because there is nothing to remove.</p>
<p>If something is selected then we call the helper get_parent_category() which simply gets us the item&#8217;s parent category.  We then remove the selected item from the tree, but since the object is still stored within our data tree (self.__categories) we need to remove it from there.  </p>
<p>If the item has a parent (todo_parent) we remove the item from the parent by calling remove_child().  If the item did not have a parent it means that it is a top level category and needs to be removed directly from self.__categories.</p>
<p>Here is get_parent_category():</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">get_parent_category</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">selection_iter</span><span class="hl-code">, </span><span class="hl-identifier">object_pos</span><span class="hl-code"> = </span><span class="hl-reserved">None</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Get the parent category of the selection_item
	@param selection_iter - gtk.TreeIter - A iter whose
	parent you want to get.
	@param object_pos - number - The index of the object
	column.  If None this will be calculated.
	@returns - todoCategory, gtk.TreeIter - The parent category of the
	iter on success, or None on failure. The parent gtk.TreeIter
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">object_pos</span><span class="hl-code"> == </span><span class="hl-reserved">None</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">tcolumn</span><span class="hl-default">, </span><span class="hl-identifier">pos</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">find_todoColumn</span><span class="hl-brackets">(</span><span class="hl-identifier">COL_OBJECT</span><span class="hl-brackets">)
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">tcolumn</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-identifier">object_pos</span><span class="hl-default"> = </span><span class="hl-identifier">tcolumn</span><span class="hl-default">.</span><span class="hl-identifier">pos
		</span><span class="hl-reserved">else</span><span class="hl-default">:
			</span><span class="hl-comment">#Column Data Error
			</span><span class="hl-reserved">return None</span><span class="hl-default">, </span><span class="hl-reserved">None
			
	</span><span class="hl-identifier">todo_parent</span><span class="hl-default"> = </span><span class="hl-reserved">None
	</span><span class="hl-identifier">selection_parent</span><span class="hl-default"> = </span><span class="hl-reserved">None
	</span><span class="hl-comment">#Get the Model
	</span><span class="hl-identifier">model</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todoTreeView</span><span class="hl-default">.</span><span class="hl-identifier">get_model</span><span class="hl-brackets">()
	</span><span class="hl-comment">#Get the current selection in the gtk.TreeView
	</span><span class="hl-identifier">selection</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todoTreeView</span><span class="hl-default">.</span><span class="hl-identifier">get_selection</span><span class="hl-brackets">()
	</span><span class="hl-identifier">if </span><span class="hl-brackets">((</span><span class="hl-identifier">model</span><span class="hl-brackets">) </span><span class="hl-identifier">and </span><span class="hl-brackets">(</span><span class="hl-identifier">selection</span><span class="hl-brackets">))</span><span class="hl-default">:
		</span><span class="hl-identifier">selection_parent</span><span class="hl-default"> = </span><span class="hl-identifier">model</span><span class="hl-default">.</span><span class="hl-identifier">iter_parent</span><span class="hl-brackets">(</span><span class="hl-identifier">selection_iter</span><span class="hl-brackets">)
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">selection_parent</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-identifier">todo_parent</span><span class="hl-default"> = </span><span class="hl-identifier">model</span><span class="hl-default">.</span><span class="hl-identifier">get_value</span><span class="hl-brackets">(</span><span class="hl-identifier">selection_parent</span><span class="hl-code">, </span><span class="hl-identifier">object_pos</span><span class="hl-brackets">)

	</span><span class="hl-reserved">return </span><span class="hl-identifier">todo_parent</span><span class="hl-default">, </span><span class="hl-identifier">selection_parent</span></pre></div></div>
<h2><a name="SavingAndLoadingWithcPickle">The Code: Saving and Loading with cPickle</a></h2>
<p>Now that we can add and remove categories, the next thing that we want to do is be able to save and load our data to and from files.  This code is very similar to the method used in my <a href="http://www.learningpython.com/2006/09/02/extending-our-pygtk-application/">Extending our PyGTK Application</a> so I will gloss over the repeated code and only explain the new stuff.</p>
<p>You probably remember the helper module mention above and used a little bit in some of the previously mentioned code.  It&#8217;s simply a helper module that I have started to use so that I don&#8217;t always have to recode the same functions.  The file&#8217;s name is &#8220;helper.py&#8221; and it looks like this:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-comment">#!/usr/bin/env python

</span><span class="hl-reserved">try</span><span class="hl-default">:
 	</span><span class="hl-reserved">import </span><span class="hl-identifier">pygtk
  	pygtk</span><span class="hl-default">.</span><span class="hl-identifier">require</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">2.0</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
</span><span class="hl-reserved">except</span><span class="hl-default">:
  	</span><span class="hl-reserved">pass
try</span><span class="hl-default">:
	</span><span class="hl-reserved">import </span><span class="hl-identifier">os
	</span><span class="hl-reserved">import </span><span class="hl-identifier">gtk
</span><span class="hl-reserved">except ImportError</span><span class="hl-default">, </span><span class="hl-identifier">e</span><span class="hl-default">:
	</span><span class="hl-reserved">print </span><span class="hl-quotes">&quot;</span><span class="hl-string">Import error in helper:</span><span class="hl-quotes">&quot;</span><span class="hl-default">, </span><span class="hl-identifier">e
	sys</span><span class="hl-default">.</span><span class="hl-identifier">exit</span><span class="hl-brackets">(</span><span class="hl-number">1</span><span class="hl-brackets">)

</span><span class="hl-reserved">def </span><span class="hl-identifier">file_browse</span><span class="hl-brackets">(</span><span class="hl-identifier">dialog_action</span><span class="hl-code">, </span><span class="hl-identifier">filters</span><span class="hl-code">, </span><span class="hl-identifier">file_extension</span><span class="hl-code">=</span><span class="hl-quotes">&quot;&quot;</span><span class="hl-code">, </span><span class="hl-identifier">file_name</span><span class="hl-code">=</span><span class="hl-quotes">&quot;&quot;</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This function is used to browse for a file.
	It can be either a save or open dialog depending on
	what dialog_action is.
	The path to the file will be returned if the user
	selects one, however a blank string will be returned
	if they cancel or do not select one.
	dialog_action - The open or save mode for the dialog either
	gtk.FILE_CHOOSER_ACTION_OPEN, gtk.FILE_CHOOSER_ACTION_SAVE
	@param filters - list - list of  gtk.FileFilter() objects
	that will be added to the dialog.
	@param file_extension - string - The file extension that will be
	added to the filename when saving
	@param file_name - Default name when doing a save
	@returns - File Name, or None on cancel.
	</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">dialog_action</span><span class="hl-code">==</span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">FILE_CHOOSER_ACTION_OPEN</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">dialog_buttons</span><span class="hl-default"> = </span><span class="hl-brackets">(</span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">STOCK_CANCEL</span><span class="hl-code">
			, </span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">RESPONSE_CANCEL</span><span class="hl-code">
			, </span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">STOCK_OPEN</span><span class="hl-code">
			, </span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">RESPONSE_OK</span><span class="hl-brackets">)
		</span><span class="hl-identifier">dlg_title</span><span class="hl-default"> = </span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Open File</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-reserved">else</span><span class="hl-default">:
		</span><span class="hl-identifier">dialog_buttons</span><span class="hl-default"> = </span><span class="hl-brackets">(</span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">STOCK_CANCEL</span><span class="hl-code">
			, </span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">RESPONSE_CANCEL</span><span class="hl-code">
			, </span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">STOCK_SAVE</span><span class="hl-code">
			, </span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">RESPONSE_OK</span><span class="hl-brackets">)
		</span><span class="hl-identifier">dlg_title</span><span class="hl-default"> = </span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Save File</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)

	</span><span class="hl-identifier">file_dialog</span><span class="hl-default"> = </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">FileChooserDialog</span><span class="hl-brackets">(</span><span class="hl-identifier">title</span><span class="hl-code">=</span><span class="hl-identifier">dlg_title</span><span class="hl-code">
		, </span><span class="hl-identifier">action</span><span class="hl-code">=</span><span class="hl-identifier">dialog_action</span><span class="hl-code">
		, </span><span class="hl-identifier">buttons</span><span class="hl-code">=</span><span class="hl-identifier">dialog_buttons</span><span class="hl-brackets">)
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">set the filename if we are saving</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">dialog_action</span><span class="hl-code">==</span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">FILE_CHOOSER_ACTION_SAVE</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">file_dialog</span><span class="hl-default">.</span><span class="hl-identifier">set_current_name</span><span class="hl-brackets">(</span><span class="hl-identifier">file_name</span><span class="hl-brackets">)
	</span><span class="hl-comment">#Add filters
	</span><span class="hl-reserved">for </span><span class="hl-identifier">filter </span><span class="hl-reserved">in </span><span class="hl-identifier">filters</span><span class="hl-default">:
		</span><span class="hl-identifier">file_dialog</span><span class="hl-default">.</span><span class="hl-identifier">add_filter</span><span class="hl-brackets">(</span><span class="hl-identifier">filter</span><span class="hl-brackets">)
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">dialog_action</span><span class="hl-code">==</span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">FILE_CHOOSER_ACTION_OPEN</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Create and add the 'all files' filter</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-identifier">filter</span><span class="hl-default"> = </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">FileFilter</span><span class="hl-brackets">()
		</span><span class="hl-identifier">filter</span><span class="hl-default">.</span><span class="hl-identifier">set_name</span><span class="hl-brackets">(</span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">All files</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">))
		</span><span class="hl-identifier">filter</span><span class="hl-default">.</span><span class="hl-identifier">add_pattern</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">*</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-identifier">file_dialog</span><span class="hl-default">.</span><span class="hl-identifier">add_filter</span><span class="hl-brackets">(</span><span class="hl-identifier">filter</span><span class="hl-brackets">)

	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Init the return value</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">result</span><span class="hl-default"> = </span><span class="hl-reserved">None
	if </span><span class="hl-identifier">file_dialog</span><span class="hl-default">.</span><span class="hl-identifier">run</span><span class="hl-brackets">()</span><span class="hl-default"> == </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">RESPONSE_OK</span><span class="hl-default">:
		</span><span class="hl-identifier">result</span><span class="hl-default"> = </span><span class="hl-identifier">file_dialog</span><span class="hl-default">.</span><span class="hl-identifier">get_filename</span><span class="hl-brackets">()
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">dialog_action</span><span class="hl-code">==</span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">FILE_CHOOSER_ACTION_SAVE</span><span class="hl-brackets">)</span><span class="hl-default">:
			</span><span class="hl-identifier">result</span><span class="hl-default">, </span><span class="hl-identifier">extension</span><span class="hl-default"> = </span><span class="hl-identifier">os</span><span class="hl-default">.</span><span class="hl-identifier">path</span><span class="hl-default">.</span><span class="hl-identifier">splitext</span><span class="hl-brackets">(</span><span class="hl-identifier">result</span><span class="hl-brackets">)
			</span><span class="hl-identifier">result</span><span class="hl-default"> = </span><span class="hl-identifier">result</span><span class="hl-default"> + </span><span class="hl-quotes">&quot;</span><span class="hl-string">.</span><span class="hl-quotes">&quot;</span><span class="hl-default"> + </span><span class="hl-identifier">file_extension
	file_dialog</span><span class="hl-default">.</span><span class="hl-identifier">destroy</span><span class="hl-brackets">()

	</span><span class="hl-reserved">return </span><span class="hl-identifier">result

</span><span class="hl-reserved">def </span><span class="hl-identifier">show_error_dlg</span><span class="hl-brackets">(</span><span class="hl-identifier">error_string</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">This Function is used to show an error dialog when
	an error occurs.
	error_string - The error string that will be displayed
	on the dialog.
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">error_dlg</span><span class="hl-default"> = </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">MessageDialog</span><span class="hl-brackets">(</span><span class="hl-identifier">type</span><span class="hl-code">=</span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">MESSAGE_ERROR</span><span class="hl-code">
				, </span><span class="hl-identifier">message_format</span><span class="hl-code">=</span><span class="hl-identifier">error_string</span><span class="hl-code">
				, </span><span class="hl-identifier">buttons</span><span class="hl-code">=</span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">BUTTONS_OK</span><span class="hl-brackets">)
	</span><span class="hl-identifier">error_dlg</span><span class="hl-default">.</span><span class="hl-identifier">run</span><span class="hl-brackets">()
	</span><span class="hl-identifier">error_dlg</span><span class="hl-default">.</span><span class="hl-identifier">destroy</span><span class="hl-brackets">()</span></pre></div></div>
<p>These are both old functions (changed slightly) so I won&#8217;t go over them.</p>
<p>The same is true for the File menu signal handers:</p>
<div class="hl-surround" style="height:280px;"><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">on_file_new</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">File | New - Start a new project file, blank out
	the currnet project and start from scratch</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__categories</span><span class="hl-default"> = </span><span class="hl-brackets">[]
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todo_file</span><span class="hl-default"> = </span><span class="hl-reserved">None
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">set_window_title_from_file</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">todo_file</span><span class="hl-brackets">)
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">reload_from_data</span><span class="hl-brackets">()


</span><span class="hl-reserved">def </span><span class="hl-identifier">on_file_open</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Function called to open a todo file</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">todo_file</span><span class="hl-default"> = </span><span class="hl-identifier">helper</span><span class="hl-default">.</span><span class="hl-identifier">file_browse</span><span class="hl-brackets">(</span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">FILE_CHOOSER_ACTION_OPEN</span><span class="hl-code">
		, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">get_browse_filter_list</span><span class="hl-brackets">()</span><span class="hl-code">
		, </span><span class="hl-identifier">FILE_EXT</span><span class="hl-brackets">)
	</span><span class="hl-comment">#If we have a file
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">todo_file</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">load_from_file</span><span class="hl-brackets">(</span><span class="hl-identifier">todo_file</span><span class="hl-brackets">))</span><span class="hl-default">:
			</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Allright it all worked! save the current file and
			set the title.</span><span class="hl-quotes">&quot;&quot;&quot;
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todo_file</span><span class="hl-default"> = </span><span class="hl-identifier">todo_file
			self</span><span class="hl-default">.</span><span class="hl-identifier">set_window_title_from_file</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">todo_file</span><span class="hl-brackets">)

</span><span class="hl-reserved">def </span><span class="hl-identifier">on_file_save</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">File | Save function - Save the Todo file</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-comment"># Let the user browse for the save location and name
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">todo_file</span><span class="hl-code"> == </span><span class="hl-reserved">None</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todo_file</span><span class="hl-default"> = </span><span class="hl-identifier">helper</span><span class="hl-default">.</span><span class="hl-identifier">file_browse</span><span class="hl-brackets">(</span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">FILE_CHOOSER_ACTION_SAVE</span><span class="hl-code">
		, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">get_browse_filter_list</span><span class="hl-brackets">()</span><span class="hl-code">
		, </span><span class="hl-identifier">FILE_EXT</span><span class="hl-brackets">)
	</span><span class="hl-comment">#If we have a todo file
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">todo_file</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">save_to_file</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">todo_file</span><span class="hl-brackets">))</span><span class="hl-default">:
			</span><span class="hl-comment">#Allright it all worked! Set the Title
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">set_window_title_from_file</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">todo_file</span><span class="hl-brackets">)

</span><span class="hl-reserved">def </span><span class="hl-identifier">on_file_save_as</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">widget</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">File | Save As function - Save the todo file</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">todo_file</span><span class="hl-default"> = </span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Untitled</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">todo_file</span><span class="hl-code"> != </span><span class="hl-reserved">None</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">todo_file</span><span class="hl-default"> = </span><span class="hl-identifier">os</span><span class="hl-default">.</span><span class="hl-identifier">path</span><span class="hl-default">.</span><span class="hl-identifier">basename</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">todo_file</span><span class="hl-brackets">)

	</span><span class="hl-identifier">todo_file</span><span class="hl-default"> = </span><span class="hl-identifier">helper</span><span class="hl-default">.</span><span class="hl-identifier">file_browse</span><span class="hl-brackets">(</span><span class="hl-identifier">gtk</span><span class="hl-code">.</span><span class="hl-identifier">FILE_CHOOSER_ACTION_SAVE</span><span class="hl-code">
		, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">get_browse_filter_list</span><span class="hl-brackets">()</span><span class="hl-code">
		, </span><span class="hl-identifier">FILE_EXT</span><span class="hl-brackets">)
	</span><span class="hl-comment">#If we have a xml_file
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">todo_file</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">save_to_file</span><span class="hl-brackets">(</span><span class="hl-identifier">todo_file</span><span class="hl-brackets">))</span><span class="hl-default">:
			</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Allright it all worked! save the current file and
			set the title.</span><span class="hl-quotes">&quot;&quot;&quot;
			</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todo_file</span><span class="hl-default"> = </span><span class="hl-identifier">todo_file
			self</span><span class="hl-default">.</span><span class="hl-identifier">set_window_title_from_file</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">todo_file</span><span class="hl-brackets">)</span></pre></div></div>
<p>They are all taken almost verbatim from previous tutorials so I won&#8217;t explaining them in detail.  The do rely on one helper function: get_browse_filter_list() that simply creates a list of gtk.FileFilters to use when browsing:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">get_browse_filter_list</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Used to get the list of gtk.FileFilter objects
	to use when browsing for a file.
	@returns - list - List of gtk.FileFilter objects
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">filter</span><span class="hl-default"> = </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">FileFilter</span><span class="hl-brackets">()
	</span><span class="hl-identifier">filter</span><span class="hl-default">.</span><span class="hl-identifier">set_name</span><span class="hl-brackets">(</span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Todo file</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">))
	</span><span class="hl-identifier">filter</span><span class="hl-default">.</span><span class="hl-identifier">add_pattern</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">*.</span><span class="hl-quotes">&quot;</span><span class="hl-code"> + </span><span class="hl-identifier">FILE_EXT</span><span class="hl-brackets">)
	</span><span class="hl-reserved">return </span><span class="hl-brackets">[</span><span class="hl-identifier">filter</span><span class="hl-brackets">]</span></pre></div></div>
<p>The actual work of saving and loading the data happens in the save_to_file(), load_from_file(), and reload_from_data() functions.  We&#8217;ll go over the save_to_file() function first:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">save_to_file</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">filename</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Save the current todoproject to a filename
		@param filename - string - the file name to save
		the file too.
		@returns boolean - success or failure
		</span><span class="hl-quotes">&quot;&quot;&quot;
		</span><span class="hl-reserved">try</span><span class="hl-default">:
			</span><span class="hl-identifier">todo_file</span><span class="hl-default"> = </span><span class="hl-builtin">open</span><span class="hl-brackets">(</span><span class="hl-identifier">filename</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">w</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
			</span><span class="hl-identifier">cPickle</span><span class="hl-default">.</span><span class="hl-identifier">dump</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">__categories</span><span class="hl-code">, </span><span class="hl-identifier">todo_file</span><span class="hl-code">, </span><span class="hl-identifier">cPickle</span><span class="hl-code">.</span><span class="hl-identifier">HIGHEST_PROTOCOL</span><span class="hl-brackets">)
			</span><span class="hl-identifier">todo_file</span><span class="hl-default">.</span><span class="hl-identifier">close</span><span class="hl-brackets">()
			</span><span class="hl-reserved">return True
		except </span><span class="hl-identifier">cPickle</span><span class="hl-default">.</span><span class="hl-identifier">PicklingError</span><span class="hl-default">, </span><span class="hl-identifier">e</span><span class="hl-default">:
			</span><span class="hl-identifier">helper</span><span class="hl-default">.</span><span class="hl-identifier">show_error_dlg</span><span class="hl-brackets">(</span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Error saving file: %s</span><span class="hl-special">\r\n</span><span class="hl-string">%s</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-code"> % </span><span class="hl-brackets">(</span><span class="hl-identifier">filename</span><span class="hl-code">, </span><span class="hl-identifier">e</span><span class="hl-brackets">))
			</span><span class="hl-reserved">return False
		except</span><span class="hl-default">:
			</span><span class="hl-identifier">helper</span><span class="hl-default">.</span><span class="hl-identifier">show_error_dlg</span><span class="hl-brackets">(</span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Error saving file: %s</span><span class="hl-quotes">&quot;</span><span class="hl-code"> % </span><span class="hl-identifier">filename</span><span class="hl-brackets">))
			</span><span class="hl-reserved">return False</span></pre></div></div>
<p>Besides the exception handling, the actual code in this function is very simple:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-identifier">todo_file</span><span class="hl-default"> = </span><span class="hl-builtin">open</span><span class="hl-brackets">(</span><span class="hl-identifier">filename</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">w</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
</span><span class="hl-identifier">cPickle</span><span class="hl-default">.</span><span class="hl-identifier">dump</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">__categories</span><span class="hl-code">, </span><span class="hl-identifier">todo_file</span><span class="hl-code">, </span><span class="hl-identifier">cPickle</span><span class="hl-code">.</span><span class="hl-identifier">HIGHEST_PROTOCOL</span><span class="hl-brackets">)
</span><span class="hl-identifier">todo_file</span><span class="hl-default">.</span><span class="hl-identifier">close</span><span class="hl-brackets">()
</span><span class="hl-reserved">return True</span></pre></div></div>
<p>First we open the file for writing, then we use <a href="http://docs.python.org/lib/module-cPickle.html">cPickle</a> to dump our __categories tree into the file, and then we close the file.  That&#8217;s it. </p>
<p>Loading the data is equally as simple:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">load_from_file</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">, </span><span class="hl-identifier">filename</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Try to a todo project from a
	specific file.
	@param filename - string - the file name to load
	from
	@returns boolean - success or failure
	</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-reserved">try</span><span class="hl-default">:
		</span><span class="hl-identifier">todo_file</span><span class="hl-default"> = </span><span class="hl-builtin">open</span><span class="hl-brackets">(</span><span class="hl-identifier">filename</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">rb</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__categories</span><span class="hl-default"> = </span><span class="hl-identifier">cPickle</span><span class="hl-default">.</span><span class="hl-identifier">load</span><span class="hl-brackets">(</span><span class="hl-identifier">todo_file</span><span class="hl-brackets">)
		</span><span class="hl-identifier">todo_file</span><span class="hl-default">.</span><span class="hl-identifier">close</span><span class="hl-brackets">()
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">reload_from_data</span><span class="hl-brackets">()
		</span><span class="hl-reserved">return True
	except </span><span class="hl-identifier">cPickle</span><span class="hl-default">.</span><span class="hl-identifier">UnpicklingError</span><span class="hl-default">, </span><span class="hl-identifier">e</span><span class="hl-default">:
		</span><span class="hl-identifier">helper</span><span class="hl-default">.</span><span class="hl-identifier">show_error_dlg</span><span class="hl-brackets">(</span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Error opening file: %s</span><span class="hl-special">\r\n</span><span class="hl-string">%s</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)</span><span class="hl-code"> % </span><span class="hl-brackets">(</span><span class="hl-identifier">filename</span><span class="hl-code">, </span><span class="hl-identifier">e</span><span class="hl-brackets">))
		</span><span class="hl-reserved">return False
	except</span><span class="hl-default">:
		</span><span class="hl-identifier">helper</span><span class="hl-default">.</span><span class="hl-identifier">show_error_dlg</span><span class="hl-brackets">(</span><span class="hl-identifier">_</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">Error opening file: %s</span><span class="hl-quotes">&quot;</span><span class="hl-code"> % </span><span class="hl-identifier">filename</span><span class="hl-brackets">))
		</span><span class="hl-reserved">return False</span></pre></div></div>
<p>First we open the file for reading and in binary mode (as instructed by the <a href="http://docs.python.org/lib/pickle-example.html">Pickle documentation</a>) and then we load the file into our self.__categories tree.  After that we close the files and reload the tree from self.__categories using the reload_from_data() function.</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">reload_from_data</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called when we want to reset everything based
	on internal data.  Probably called when a file has
	been loaded.</span><span class="hl-quotes">&quot;&quot;&quot;
	</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">todoTree</span><span class="hl-default">.</span><span class="hl-identifier">clear</span><span class="hl-brackets">()
	</span><span class="hl-identifier">if </span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">__categories</span><span class="hl-brackets">)</span><span class="hl-default">:
		</span><span class="hl-reserved">for </span><span class="hl-identifier">todo_ob </span><span class="hl-reserved">in </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__categories</span><span class="hl-default">:
			</span><span class="hl-identifier">todo_ob</span><span class="hl-default">.</span><span class="hl-identifier">add_to_tree</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">todoTree</span><span class="hl-code">, </span><span class="hl-reserved">None</span><span class="hl-code">, </span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">__tree_columns</span><span class="hl-brackets">)
	</span><span class="hl-reserved">else</span><span class="hl-default">:
		</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">__categories</span><span class="hl-default"> = </span><span class="hl-brackets">[]</span></pre></div></div>
<p>reload_from_data simply clears the gtk.TreeStore using the <a href="http://www.pygtk.org/docs/pygtk/class-gtktreestore.html#method-gtktreestore--clear">gtk.TreeStore.clear()</a> function.  Then it loops through all of the toplevel categories in self.__categories and adds each category to the tree by calling the add_to_tree() function.  If self.__categories is None for some reason (perhaps a bad file?) we simply reset it to a blank list.</p>
<p>If you remember the add_to_tree() function you&#8217;ll remember that it will also add all children of the category (and their children recursively) to the tree.</p>
<h2><a name="ConnectingOurMenuWithThegtkMenuToolButton">The Code: Connecting our menu with the gtk.MenuToolButton</a></h2>
<p>Well we&#8217;re almost done here, all we have to do is connect our gtk.MenuToolButton with the menu that we created way back in the GUI section.  Up until now you may have noticed that the arrow beside the Add button has been greyed out or disabled, this is because we have not attached a menu to the button yet using the <a href="http://www.pygtk.org/docs/pygtk/class-gtkmenutoolbutton.html#method-gtkmenutoolbutton--set-menu">gtk.MenuToolButton.set_menu()</a> function.  We will connect the menu to the button in a function called initialize_menus() that will be called in the __init__ function:</p>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-comment">#Initialize the todo Tree
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">initialize_todo_tree</span><span class="hl-brackets">()
</span><span class="hl-comment">#initialize menus
</span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">initialize_menus</span><span class="hl-brackets">()</span></pre></div></div>
<div class="hl-surround" ><div class="hl-main"><pre><span class="hl-reserved">def </span><span class="hl-identifier">initialize_menus</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)</span><span class="hl-default">:
	</span><span class="hl-quotes">&quot;&quot;&quot;</span><span class="hl-string">Called to initialize the menus</span><span class="hl-quotes">&quot;&quot;&quot;

	</span><span class="hl-identifier">add_button</span><span class="hl-default"> = </span><span class="hl-identifier">self</span><span class="hl-default">.</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">btnAdd</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-comment">#load the menu from the glade file
	</span><span class="hl-identifier">wTree</span><span class="hl-default"> = </span><span class="hl-identifier">gtk</span><span class="hl-default">.</span><span class="hl-identifier">glade</span><span class="hl-default">.</span><span class="hl-identifier">XML</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-code">.</span><span class="hl-identifier">gladefile</span><span class="hl-code">, </span><span class="hl-quotes">&quot;</span><span class="hl-string">addMenu</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-comment">#connect the menu with the signals
	</span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">signal_autoconnect</span><span class="hl-brackets">(</span><span class="hl-identifier">self</span><span class="hl-brackets">)
	</span><span class="hl-comment">#Get the menu dialog widget
	</span><span class="hl-identifier">menu</span><span class="hl-default"> = </span><span class="hl-identifier">wTree</span><span class="hl-default">.</span><span class="hl-identifier">get_widget</span><span class="hl-brackets">(</span><span class="hl-quotes">&quot;</span><span class="hl-string">addMenu</span><span class="hl-quotes">&quot;</span><span class="hl-brackets">)
	</span><span class="hl-identifier">if </span><span class="hl-brackets">((</span><span class="hl-identifier">add_button</span><span class="hl-brackets">) </span><span class="hl-identifier">and </span><span class="hl-brackets">(</span><span class="hl-identifier">menu</span><span class="hl-brackets">))</span><span class="hl-default">:
		</span><span class="hl-identifier">add_button</span><span class="hl-default">.</span><span class="hl-identifier">set_menu</span><span class="hl-brackets">(</span><span class="hl-identifier">menu</span><span class="hl-brackets">)</span></pre></div></div>
<p>The first thing that we do is get the our gtk.MenuToolButton &#8220;btnAdd&#8221; from the widget tree.  Then we get the widget tree that represents the &#8220;addMenu&#8221;.  We then auto connect that widget tree with ourselves (this connects the &#8220;Add Category&#8221; menu item with our on_add_category() function.  Then we get the actual <a href="http://www.pygtk.org/docs/pygtk/class-gtkmenu.html">gtk.Menu</a> from the menu&#8217;s widget tree.</p>
<p>If all of the widgets have been returned properly we then connect the two using the <a href="http://www.pygtk.org/docs/pygtk/class-gtkmenutoolbutton.html#method-gtkmenutoolbutton--set-menu">gtk.MenuToolButton.set_menu()</a> function.</p>
<p>Now when you run the application you will be able to use the menu to add categories!</p>
<p><img style="margin: 0pt 10px 10px 0pt;" src="http://www.learningpython.com/images/pylan_01/pylan_01_06.png" alt="Python GTD pyGTK" border="0" /></p>
<h2><a name="Conclusion">Conclusion</a></h2>
<p>You can download the full source to this tutorial <a href="http://www.learningpython.com/sources/PyLan_01.tar.gz">here</a>.</p>
<p>Whew!  That was a lot of code and a lot of text to get through.  Hopefully you were able to understand and follow along with all of it, and hopefully the next parts won&#8217;t be as long!  The only reason that this part was so long was that it had so much ground to cover and because so much of it had been covered before.  Future tutorials should cover smaller and more discrete tasks.</p>
<p>You will also notice that none of the translation files are included with the source, this was simply left out for now since there will be more text added in the future.  There are also some extra dialogs in the glade project that will be used in future tutorials, if you want you could start implementing them.</p>
<p>Of course you will probably never find yourself creating an application that is identical to this pyLan application, but the idea is that you may find yourself creating an application that is <i>similar</i> or that requires <i>similar elements</i>.  In those situations hopefully you will be able to re-use or re-factor that code found in this, and future, tutorials.</p>
<p>As always if you find any errors or have any questions feel free to leave a comment.  If however you have a general question about python or PyGTK I would appreciate it if you ask it in the <a href="http://www.learningpython.com/forums/">LearningPython</a> forums so that a possible solution to someone elses problem will not get buried in an unrelated area.</p>
<p>Time for a some food!</todocategory></todocolumn></selsine></p>
<div style="float:right;margin:0px 0px 0px 0px;"><a href="http://www.google.com/reader/link?url=http://www.learningpython.com/2007/02/17/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-one/&title=PyLan a GTD todo application written in python and PyGTK - part one&srcTitle=learning python&srcURL=http://www.learningpython.com"target="_blank" rel=""><img border="0" src="http://www.learningpython.com/wp-content/plugins/wp-google-buzz/icon/12.png" style="opacity:1;filter:alpha(opacity=100)" onmouseover="this.style.opacity=0.8;this.filters.alpha.opacity=70" onmouseout="this.style.opacity=1;this.filters.alpha.opacity=100"/> </a></div>]]></content:encoded>
			<wfw:commentRss>http://www.learningpython.com/2007/02/17/pylan-a-gtd-todo-application-written-in-python-and-pygtk-part-one/feed/</wfw:commentRss>
		<slash:comments>20</slash:comments>
		</item>
	</channel>
</rss>
