Thursday, August 12, 2010
A busy Delphi fall in Europe
Coming fall promises to be a very busy period for Delphi and TMS software. Several cool events are coming up and TMS software will be present at at least three of these events.Paris, France
The first event is the CodeWay tour 2010 in France. On september 9th, CodeWay organises a Delphi day in Paris. TMS software will be present and will do a session on our components. You'll have the opportunity to learn great things about Delphi development and to talk to us in person. Reserve your seat now for the CodeWay Tour 2010 in Paris.
Berlin, Germany
Friday 17 & saturday 18 September, the Delphi-Tage 2010 are organised in Berlin. Last year, over 200 Delphi developers gathered in Hamburg for an exciting event where TMS software was also present. This year, Berlin is the place where german Delphi developers unite. Unfortunately we can't attend this years Delphi Tage but TMS software is sponsoring the conference. Visit Delphi-Tage 2010 for more information and to confirm your presence.
Darmstadt, Germany
September 27 to 30, the EKON Delphi conference is being organised for the 14th time already. Many international and German speakers bring sessions on Delphi, Delphi Prism, VCL for the Web. TMS software will be present as exhibitor. It will be a great opportunity to meet with many of our existing & new German customers. More information on EKON14 and details to signup can be found on the Entwickler website
Verona, Italy
November 17-19, ITDevCon is taking place in Verona with November 18 - 19 entirely devoted to the European Delphi Conference. Three tracks of sessions are provided, thus plenty of choice to learn about designing and developing Delphi applications. TMS software is exhibitor and will also do two sessions. We look forward to meet our Italian existing & new customers for the first time. More details and signup for ITDevCon 2010 can be found on the ITDevCon website.
We'll keep you informed if more events do come up about Delphi here in Europe!
| Bookmarks: |
Bruno Fierens
This blog post has received 1 comment. Add a comment.
Friday, August 06, 2010
Get social with TMS list controls
Downloads
Twitter client
Facebook client
Introduction
Friends lists, tweets lists, comments lists, posts lists, favourites lists, ... we tend to order everything into lists in our life.
How we want to visualize items in lists has dramatically evolved from the nineties Windows 3.0 Listbox control that could just display
text. Web pages render lists with items that have all kinds of attributes. At TMS, we thought that Windows development with Delphi
also deserved richer list controls and recently developed two such powerful list controls: TAdvSmoothListBox and TMS Poly List controls.
As an excercise for the versatility & flexibility of these controls, we created two sample applications that we'd like to share:
an application that shows your tweets and an application that shows your Facebook home page. For the Twitter viewer, we used the TAdvSmoothListBox.
For the Facebook home page, we used the TMS Poly List controls. The focus of this article is to explain how these list controls were used. The two sample applications have 3 selectable styles to demonstrate how easy it is to change the look of the TMS list controls.
Twitter client:
General approach
The applications presented here have basically 3 parts, handled with 3 components. The Twitter viewer uses our TRESTClient component to retrieve data via the Twitter API in JSON format. The JSON data is parsed with a basic JSON parser, the component TJSONFormat and the data is visualized with the TAdvSmoothListBox. The Facebook home page viewer also uses the TRESTClient component for data retrieval in JSON format, the TJSONFormat component for parsing and a TAdvVerticalPolyList for showing the home page and a TAdvPolyList for showing the friends list.
The TRESTClient implements HTTP GET and HTTP POST via the Microsoft Windows WinInet API. We have choosen for the WinInet API as it is stable, it is able to pick up Internet Explorer's proxy settings transparently and it does not introduce dependencies on other components and is as such easy to use in a wide range of Delphi versions. The TRESTClient returns data as a TStream or string. It can equally work to download an image or text. It also handleds basic HTTP authentication. If there is an interest in this component, we might make it available at a later time. The data is parsed by a JSON parser we developed. This is a small & simple JSON parser that parses the JSON tree and in the process can also generate JSON from an object tree. We might also consider to make this available as a component if there is interest for this.
The Twitter client
The Twitter client as such uses the Twitter API (http://apiwiki.twitter.com/Twitter-API-Documentation) to access Twitter feed information in JSON format. The TAdvSmoothListBox is very convenient to display a Tweet. Following items are displayed inside the TAdvSmoothListBoxItem:
a) The item's Caption of the item is set to the screen_name of the user sending the Tweetb) The item's Info is set to the creation timestamp of the Tweet
c) The item's left graphic element is set to the user's profile image. In a separate thread, these images are loaded
d) The item's Notes are set to the TWeet's text. The Notes can handle HTML formatted text, so this is very convenient to display & handle links in the Tweets. The ConvertTextToHTML event converts the Tweet's text to HTML and takes care of the encoding of special characters in the Tweet text
e) A clickable hyperlink displayed in the item's notes.
The TRESTClient currently uses basic HTTP authentication with the Twitter API. We'll replace this basic authentication in a next version with OAuth authentication, but currently the code it uses is:
with RESTClient1.Items.Add do
begin
url := 'http://api.twitter.com/1/account/verify_credentials.json';
HTTPUserID := username;
HTTPPassword := password;
end;
RESTClient1.Execute;jsonformat1.LoadFromStream(RESTClient1.Items[0].Stream);
AdvSmoothListBox1.Header.Caption := jsonformat1.JSONObject.GetJSONValueString('screen_name');
url := jsonformat1.JSONObject.GetJSONValueString('profile_image_url');
RESTClient1.Items.Clear;
with RESTClient1.Items.Add do
begin
url := 'http://api.twitter.com/1/statuses/home_timeline.json';
HTTPUserID := username;
HTTPPassword := password;
end;
RESTClient1.Execute; A := TStringList.Create;
Split(' ', js.GetJSONValueString('created_at'), A);
AdvSmoothListBox1.Items[i].Info := 'Tweet on ' + A[2] + ' ' + A[1] + ' ' + A[5] + ' ' + A[3];
A.Free;
AdvSmoothListBox1.Items[i].InfoFont.Style := [fsItalic];
AdvSmoothListBox1.Items[i].NotesFont.Size := 10;
AdvSmoothListBox1.Items[i].NotesLocation := plCenterLeft;
AdvSmoothListBox1.Items[i].Notes := ConvertTextToHTML(ProcessString((js as TJSONObject).GetJSONValueString('text')));
AdvSmoothListBox1.Items[i].GraphicLeftType := gtImage;
AdvSmoothListBox1.Items[i].GraphicLeftWidth := 45;
AdvSmoothListBox1.Items[i].GraphicLeftHeight := 45; itId := TItemID.Create;
itId.ID := js.GetJSONValueNum('id');
itId.ImageURL := jsUser.GetJSONValueString('profile_image_url');
AdvSmoothListBox1.items[i].ItemObject := itId; for i := 0 to AdvSmoothListBox1.Items.Count - 1 do
begin
if Assigned(AdvSmoothListBox1.Items[i].ItemObject) then
begin
itemid := TItemID(AdvSmoothListBox1.Items[i].ItemObject);
if itemid.Status = tsNone then
begin
itemid.Status := tsStarted;
url := itemid.ImageURL;
img := DownloadPicture(url);
if Assigned(img) then
begin
AdvSmoothListBox1.Items[i].GraphicLeft.Assign(img);
img.Free;
end;
itemid.Status := tsLoaded;
end;
end;
end;
The Facebook client
The Facebook client uses the Facebook graph API (http://developers.facebook.com/docs/api). For authentication, first a Facebook application ID must be requested. Then, with this ID, the user needs to authenticate access to his profile. Upon succesful authentication, an access token is used for every access to the API. To obtain the access token, we need to use a TWebBrowser control to show the Facebook login screen and the redirect URL holds the access token. After login, the application loads the facebook friends list in a TAdvPolyList. This is a grid of images with the name of the friends shown under each image. The Facebook home page is shown in a TAdvVerticalPolyList. We have choosen for the TAdvVerticalPolyList as it enables to embed controls in each item. The controls are used to open comments for an item or to open a link associated with a home page item. The item type that is added in the TAdvVerticalPolyList is of the type TImageSectionItem. This allows us to associate an image with each item, to have a larger text caption and to have the description of the item. As a posted item can also have an additional image, this is is custom drawn on the item. Further, a panel can be associated with the item that can hold a button to view comments or visit a link.
The Facebook home page
Organisation of the facebook home page item:
a) Username as caption of the polylist TImageSectionItem
b) Post text as description of the TImageSectionItem. The margin of the description is set to the width of the post image to have the description text properly indented.
c) Picture of the user who posted the item. This picture is loaded via a separate thread as the TImageSectionItem's picture that is left positioned
d) Image of the post that is custom drawn in the OnItemEndDraw event
e) Panel embedded in the item with Comments & Visit link button
f) Comments items. These are two items of the type TImageItem with the user image positioned right. The OnItemStartDraw event is used to paint a text bubble like background.
This is the code that creates the item for a normal home page post:
itNormal := TImageSectionItem(List.AddItem(TImageSectionItem));
with itNormal do
begin
// reserve space for poster image
ImageHeight := 50;
ImageWidth := 50;
// set item default height
Height := 75;
CaptionSize := 11;
Ellipsis := True;
WordWrap := False;
DescriptionMargin.Left := 60;
CaptionMargin.Left := 50;
CaptionColor := ItemCaptionColor;
DescriptionColor := ItemDescriptionColor;
// set the caption to poster name and its location top left in the item
Caption := msgFromName;
CaptionLocation := tlTopLeft;
// set the description text for the TImageSectionItem
if msgMessage <> '' then
begin
if (msgDescription = '') and (msgcaption = '') then
Description := msgMessage
else
Caption := Caption + ' ' + msgMessage;
end;
if msgCaption <> '' then
Description := msgCaption + #13#10;
if msgDescription <> '' then
Description := Description + msgDescription + #13#10;
// object associated with the item
ItemObject := TItemID.Create;
TItemID(ItemObject).ID := msgFromID;
TItemID(ItemObject).MsgType := MsgType;
TItemID(ItemObject).ItemType := itHome;
LineStyle := psSolid;
LineSize := 1;
LineLocation := [llTop];
LineColor := clSilver;
// a picture is associated with the post, so download and
if msgPicture <> '' then
begin
with TItemID(ItemObject) do
begin
DescriptionImage := DownloadPicture(msgPicture);
if Assigned(DescriptionImage) then
begin
Height := DescriptionImage.Height + 60;
// set indent for the description
DescriptionMargin.Left := DescriptionMargin.Left + DescriptionImage.Width + 20;
end;
end;
end;
// assign the event handler that will draw the description image in the associated item object.
OnItemEndDraw := ItemEndDraw;
end;
itComment := TImageItem(List.AddItem(TImageItem));
with itComment do
begin
Level := 1;
// put images on the right side in the comment item
ImageTextLayout := ilRightLeft;
ImageHeight := 50;
ImageWidth := 50;
Height := 60;
CaptionSize := 11;
Ellipsis := True;
WordWrap := False;
CaptionColor := ItemCommentCaptionColor;
DescriptionColor := ItemCommentDescriptionColor;
Caption := msgFromName;
// item's caption & description location
CaptionLocation := tlTopLeft;
DescriptionLocation := tlTopLeft;
// indent for the comment poster & text
CaptionMargin.Left := 100;
DescriptionMargin.Left := 110;
if msgMessage <> '' then
Description := msgMessage;
// Object associated with the comment item
ItemObject := TItemID.Create;
TItemID(ItemObject).ID := msgFromID;
TItemID(ItemObject).MsgType := MsgType;
TItemID(ItemObject).ItemType := itHome;
// code that will draw the item background as a balloon
OnItemStartDraw := ItemStartDraw;
end;
Draw the item's description image, retrieved from object associated with the TAdvVerticalPolyList item via the ItemObject property:
procedure TForm1.ItemEndDraw(Sender: TObject; AGraphics: TGPGraphics;
Item: TCustomItem; ARect: TGPRectF);
var
itemid: TItemID;
pic: TAdvGDIPPicture;
offset: Double;
begin
if Assigned(item) then
begin
itemid := TItemID(item.ItemObject);
if Assigned(itemid.DescriptionImage) then
begin
pic := itemid.DescriptionImage;
offset := ARect.X + 40;
if Assigned((Item as TImageSectionItem).Image) then
offset := offset + (Item as TImageSectionItem).Image.Width + 5;
pic.GDIPDraw(AGraphics, MakeRect(offset, ARect.Y + 5 + (ARect.Height - pic.Height) / 2, pic.Width, pic.Height))
end;
end;
end;
procedure TForm1.ItemStartDraw(Sender: TObject; AGraphics: TGPGraphics; Item: TCustomItem; ARect: TGPRectF); var b: TGPSolidBrush; pth: TGPGraphicsPath; begin b := TGPSolidBrush.Create(MakeColor(255, ItemBackGroundColor)); AGraphics.FillRectangle(b, MakeRect(ARect.X + 100, ARect.Y, ARect.Width - 100, ARect.Height)); pth := TGPGraphicsPath.Create; pth.AddLine(ARect.X + 104, ARect.Y, ARect.X + 110, ARect.Y - 8); pth.AddLine(ARect.X + 110, ARect.Y - 8, ARect.X + 116, ARect.Y); pth.CloseFigure; AGraphics.FillPath(b, pth); pth.Free; b.Free; end;
The Facebook friends list
To show the friends list, a TAdvPolyList is used. This is a grid of poly list items. Each item is a picture with under the picture the name of the Facebook friend. To retrieve the friends list, the RESTClient uses the Friends request:
RESTClient1.Items.Clear;
RESTClient1.Items.Add.URL := 'https://graph.facebook.com/me/friends?access_token=' + access_code; ;
RESTClient1.Execute; var
vl: TValueList;
i: integer;
jo: TJSONObject;
JSONFormat1.LoadFromStream(RESTClient1.Items[0].Stream);
vl := JSONFormat1.JSONObject.GetJSONValueArray('data');
ProfileList.BeginUpdate;
for i := 0 to vl.Count - 1 do
begin
jo := TJSONObject(vl.Items[i]);
with TImageItem(ProfileList.AddItem(TImageItem)) do
begin
CaptionColor := ItemCaptionColor;
Height := 80;
CaptionSize := 7;
ImageHeight := 30;
ImageWidth := 30;
Caption := ProcessString(jo.GetJSONValueString('name'));
strid := jo.GetJSONValueString('id');
ItemObject := TItemID.Create;
TItemID(ItemObject).ID := strid;
TItemID(ItemObject).ItemType := itProfile;
end;
end;
ProfileList.EndUpdate;
Conclusion
Both demo applications were created as a fun project under the "eat your own dogfood" principle as a validation for both the experience for developing with the TMS TAdvSmoothListBox and TMS Poly List controls and the experience in the user interface. We found little or no limitations or friction to achieve the UI features we wanted to offer in these samples nor with the code to implement it. The executable applications are here so you can play with it. We look forward to your feedback about the list controls in general and the possible interest in the RESTClient and JSON parser. If there is sufficient interest and when the RESTClient & JSON parser are further polished for general use, we might consider to publish the full source code of the application. Stay tuned.
| Bookmarks: |
Bruno Fierens
This blog post has received 11 comments. Add a comment.
Thursday, July 15, 2010
Free Delphi plugin to ZIP and send Delphi projects
Frequently we try to help our customers by sending a small sample project showing how to achieve a specific task or requirement of the customer. Sometimes, we also need to revise projects customers created and send it back. This typically involves following steps:- Open Windows explorer
- Browse to the folder of the project
- Cleanup the folder and remove all unwanted files such as project.dsk, project.identcache etc...
- ZIP all files
- Add the ZIP file as attachment

The first option will traverse all files in the project and add this to ZIP file and open Windows Explorer in the project folder. The 2nd option will upload the ZIP file to a preset FTP server and put the link to the file on the clipboard. This link can then be pasted in the email to reply to the customer.
The dialog to customize the FTP settings as well as configure what files to include in the ZIP file can be called from the Delphi Help menu:

As we think this plugin can be helpful for many users, including our customers to send projects for revision to our support, you can obtain it free on the TMS ZIP Delphi Project page. Enjoy!
Bookmarks:
Bruno Fierens
This blog post has received 6 comments. Add a comment.
Sunday, July 11, 2010
Support: how to help you best?
For a long time, we offered our customers support via email and as of today, we still do. Several years ago, our customers requested a newsgroup as alternative for email support. So, we added a couple of years ago newsgroup support. More recently, our customers started requesting a web forum for support. And so we did. 2 months ago we finished the integration of a searchable web forum for support for our customers. It might be a subjective impression that the preference for newsgroup support is a bit on the decline. Is the preference for direct email support still as prevalent as it was years ago? Or is instant messenging the new wave? Or do you think it is crucial to be able to speak someone over the phone? Well, we want to know it so we can steer our efforts. Cast your vote here. Many thanks! | Bookmarks: |
Bruno Fierens
Tuesday, July 06, 2010
How Microsoft develops Outlook's spam filter
Each day, I discover emails in the Outlook junk mail folder that do not belong in the junk mail. Sometimes I really wonder on what criteria Microsoft decides an email is spam or junk. Today, I discovered that suddenly an email from Delphi.About.com (an excellent website by the way) got classified as junk. I have been receiving emails from Delphi.About.com for years without problems. So, my typical reaction is to mark the email as safe sender and move it to my Inbox.Now, I'm starting to think that Microsoft utilizes a very clever algorithm for filtering emails. Everyday it randomly flags some emails as junk. It counts on the user for inspecting the junk folder and whitelisting the emails that are not spam. This way, all Microsoft has to do is accept all emails in the whitelist the user created and further randomly move some emails to the junk folder. Eventually, when Microsoft classifies enough random emails as spam and the user persists building the whitelist, there is hope that one day the Microsoft Outlook email filter will work as expected. Now, don't tell me Microsoft isn't innovative!
| Bookmarks: |
Bruno Fierens





