<?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>elsdoerfer.name</title>
	<atom:link href="http://blog.elsdoerfer.name/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.elsdoerfer.name</link>
	<description>the blog</description>
	<lastBuildDate>Tue, 09 Mar 2010 13:08:26 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Twisted Twistd Autoreload</title>
		<link>http://blog.elsdoerfer.name/2010/03/09/twisted-twistd-autoreload/</link>
		<comments>http://blog.elsdoerfer.name/2010/03/09/twisted-twistd-autoreload/#comments</comments>
		<pubDate>Tue, 09 Mar 2010 13:08:26 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://blog.elsdoerfer.name/?p=161</guid>
		<description><![CDATA[While working on the Twisted server for A World Of Photo, I quickly began missing the convenience of having it automatically restart during development when I had made changes to the code. It turns out that the autoreload module that Django uses is actually pretty generic [1]. One thing Twisted doesn't like is that the [...]]]></description>
			<content:encoded><![CDATA[<p>While working on the Twisted server for <a href="http://elsdoerfer.name/=photoworld">A World Of Photo</a>, I quickly began missing the convenience of having it automatically restart during development when I had made changes to the code. It turns out that the autoreload module that Django uses is actually pretty generic [1]. One thing Twisted doesn't like is that the code which checks for file changes is run inside the main thread, and the actual app in a separate thread. That's easily reversed though. You can find a patched version <a href="http://bitbucket.org/miracle2k/pyutils/src/tip/pyutils/autoreload.py">on bitbucket</a>.</p>
<p>Then, all you need is a simple twistd wrapper:</p>
<pre name="code" class="python">
from twisted.scripts import twistd
from pyutils import autoreload

autoreload.main(twistd.run)
</pre>
<p>[1] <a href="http://twistedmatrix.com/trac/ticket/4072">http://twistedmatrix.com/trac/ticket/4072</a></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.elsdoerfer.name/2010/03/09/twisted-twistd-autoreload/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Django Tree Libraries</title>
		<link>http://blog.elsdoerfer.name/2010/02/28/django-tree-libraries/</link>
		<comments>http://blog.elsdoerfer.name/2010/02/28/django-tree-libraries/#comments</comments>
		<pubDate>Sun, 28 Feb 2010 05:58:31 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Django]]></category>

		<guid isPermaLink="false">http://blog.elsdoerfer.name/?p=177</guid>
		<description><![CDATA[django-mptt

Nested Set trees.
A register() call is used to set things up; it ads the necessary fields to the model.
A tree model still has a foreign key to itself. This is the API you use to manage the tree. Signals are used that the hidden tree fields are updated when the parent ForeignKey changes. No add_child() [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://code.google.com/p/django-mptt/">django-mptt</a></p>
<ul>
<li>Nested Set trees.</li>
<li>A <em>register()</em> call is used to set things up; it ads the necessary fields to the model.</li>
<li>A tree model still has a foreign key to itself. This is the API you use to manage the tree. Signals are used that the hidden tree fields are updated when the parent ForeignKey changes. No add_child() required.</li>
<li>Using the foreign key to self means that deletion is handled automatically be Django and/or the database. The other libraries need to implement a custom Queryset subclass to handle deletes.</li>
</ul>
<p><a href="http://code.tabo.pe/django-treebeard/">django-treebeard</a></p>
<ul>
<li>Has an awesome name.</li>
<li>In addition to the common <em>Nested Set/MPTT</em> approach, supports two other tree implementations. <em>Materialized Path</em> in particular is interesting.</li>
<li>You inherit your models from abstract base classes, which I like.</li>
<li>The tree has to be managed manually, that is, there are specific APIs like <em>add_child()</em> you have to call.</li>
<li>Unfortunately, those APIs are classmethods on the model rather than the Django-way, putting them into the model manager.</li>
</ul>
<p><a href="http://bitbucket.org/fivethreeo/django-easytree/">django-easy-tree</a></p>
<ul>
<li>Apparently a fork of django-treebeard, but only supports Nested Set trees.</li>
<li>But has a prettier API that fits very well into Django: Nicer class names, properly puts methods into the manager when they belong there, options are specified inside "Meta" rather than on the model itself.</li>
<li>Has an interesting concept of validators. Included is a <em>SingleRootAllowedValidator</em>.</li>
<li>No tests!</li>
</ul>
<p>Clearly, somebody needs to write a django-treebeard that uses the django-easy-tree API design and django-mptt's signal approach.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.elsdoerfer.name/2010/02/28/django-tree-libraries/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Speeding up Django tests using a RAM-bound MySQL server</title>
		<link>http://blog.elsdoerfer.name/2010/02/25/speeding-up-django-tests-using-a-ram-bound-mysql-server/</link>
		<comments>http://blog.elsdoerfer.name/2010/02/25/speeding-up-django-tests-using-a-ram-bound-mysql-server/#comments</comments>
		<pubDate>Thu, 25 Feb 2010 21:16:39 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.elsdoerfer.name/?p=173</guid>
		<description><![CDATA[A while ago, Django's testing framework got transaction-based rollback, which obviously did wonders in terms of test performance. One thing that still bothered me though was the slow, initial table setup. For example, in a modestly sized project of mine with about 40 tables, this would take up to almost a minute. In particular when [...]]]></description>
			<content:encoded><![CDATA[<p>A while ago, Django's testing framework got transaction-based rollback, which obviously did wonders in terms of test performance. One thing that still bothered me though was the slow, initial table setup. For example, in a modestly sized project of mine with about 40 tables, this would take up to almost a minute. In particular when writing new tests, which is going to be an iterative process, that's really not acceptable.</p>
<p>Now, one obvious things to do is using an in-memory SQLite database for testing purposes. I've tried that at times, but ultimately, various MySQL-specific stuff and raw SQL queries always made this an unsatisfying experience.</p>
<p>I've now finally realized that there is an easy solution, and I'm perplexed it didn't occur to me earlier (maybe Linux, to which I've recently switched, just puts these kinds of options closer to one's grasp). And it really is pretty straightforward: Mount a tmpfs, run a second MySQL instance on a different socket/port using this mount as a data dir, and tell Django to use it.</p>
<p>I've put shell script that I'm using <a href="http://github.com/miracle2k/linuxutils/blob/master/mysqld-ram.sh">on github</a>.</p>
<p>You might want to customize the location of the data directory or the bind options, then simply do:</p>
<p><code>sudo ./mysqld-ram.sh</code></p>
<p>and when you're done, shutdown with Ctrl+C.</p>
<p>The tables which previously took a minute to setup, now only need two and a half seconds. It even cuts the runtime of the actual tests, which were already using transaction-rollback before, in half. Not surprisingly, I notice that my motivation to actually write tests and keep them up-to-date has noticeably improved.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.elsdoerfer.name/2010/02/25/speeding-up-django-tests-using-a-ram-bound-mysql-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Windows BCD file is just a registry hive</title>
		<link>http://blog.elsdoerfer.name/2010/02/22/windows-bcd-file-is-just-a-registry-hive/</link>
		<comments>http://blog.elsdoerfer.name/2010/02/22/windows-bcd-file-is-just-a-registry-hive/#comments</comments>
		<pubDate>Mon, 22 Feb 2010 20:04:39 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.elsdoerfer.name/?p=168</guid>
		<description><![CDATA[The Vista/Windows 7 Boot Manager data in Boot/BCD is simply a registry hive and can be read using a tool like reged. 
It contains stuff like /Description/TreatAsSystem, /Description/GuidCache and a whole bunch of guids under /Objects. Presumably, the actually interesting data is there, but unfortunately, it's all binary.
A guy named Geoff Chapell has some info [...]]]></description>
			<content:encoded><![CDATA[<p>The Vista/Windows 7 Boot Manager data in <em>Boot/BCD</em> is simply a registry hive and can be read using a tool like <a href="http://pogostick.net/~pnh/ntpasswd/editor.html">reged</a>. </p>
<p>It contains stuff like <em>/Description/TreatAsSystem</em>, <em>/Description/GuidCache</em> and a whole bunch of guids under <em>/Objects</em>. Presumably, the actually interesting data is there, but unfortunately, it's all binary.</p>
<p>A guy named Geoff Chapell <a href="http://www.geoffchappell.com/viewer.htm?doc=notes/windows/boot/bcd/index.htm">has some info</a> on what it all might mean.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.elsdoerfer.name/2010/02/22/windows-bcd-file-is-just-a-registry-hive/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Downloading drivers for old 3ware products</title>
		<link>http://blog.elsdoerfer.name/2010/02/15/downloading-drivers-for-old-3ware-products/</link>
		<comments>http://blog.elsdoerfer.name/2010/02/15/downloading-drivers-for-old-3ware-products/#comments</comments>
		<pubDate>Mon, 15 Feb 2010 22:28:52 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.elsdoerfer.name/?p=166</guid>
		<description><![CDATA[On the download site, make sure to select the All Releases and go through the form wizard. Do not use Click here to View all our products - it'll lead you to a huge, inpenetrable list of possible downloads for some products.
]]></description>
			<content:encoded><![CDATA[<p>On the <a href="http://www.3ware.com/support/download.asp">download site</a>, make sure to select the <em>All Releases</em> and go through the form wizard. Do not use <em>Click here to View all our products</em> - it'll lead you to a huge, inpenetrable list of possible downloads for some products.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.elsdoerfer.name/2010/02/15/downloading-drivers-for-old-3ware-products/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Use different terminal colors while inside ssh</title>
		<link>http://blog.elsdoerfer.name/2010/01/28/use-different-terminal-colors-while-inside-ssh/</link>
		<comments>http://blog.elsdoerfer.name/2010/01/28/use-different-terminal-colors-while-inside-ssh/#comments</comments>
		<pubDate>Thu, 28 Jan 2010 20:28:14 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://blog.elsdoerfer.name/?p=153</guid>
		<description><![CDATA[Since this was a source of confusion for me in the past, I like to make it visually obvious when I'm inside an ssh session in gnome-terminal, vs. on the local machine. This is the best solution I have found so far:

ssh-done() {
        setterm -term linux -inversescreen off;
}
ssh() [...]]]></description>
			<content:encoded><![CDATA[<p>Since this was a source of confusion for me in the past, I like to make it visually obvious when I'm inside an ssh session in gnome-terminal, vs. on the local machine. This is the best solution I have found so far:</p>
<pre name="code">
ssh-done() {
        setterm -term linux -inversescreen off;
}
ssh() {
        setterm -term linux -inversescreen on;
        /usr/bin/env ssh $*;
        ssh-done;
}
</pre>
<p>The reason why <em>ssh-done</em> is exposed as a separate function is that when ending ssh through <em>Ctrl+C</em> (for example, while at the password prompt), this gives you the ability to manually reset the terminal to normal again.</p>
<p><em>setterm</em> in theory would also allow you to manually select a foreground and background color, though this didn't work to well for me; in particular, it broke in various cases when commands tried to colorize their own output.</p>
<p>Totally awesome would be the ability to script gnome-terminal to switch the profile, but this <a href="https://bugzilla.gnome.org/show_bug.cgi?id=569869">doesn't seem to exist yet</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.elsdoerfer.name/2010/01/28/use-different-terminal-colors-while-inside-ssh/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Django: Flexible date form fields accepting (almost) any input</title>
		<link>http://blog.elsdoerfer.name/2009/12/12/django-flexible-date-form-fields-accepting-almost-any-input/</link>
		<comments>http://blog.elsdoerfer.name/2009/12/12/django-flexible-date-form-fields-accepting-almost-any-input/#comments</comments>
		<pubDate>Sat, 12 Dec 2009 06:25:12 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Django]]></category>

		<guid isPermaLink="false">http://blog.elsdoerfer.name/?p=138</guid>
		<description><![CDATA[At critify, we do a lot of copy &#038; paste. Sometimes, that means copy &#038; pasting a date from another site into a Django DateTimeField on our site. This can be tedious, because Django only supports a fixed number of strict input formats, while the actual input can at times be something quite freeform. So [...]]]></description>
			<content:encoded><![CDATA[<p>At <a href="http://critify.de">critify</a>, we do a lot of copy &#038; paste. Sometimes, that means copy &#038; pasting a date from another site into a Django <a href="http://docs.djangoproject.com/en/dev/ref/forms/fields/#datetimefield">DateTimeField</a> on our site. This can be tedious, because Django only supports a fixed number of strict input formats, while the actual input can at times be something quite freeform. So I decided that what was needed were date form fields that would make a good attempt at parsing the input.</p>
<p>Here's what you need:</p>
<ul>
<li><a href="http://labix.org/python-dateutil">python-dateutil</a>, which provides the parser.</li>
<li><a href="http://bitbucket.org/miracle2k/djutils/src/468ecaa38255/djutils/forms/fields/dateutil.py">This file</a>, which implements <em>DateTimeField</em> and <em>DateField</em> form field classes which use <em>python-dateutil</em> to process the input.</li>
</ul>
<p>With that available, the actual code is quite simple:</p>
<pre name="code" class="python">
from djutils.forms.fields import formfield_callback

class YourForm(ModelForm):
    formfield_callback = formfield_callback
    class Meta:
        model = YourModel
</pre>
<p>The <em>formfield_callback</em> will ensure that for every <em>DateField</em> or <em>DateTimeField</em> that your model has, the appropriate form field with dateutil-parsing support will be generated.</p>
<p>Of course, you can use these fields manually as well:</p>
<pre name="code" class="python">
from django import forms
from djutils.forms.fields import DateField

class MyForm(forms.Form):
    std_date = forms.DateField() # < - Uses the standard DateField
    parsed_date = DateField()  # <- Uses the custom DateField
</pre>
<p>This should work well enough; we can now put something like <em>8th of January</em> into the form, and it'll be parsed into the correct date.</p>
<p><em>"8th of January"</em>? My site is in German! Fortunately, while not supporting it out of the box, <em>python-dateutil</em> is flexible enough to allow for internationalization as well. You need to get:</p>
<ul>
<li><a href="http://bitbucket.org/miracle2k/pyutils/src/tip/pyutils/date/__init__.py">Yet another file</a>, which adds support for German date strings to <em>python-dateutil</em> (i.e. "Janauar", "Montag", ....). If you need to support a different language, you can use that file as a template.</li>
</ul>
<p>The way internationalization is done with <em>python-dateutil</em> is that you implement a <em>parserinfo</em> class for a given language. We need to tell our custom form fields to use the German parserinfo provided by the file above:</p>
</pre>
<pre name="code" class="python">
from djutils.forms.fields import get_formfield_for
from pyutils.date import GermanParserInfo

class YourForm(ModelForm):
    def formfield_callback(field):
         # If it's a date-related field, get one of our custom form fields
         result = get_formfield_for(field, parserinfo=GermanParserInfo())
         # Otherwise, use the default form field.
         return result or field.formfield()
    class Meta:
        model = YourModel
</pre>
<p>That's basically it. You might want to create a base form class that you can inherit from for DRY purposes.</p>
<p>By the way, my module containing the German parser info also has a <em>MultiParserInfo</em> helper that may be useful to some:</p>
<pre name="code" class="python">
parserinfo=MultiParserInfo(parsers=[GermanParserInfo()])
</pre>
<p>This will give you a parser that supports both German date names, and the original English date names as a fallback. If you need to support even more languages, you could too:</p>
<pre name="code" class="python">
parserinfo=MultiParserInfo(parsers=[GermanParserInfo(), FrenchParserInfo()])
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.elsdoerfer.name/2009/12/12/django-flexible-date-form-fields-accepting-almost-any-input/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Properly sending contact form emails and how to do it in Django</title>
		<link>http://blog.elsdoerfer.name/2009/11/09/properly-sending-contact-form-emails-and-how-to-do-it-in-django/</link>
		<comments>http://blog.elsdoerfer.name/2009/11/09/properly-sending-contact-form-emails-and-how-to-do-it-in-django/#comments</comments>
		<pubDate>Mon, 09 Nov 2009 13:41:18 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Django]]></category>

		<guid isPermaLink="false">http://blog.elsdoerfer.name/?p=84</guid>
		<description><![CDATA[Ever since I decided to use SpamStopsHere (their excellent, by the way) I noticed that some emails sent to me by one of my site's contact form didn't pass their SPF check.
It turns out that apart from your normal "From" sender, an email message also has an envelope sender specified in the Return-Path header. The [...]]]></description>
			<content:encoded><![CDATA[<p>Ever since I decided to use <a href="http://spamstopshere.com/">SpamStopsHere</a> (their excellent, by the way) I noticed that some emails sent to me by one of my site's contact form didn't pass their <a href="http://en.wikipedia.org/wiki/Sender_Policy_Framework">SPF</a> check.</p>
<p>It turns out that apart from your normal "<em>From</em>" sender, an email message also has an <a href="http://en.wikipedia.org/wiki/Bounce_address">envelope sender</a> specified in the <em>Return-Path</em> header. The first is considered to be the author, the second refers to who is responsible for actually sending the message.</p>
<p>So my site sent those contact form emails to me using as the sender whatever the user specified as his email address in the form - in both the <em>From</em> and <em>Return-Path</em> path fields. Whenever the user's email domain had SPF records installed, the validation would run the user's email against my mail servers and thus obviously fail.</p>
<p>The solution then is to use as the <em>Return-Path</em> an address of your own. How to do this in Django? It's really simple, but totally non-obvious. This is per <a href="http://code.djangoproject.com/ticket/9214">Ticket 9214</a> and <a href="http://code.djangoproject.com/changeset/9842">Changeset 9842</a> (so you need at least 1.1).</p>
<pre name="code" class="python">
connection = SMTPConnection(fail_silently=fail_silently)
headers = {'From': 'users@email.address'}  # From-header
from_email = 'bounce@mysite.com'           # Return-Path header
EmailMessage(subject, message, from_email, recipient_list,
                   connection=connection, headers=headers).send()
</pre>
<p>Note that we need to work with ``EmailMessage`` directly - <code>django.core.mail.send_mail</code> doesn't provide an option for custom headers.</p>
<p>If you are using <a href="http://bitbucket.org/ubernostrum/django-contact-form/">django-contact-form</a>, it unfortunately doesn't support custom headers out of the box either, so you need to apply <a href="http://bitbucket.org/miracle2k/django-contact-form/changeset/97e82ad7e8d3/">a patch</a>. Then, the following should work:</p>
<pre name="code" class="python">
class MyContactForm(AkismetContactForm):
    def __init__(self, *args, **kwargs):
        super(self.__class__, self).__init__(*args, **kwargs)
            self.subject = "Contact Form"
            self.template_name = "site/pages/contact_email.txt"
            # Return-Path header, e.g. bounce@mysite.com
            self.from_email = settings.DEFAULT_FROM_EMAIL
            # From-header
            self.headers = \
                lambda: {'From': "%s < %s>" %
                    (self.cleaned_data['name'], self.cleaned_data['email'])}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.elsdoerfer.name/2009/11/09/properly-sending-contact-form-emails-and-how-to-do-it-in-django/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Clickable URLs in Android TextViews</title>
		<link>http://blog.elsdoerfer.name/2009/10/29/clickable-urls-in-android-textviews/</link>
		<comments>http://blog.elsdoerfer.name/2009/10/29/clickable-urls-in-android-textviews/#comments</comments>
		<pubDate>Thu, 29 Oct 2009 04:28:08 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Android]]></category>

		<guid isPermaLink="false">http://blog.elsdoerfer.name/?p=120</guid>
		<description><![CDATA[Android's TextView widget can contain clickable URLs. It can easily make web addresses open in the browser, or connect phone numbers with the dialer. All that is amazing compared to the last GUI framework I used, Delphi's once great VCL).
Unfortunately, both TextView and the Linkify utility it uses basically hardcode URL click handling to Intents, [...]]]></description>
			<content:encoded><![CDATA[<p>Android's <a href="http://developer.android.com/reference/android/widget/TextView.html">TextView</a> widget can contain clickable URLs. It can easily make web addresses open in the browser, or connect phone numbers with the dialer. All that is amazing compared to the last GUI framework I used, Delphi's once great <a href="http://en.wikipedia.org/wiki/Visual_Component_Library">VCL</a>).</p>
<p>Unfortunately, both <em>TextView</em> and the <a href="http://developer.android.com/reference/android/text/util/Linkify.html">Linkify</a> utility it uses basically hardcode URL click handling to Intents, by way of the <a href="http://developer.android.com/reference/android/text/style/URLSpan.html">URLSpan</a>s they create. What if we want the link to affect something within your own Activity, say, display a dialog, or enable a filter? </p>
<p>For example, in <a href="http://elsdoerfer.name/=android-autostarts">Autostarts</a>, if the user's filters cause the application list to be empty, I wanted to display an explanatory message, and provide a quick and easy way for the user to rectify the situation, i.e. lead him towards the filter selection dialog. Making the whole text clickable is hard to get right visually, and I didn't like the idea of a button too much. A link within the text seemed perfect.</p>
<p>Now, we could just use a custom URL scheme of course, and register our Activity to handle Intents for that scheme, but that seemed much too heavy, if not hacky. Why shouldn't we be able to just hook up an onClick handler?</p>
<p>As mentioned, <em>URLSpan</em> doesn't allow us to change the way it handles clicks (it always sends off an Intent), but we can create a subclass:</p>
<pre name="code" class="java">
static class InternalURLSpan extends ClickableSpan {
	OnClickListener mListener;

	public InternalURLSpan(OnClickListener listener) {
		mListener = listener;
	}

	@Override
	public void onClick(View widget) {
		mListener.onClick(widget);
	}
}
</pre>
<p>That looks pretty decent. Actually using that class it is more though. There is no way to tell <em>TextView</em> or <em>Linkify</em> to use our custom span. In fact, <em>Linkify</em> actually has <a href="http://www.google.com/codesearch/p?hl=en&#038;sa=N&#038;cd=1&#038;ct=rc#uX1GffpyOZk/core/java/android/text/util/Linkify.java&#038;q=class:Linkify%20android&#038;l=378">a method (<em>applyLink</em>)</a> that would be nearly perfect to override, but declares it final.</p>
<p>So, we end up having to generate the spans manually; note nice, but hey, it works.</p>
<pre name="code" class="java">
SpannableString f = new SpannableString("....")
f.setSpan(new InternalURLSpan(new OnClickListener() {
        public void onClick(View v) {
            showDialog(DIALOG_VIEW_OPTIONS);
        }
    }), x, y, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
</pre>
<p>We probably also want the user to jump to your link my moving the focus (e.g. using the trackball), which we can do by setting the proper movement method:</p>
<pre name="code" class="java">
MovementMethod m = emptyText.getMovementMethod();
if ((m == null) || !(m instanceof LinkMovementMethod)) {
    if (textView.getLinksClickable()) {
        textView.setMovementMethod(LinkMovementMethod.getInstance());
    }
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.elsdoerfer.name/2009/10/29/clickable-urls-in-android-textviews/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Android: Determine if running in emulator</title>
		<link>http://blog.elsdoerfer.name/2009/07/24/android-determine-if-running-in-emulator/</link>
		<comments>http://blog.elsdoerfer.name/2009/07/24/android-determine-if-running-in-emulator/#comments</comments>
		<pubDate>Fri, 24 Jul 2009 14:39:32 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Android]]></category>

		<guid isPermaLink="false">http://blog.elsdoerfer.name/?p=108</guid>
		<description><![CDATA[
if ("1".equals(SystemProperties.get("ro.kernel.qemu")) {
    // Emulator
}

[via]
]]></description>
			<content:encoded><![CDATA[<pre name="code" class="java">
if ("1".equals(SystemProperties.get("ro.kernel.qemu")) {
    // Emulator
}
</pre>
<p>[<a href="http://www.google.com/codesearch?hl=en&#038;lr=&#038;q=ro.kernel.qemu">via</a>]</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.elsdoerfer.name/2009/07/24/android-determine-if-running-in-emulator/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
