segunda-feira, maio 26, 2008

Recursive component's enumerator in Delphi

I needed to loop through all the components in some forms, and when you have a frame inside a form, the default TComponent's enumerator doesn't return the components which are inside the frame.

After goggling a little bit I found this nice reference: Fun with enumerators, which helped me understand how Delphi enumerator's work (and how complicated they are), so I managed to write a class helper to loop recursively through components.

Below is the unit full source code:

unit RecursiveEnumerator;

interface

uses Classes,
Contnrs;

type
TRecursiveComponentsEnum = class
private
FComponents: TComponentList;
FIndex: Integer;
function GetCurrent: TComponent;
public
constructor Create(AContainer: TComponent);
destructor Destroy; override;
function MoveNext: Boolean;
property Current: TComponent read GetCurrent;
end;

IRecursiveEnumeratorFactory = interface
function GetEnumerator: TRecursiveComponentsEnum;
end;

TRecursiveEnumeratorFactory = class(TInterfacedObject, IRecursiveEnumeratorFactory)
private
FContainer: TComponent;
public
function GetEnumerator: TRecursiveComponentsEnum;
constructor Create(AContainer: TComponent);
end;

TRecursiveEnumeratorComponentHelper = class helper for TComponent
public
function GetRecursiveEnumerator: IRecursiveEnumeratorFactory;
end;

implementation

uses
SysUtils;

constructor TRecursiveComponentsEnum.Create(AContainer: TComponent);
procedure AddToList(AComponent: TComponent);
var
lComponent: TComponent;
begin
for lComponent in AComponent do
begin
if lComponent.ComponentCount > 0 then
AddToList(lComponent);
FComponents.Add(lComponent);
end;
end;
begin
FComponents := TComponentList.Create(False);
AddToList(AContainer);
FIndex := -1;
end;

destructor TRecursiveComponentsEnum.Destroy;
begin
FComponents.Free;
inherited;
end;

function TRecursiveComponentsEnum.GetCurrent: TComponent;
begin
Result := FComponents.Items[FIndex];
end;

function TRecursiveComponentsEnum.MoveNext: Boolean;
begin
Result := FIndex < FComponents.Count - 1;
if Result then
Inc(FIndex);
end;

function TRecursiveEnumeratorComponentHelper.GetRecursiveEnumerator: IRecursiveEnumeratorFactory;
begin
Result := TRecursiveEnumeratorFactory.Create(Self);
end;

constructor TRecursiveEnumeratorFactory.Create(AContainer: TComponent);
begin
FContainer := AContainer;
end;

function TRecursiveEnumeratorFactory.GetEnumerator: TRecursiveComponentsEnum;
begin
Result := TRecursiveComponentsEnum.Create(FContainer);
end;

end.


It is a class helper, to use it, just add the unit to the uses list and use it like this:



var
Component: TComponent;
begin
for Component in GetRecursiveEnumerator do
// do something with the component
end;


The magic here is that it doesn't loop trough the components "on the fly". When you call the GetRecursiveEnumerator a TRecursiveComponentsEnum instance is created, at this time, it loops recursively trough all the component's underlying components and fill a TComponentList (FComponents), then the GetCurrent method return's the components from this list, and it just works.



constructor TRecursiveComponentsEnum.Create(AContainer: TComponent);
procedure AddToList(AComponent: TComponent);
var
lComponent: TComponent;
begin
for lComponent in AComponent do
begin
if lComponent.ComponentCount > 0 then
AddToList(lComponent);
FComponents.Add(lComponent);
end;
end;
begin
FComponents := TComponentList.Create(False);
AddToList(AContainer);
FIndex := -1;
end;


Hope I'm not reinventing the wheel. If you know a better solution, please let me know.

sexta-feira, maio 09, 2008

Code is your least problem

Most developers think that in order to be a good developer, they need to know 10 different programming languages. I wish real life was that simple.

When you start working in real life software, problems in the source code are the easiest to solve, the real problems start to hunt you when you need to think about design, or in most cases, when you don't design in the first place.

Keeping it short, you can't please both Greeks and Trojans. If you try to do that, you can doom your project for that neat little feature you added just because someone asked and you found it cool.

I just finished reading The Mythical Man Month, it was written in the sixties, back then they didn't have these wonderful ultra high level languages as we do today, but still problems in the design phase were worst than coding problems, can you imagine what is worst than reading memory dumps produced by assembly code?

I confess that when I started programming, I wanted to write code, and still want, but I realized that rushing straight to the code writing will give you more headaches and make you lose a lot more time than if you take your time and carefully think about what problem you are trying to solve, but still I always rush into it.

Have you ever get in a discussion that lasted hours and hours and suddenly someone asks "what problem are we trying to solve again?", usually nobody can answer it.

Asking yourself what problems you are trying to solve is indeed one of the best ways to be sure that what you are trying to do is worth it, you need to solve problems, not write code, indeed for a developer it is very difficult to solve a problem without writing code, but that would be heaven, personally I find it more enjoyable to delete code, not write it.

If we wish to count lines of code, we should not regard them as lines produced but as lines spent. (Edsger Dijkstra)

Remember, your purpose is to solve people's problem, not write code, if you keep that in mind, you can produce real software which people would really use in real life, which would solve real problems.

Easier said than done, isn't it?

domingo, maio 04, 2008

How to add syntax highlight to Blogger

Adding syntax highlight to blogger is very simple, first of all you need to download SyntaxHighlighter.

Now extract the contents of the package and upload the Scripts and Styles folder to any host or website which can be linked from your blog.

To make it work, you will need to edit your blog's template and add the following code after the <!-- end outer-wrapper --> tag:


<link href='http://[YOUR HOST URL]/SyntaxHighlighter.css' rel='stylesheet' type='text/css'/>
<script language='javascript' src='http://[YOUR HOST URL]/shCore.js'/>


<script language='javascript'>
dp.SyntaxHighlighter.BloggerMode();
dp.SyntaxHighlighter.HighlightAll('code');
</script>


Now you just need to add support for the languages you want, I could just say, just put this bunch of code on your blog's template and it will work, but most people don't post code in several languages, also it's very important to understand what the hell you are doing.

To add syntax highlight support for python, after the shCore.js line you added before, add this line:

<script language='javascript' src='http://[YOUR HOST URL]/shBrushPython.js'/>


If you browse the Scripts folder of the syntaxhighlighter package, you will notice several shBrush*.js files, like shBrushPhp.js, these files are the highlight rules for especific languages, to support other languages, just change the shBrushPython in the above code to your language's specific file and add it to your template.

Syntaxhighlighter supports pre and textarea tags, but it will not work automagically, you need to specify that a pre or textarea tag is code and which language the code is.

To add some python code to your blog use:

<pre name="code" class="python">

The list of supported languages and their aliases can be found at the syntaxhighlighter wiki