C++Builder XE5 iOS RSS feed reader app

Posted by on in Blogs
Last year, Marco Cantu created a Delphi for iOS/Android feed reader app (YouTube video). In this blog post I'll show you how to create a C++ iOS RSS feed reader app using C++Builder XE5 update 2. In the demo project I will be using the isocpp.org blog RSS feed (http://isocpp.org/blog/rss) and the Embarcadero technology blog RSS feed (http://blogs.embarcadero.com/feeds/wpmu-feed/). To access XML based RSS feeds, I use the TIdHTTP component. To parse the XML I use TXMLDocument component and the Open XML ADOM XML. To display the RSS feed items, I use the TListBox component. To navigate to the article I use the TWebBrowser component. Here are a few of the steps and source code to create your own C++ iOS RSS feed reader app.



Create a starting C++Builder for iOS mobile app using File | New | FireMonkey Mobile Application -  C++Builder. Add the TIdHTTP and TXMLDocument components to the form. Add a TabControl and add 3 TabItems to the TabControl. Set the Text properties for each of the TabItems to "isocpp.org", "Embarcadero blogs" and "Browser". Set the StyleLookup property for each of the TabItems to  "tabitemmostviewed", "tabitemfavorites" and "tabitembookmarks" (These were my choices, you can choose whatever styles/icons you want to use). The 3 TabItems will be used for two RSS feeds (isocpp.org and blogs.embarcadero.com) and the TWebBrowser display.

For the first 2 TabItems, add 2 two Toolbars to each. Align one (the header) to the top (Align property - alTop) and one (the footer) to the bottom (Align property = alBottom). Add a label (to identify the TabItem we are using)  and a speed button (used for loading and refreshing the RSS feed) to the header toolbars.  Set the SpeedButton's StyleLookup property to "refreshtoolbuttonbordered". Add a label to the two footer toolbars (I use these for status messages and also to contain the URL link for a selected RSS feed item in the ListBox. Add a TListBox to both of the first two TabItems. These will contain the RSS feed items that are returned from the two websites. On the third TabItem, add a TWebBrowser component. Set its alignment to the entire client area (Align property = alClient). Depending on the Name property settings you use your Structure Window should look like the following bitmap.

When you add the TXMLDocument component, make sure to set the DOMVendor property to the ADOM XML choice (and not the MSXML choice). There is a tip in the Embarcadero DocWiki if you are using XMLDocument in a Mac OS X or mobile application: "Tip: To use TXMLDocument in Mac OS X or Mobile applications, in the Object Inspector, set the DOMVendor property to ADOM XML v4 right after dropping this component onto the Form Designer. Otherwise, the TXMLDocument component is no longer usable for iOS/Android/OSX applications."



After you have completed the UI steps above your C++ iOS app 3 TabItems should look like the following bitmaps.



To make the C++ for iOS magic happen we need to write a little bit of code. For each of the two TSpeedButton components, use the Object Inspector and create one onClick event handler that is shared for both speed buttons. My code will use the text for each of the TabItems to know which RSS feed to process.
void __fastcall TForm5::FeedButtonClick(TObject *Sender)
{
// here is where the code will go to take a feed URL, use TIdHTTP
// to get the resulting XML string and then use XMLDocument
// to parse the feed, populate the listbox for that feed
}

Most of the code for the SpeedButton onClick event handler uses TIdHTTP to get the XML RSS feed string, use XMLDocument and ADOM XML to parse it and finally navigate through the XML to find the Title, Author (if there is one), Date and URL for each item. Different RSS feeds use different tags, so some of the code is dependent on the specific feed. For example, isocpp.org does not have an author tag. For the date of the article, isocpp.org uses a "date" tag and embarcadero blogs uses a "pubdate" tag. You'll see this special case code in the OnClick event handler below.

Here is the code to set up some variables for each of the two feeds:
	// I am using the TabItem text to know which feed to process
if (TabControlMain->ActiveTab->Text == "isocpp.org") {
strUrl = "http://isocpp.org/blog/rss";
TargetList = ListBoxCpp;
LabelStatus = LabelStatusC;
feedIndex = 0;
}
else {
strUrl = "http://blogs.embarcadero.com/feeds/wpmu-feed/";
TargetList = ListBoxEmbt;
LabelStatus = LabelStatusE;
feedIndex = 1;
}

The next 3 lines contain the code to get the RSS XML string and activate the XMLDocument component to parse it.
		String strXml = IdHTTP1->Get(strUrl);
XMLDocument1->LoadFromXML(strXml);
XMLDocument1->Active = True;

The rest of the OnClick event handler finds the "channel" child node within the DocumentElement, looks for "item" child nodes for each of the articles and populates the TabItem's ListBox with the article information. Notice that I have to do some special handling in each of the feeds for author and date. Other RSS feeds may use different tags and you'll need to do your own work to handle those tags. At least the XMLDocument component and interface allows common navigation through the RSS Feed string.
		IXMLNode *ChannelNode = XMLDocument1->DocumentElement->ChildNodes->FindNode("channel");
for (int I = 0; I < ChannelNode->ChildNodes->Count; I++) {
IXMLNode *ItemNode = ChannelNode->ChildNodes->Get(I);
if (ItemNode->NodeName == "item") {
LabelStatus->Text = "Processing Node " + IntToStr(I);
String title = ItemNode->ChildValues["title"];
// handle specific tags for author and date in each feed
switch (feedIndex) {
case 0: // isocpp.org
// author = ItemNode->ChildValues["author"];
author = ""; // the isocpp.org feed does not have an author tag
pubDate = ItemNode->ChildValues["date"];
break;
case 1: // blogs.embarcadero.com
author = ItemNode->ChildValues["creator"];
pubDate = ItemNode->ChildValues["pubDate"];
break;
default:
;
}
String url = ItemNode->ChildValues["link"];
ListBoxItem = new TListBoxItem(TargetList);
ListBoxItem->Text = title;
ListBoxItem->ItemData->Detail = author
+ " - "
+ pubDate;
ListBoxItem->TagString = url; //stash the URL in the ListBoxItem's TagString
TargetList->AddObject(ListBoxItem);
}
}
TargetList->EndUpdate();
LabelStatus->Text = "RSS Processed";
LabelStatus->Repaint();
}
// catch any error that might happen getting the RSS feed
catch(Exception& e) {
ShowMessage("Error: " + e.Message);
}

Now that we have the code to populate the ListBoxes for each feed, you'll create an OnItemClick event handler for each list using the Object Inspector. When I created each ListBox item above, I stored the article URL in the TagString for each ListBox item. In the OnClick handler I retrieve the URL from the TagString and use the TWebBrowser Navigate method to display the article page and activate the Browser TabItem. The code for the event handlers is included below.
void __fastcall TForm5::ListBoxEmbtItemClick(const TCustomListBox *Sender, const TListBoxItem *Item)
{
// display selected Embarcadero Blog URL
LabelStatusE->Text = Item->TagString;
WebBrowser1->Navigate(Item->TagString);
TabControlMain->ActiveTab = BrowserTabItem;
}

void __fastcall TForm5::ListBoxCppItemClick(const TCustomListBox *Sender, const TListBoxItem *Item)
{
// display selected isocpp.org URL
LabelStatusC->Text = Item->TagString;
WebBrowser1->Navigate(Item->TagString);
TabControlMain->ActiveTab = BrowserTabItem;
}

One final piece of code is in the FormCreate event handler. This line of code makes sure that the first TabItem (isocpp.org) is the TabControl ActiveTab. When you are working in the designer on different tab items, the TabControl will have the ActiveTab set to whatever TabItem you activated. To make sure that the app starts at the TabItem you want, I always include this line of code. Then I don't have to always remind myself to set the first Tab active.
void __fastcall TForm5::FormCreate(TObject *Sender)
{
TabControlMain->ActiveTab = TabCppFeed;
}

Here is the Project Window for my app:



I've uploaded the complete project to CodeCentral. You can download it using the the http://cc.embarcadero.com/item/29705 link.

Here are 3 screen shots from my app running on my iPhone 4s.



Using C++Builder XE5 Update 2, you can build cool desktop and mobile C++ apps fast. Have fun building multi-device apps with C++Builder and iOS!


About
Gold User, Rank: 1, Points: 2466
David Intersimone (known to many as David I.) is a passionate and innovative software industry veteran-often referred to as a developer icon-who extols and educates the world on Embarcadero developer tools. He shares his visions as an active member of the industry speaking circuit and is tapped as an expert source by the media. He is a long-standing champion of architects, developers and database professionals and works to ensure that their needs are folded into Embarcadero's strategic product plans. David holds a bachelor's degree in computer science from California Polytechnic State University at San Luis Obispo, California.

Comments

  • Guest
    Remy Lebeau Wednesday, 29 January 2014

    Good article. My only advice would be to use the overloaded version of TIdHTTP::Get() that retrieves to a TStream and then use TXMLDocument::LoadFromStream(). This way, the raw XML as provided by the server is parsed as-is, it does not have to be decoded to a UTF-16 String first, which would double (even triple, albeit temporarily) the amount of memory used, and be subject to charset processing issues, before TXMDocument even has a chance to see it.

  • Guest
    Lena Wednesday, 29 January 2014

    Thank you for the good article!

  • Guest
    David Intersimone Wednesday, 29 January 2014

    Remy - thanks for the great tip. I will make the change, test it and update the codecentral download and article :)

  • Please login first in order for you to submit comments
  • Page :
  • 1

Check out more tips and tricks in this development video: