org.symbian.tools.wrttools.doc.WRTKit/html/WRTKit_Travel_Companion_functionality-GUID-384f2430-3de9-4006-ac8e-86c5774c3a79.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/org.symbian.tools.wrttools.doc.WRTKit/html/WRTKit_Travel_Companion_functionality-GUID-384f2430-3de9-4006-ac8e-86c5774c3a79.html Fri Mar 05 19:31:41 2010 -0800
@@ -0,0 +1,854 @@
+<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html lang="en" xml:lang="en">
+<head>
+<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
+<meta name="copyright" content="(C) Copyright 2005" />
+<meta name="DC.rights.owner" content="(C) Copyright 2005" />
+<meta content="concept" name="DC.Type" />
+<meta name="DC.Title" content="Functionality" />
+<meta scheme="URI" name="DC.Relation" content="WRTKit_Travel_Companion_Tutorial-GUID-be79ba64-fa03-4968-964e-d7dcc42d7053.html" />
+<meta content="XHTML" name="DC.Format" />
+<meta content="GUID-384F2430-3DE9-4006-AC8E-86C5774C3A79" name="DC.Identifier" />
+<meta content="en" name="DC.Language" />
+<link href="commonltr.css" type="text/css" rel="stylesheet" />
+<title>
+Functionality</title>
+</head>
+<body id="GUID-384F2430-3DE9-4006-AC8E-86C5774C3A79"><a name="GUID-384F2430-3DE9-4006-AC8E-86C5774C3A79"><!-- --></a>
+
+
+
+ <h1 class="topictitle1">
+Functionality</h1>
+
+ <div>
+
+ <div class="section"><h2 class="sectiontitle">
+Weather forecast</h2>
+
+
+ <p>
+
+ Let's continue by implementing the weather forecast view. This view will
+ be entirely composed of non-foldable ContentPanel controls. We'll have one
+ panel that displays the city for which the forecast is for and one panel
+ for each day of the five-day forecast. In order to make it easy to change
+ the number of days the forecast is for we'll store references to the forecast
+ panels in an array. Thus, we need to add two global variables to the widget:
+ </p>
+
+<pre>
+
+// Weather view controls.
+var weatherCityPanel;
+var weatherContentPanels;
+</pre>
+
+ <p>
+
+ The next step is to create the actual view in the createWeatherView() function.
+ Of course the actual content for the content panels won't be known until at
+ runtime when we know what city the forecast is for and what the actual weather
+ forecast is. Still, we can create the actual content panels and just set their
+ content later so this is not a problem.
+ </p>
+
+<pre>
+
+// Creates the weather view.
+function createWeatherView() {
+ // empty caption text to display the caption bar - custom background using CSS
+ weatherView = new ListView(null, "");
+
+ // heading panel for city
+ weatherCityPanel = new ContentPanel();
+ weatherView.addControl(weatherCityPanel);
+
+ // create five content panels - one for each day in the 5-day forecast
+ weatherContentPanels = [];
+ for (var i = 0; i < 5; i++) {
+ var weatherContentPanel = new ContentPanel();
+ weatherView.addControl(weatherContentPanel)
+ weatherContentPanels.push(weatherContentPanel);
+ }
+}
+</pre>
+
+ <p>
+
+ When we show the weather view we have to check what the current local city
+ is and set the weatherCityPanel's content to a suitable HTML fragment that
+ will work as a heading for the weather forecast. In addition to that we'll
+ have to retrieve the weather forecast from the business logic engine and then
+ create HTML from that for each day in the forecast and set it to the five
+ content panels that we are storing references to in the weatherContentPanels
+ array. The caption for the weather forecast panels will be a string that
+ indicates the day that the forecast is for.
+ </p>
+
+ <p>
+
+ Creating the HTML fragment for the forecast heading doesn't sound so hard
+ but generating HTML for a weather forecast for five days sounds a bit tricky.
+ Let's create a separate function to do that. Remember that the weather object
+ that the engine is returning to us has two properties: temperature and type.
+ The temperature is in the preferred temperature unit and the type is one of
+ the type codes, e.g. "Sunny". We'll use it to match it up with a weather icon.
+ </p>
+
+<pre>
+
+// Returns HTML for one day of weather forecast.
+function getHTMLForWeather(weather) {
+ // build weather icon file name string
+ var weatherIcon = "Weather" + weather.type + ".png";
+
+ // build temperature string
+ var temperatureStr = weather.temperature + "&deg;" + engine.getTemperatureUnit().toUpperCase();
+
+ // build weather HTML
+ var weatherBuf = "";
+ weatherBuf += "<table class=\"WeatherForecastDayTable\"><tr>";
+ weatherBuf += "<td class=\"WeatherForecastIconCell\">";
+ weatherBuf += "<img src=\"" + weatherIcon + "\"/>";
+ weatherBuf += "</td>";
+ weatherBuf += "<td class=\"WeatherForecastTemperatureCell\">";
+ weatherBuf += temperatureStr;
+ weatherBuf += "</td>";
+ weatherBuf += "</tr></table>";
+
+ return weatherBuf;
+}
+</pre>
+
+ <p>
+
+ The HTML that we are generating is a table with a single row with two cells.
+ The left cell has the weather icon image and the right cell has the temperature.
+ We are using three CSS style rules for the table and we naturally need to create
+ those too in the TravelCompanion.css file:
+ </p>
+
+<pre>
+
+/* Table for one day of weather forecast information */
+.WeatherForecastDayTable {
+ margin: auto;
+ border-spacing: 0px;
+}
+
+/* Table cell for weather icon */
+.WeatherForecastIconCell {
+ line-height: 1px;
+ font-size: 1px;
+ vertical-align: middle;
+}
+
+/* Table cell for temperature information */
+.WeatherForecastTemperatureCell {
+ padding: 0px 0px 0px 10px;
+ vertical-align: middle;
+}
+</pre>
+
+ <p>
+
+ Now we have a way to turn a weather forecast into HTML that we can use in a
+ ContentPanel control. We'll do that in a function we call updateWeatherForecast().
+ The caption for each weather forecast panel will indicate the day that the
+ forecast is for. The first weather object in the array that the engine returns
+ is for today and the subsequent ones are for coming days.
+ </p>
+
+<pre>
+
+// Updates the weather forecast.
+function updateWeatherForecast() {
+ // get local time and weather
+ var localTime = engine.getLocalTime();
+ var localWeather = engine.getLocalWeather();
+
+ // set the weather for each day in the forecast
+ for (var i = 0; i < 5; i++) {
+ // figure out day name
+ var day = (localTime.day + i) % 7;
+ var dayName = localTime.dayNames[day];
+
+ // set weather to content panel
+ weatherContentPanels[i].setCaption((i == 0 ? "Today, " : "") + dayName);
+ weatherContentPanels[i].setContent(getHTMLForWeather(localWeather[i]));
+ }
+}
+</pre>
+
+ <p>
+
+ We are now ready to implement the showWeatherView() function:
+ </p>
+
+<pre>
+
+// Displays the weather view.
+function showWeatherView() {
+ // set heading city panel
+ weatherCityPanel.setContent("<div class=\"WeatherCityPanel\">" + engine.getLocalCity().name + " 5-day Forecast("</div>");
+
+ // update the weather forecast before showing the view
+ updateWeatherForecast();
+
+ setSubViewSoftkeys();
+ uiManager.setView(weatherView);
+}
+</pre>
+
+ <p>
+
+ The weatherCityPanel gets a heading that matches the currently configured local city.
+ We're using another CSS rule for that so we'll have to add it to our stylesheet:
+ </p>
+
+<pre>
+
+/* City heading panel for weather forecast view */
+.WeatherCityPanel {
+ font-size: 14px;
+ font-weight: bold;
+ padding: 0px 0px 10px 0px;
+}
+</pre>
+
+ <p>
+
+ The weather forecast view and functionality is now ready to be tested.
+ </p>
+
+ </div>
+
+ <div class="section"><h2 class="sectiontitle">
+Currency converter</h2>
+
+
+ <p>
+
+ It's time to move on to the currency converter. This view is going to have two
+ TextField controls. One for home currency and one for local currency. In addition
+ there will be two FormButton controls to convert from the home currency to the
+ local currency, and vice versa. We'll need references to the textfields so that
+ we can retrieve their values when the form buttons are pressed:
+ </p>
+
+<pre>
+
+// Converter view controls.
+var homeMoneyField;
+var localMoneyField;
+</pre>
+
+ <p>
+
+ Creating the view is quite straight forward:
+ </p>
+
+<pre>
+
+// Creates the converter view.
+function createConverterView() {
+ // empty caption text to display the caption bar - custom background using CSS
+ converterView = new ListView(null, "");
+
+ // home money
+ homeMoneyField = new TextField();
+ converterView.addControl(homeMoneyField);
+
+ // local money
+ localMoneyField = new TextField();
+ converterView.addControl(localMoneyField);
+
+ // home to local
+ var homeToLocalButton = new FormButton(null, "Convert Home to Local");
+ converterView.addControl(homeToLocalButton);
+
+ // local to home
+ var localToHomeButton = new FormButton(null, "Convert Local to Home");
+ converterView.addControl(localToHomeButton);
+}
+</pre>
+
+ <p>
+
+ Notice that the textfields don't have any caption or text at this point. We will
+ set that just before the view is displayed because the caption will depend on
+ what the home and local cities are configured to.
+ </p>
+
+ <p>
+
+ Also notice that we don't have any event listeners for the buttons at this point.
+ That's because we haven't actually written any functions that will implement
+ the currency conversion yet. But before we do that we'll implement the
+ function to show the view:
+ </p>
+
+<pre>
+
+// Displays the converter view.
+function showConverterView() {
+ // set captions and reset fields
+ homeMoneyField.setCaption("Home Currency (" + engine.getHomeCity().currency + ")");
+ homeMoneyField.setText("");
+ localMoneyField.setCaption("Local Currency (" + engine.getLocalCity().currency + ")");
+ localMoneyField.setText("");
+
+ setSubViewSoftkeys();
+ uiManager.setView(converterView);
+}
+</pre>
+
+ <p>
+
+ You can now test the view but it won't actually convert any currency until
+ we give our form buttons event listeners and write the code that will be
+ called when the buttons are pressed.
+ </p>
+
+ <p>
+
+ We'll implement that in two functions. One to convert from home to local and
+ another to convert in the other direction. The functions take the current
+ text value from the corresponding field and then pass it to the engine to do
+ the conversion. The result is then placed in the other of the two fields,
+ formatted so that the result has exactly two digits.
+ </p>
+
+<pre>
+
+// Called when the user clicks on the "convert home to local" button
+// in the converter view. (rounds to two decimals)
+function convertHomeToLocalMoney() {
+ var homeMoney = parseFloat(homeMoneyField.getText());
+ var localMoney = engine.convertHomeToLocalMoney(homeMoney).toFixed(2);
+ localMoneyField.setText(localMoney);
+}
+
+// Called when the user clicks on the "convert local to home" button
+// in the converter view. (rounds to two decimals)
+function convertLocalToHomeMoney() {
+ var localMoney = parseFloat(localMoneyField.getText());
+ var homeMoney = engine.convertLocalToHomeMoney(localMoney).toFixed(2);
+ homeMoneyField.setText(homeMoney);
+}
+</pre>
+
+ <p>
+
+ Now that the functions are implemented we can add the event listeners to our
+ form buttons. We'll add this code right after where the buttons are created in
+ the createConverterView() function:
+ </p>
+
+<pre>
+
+homeToLocalButton.addEventListener("ActionPerformed", convertHomeToLocalMoney);
+localToHomeButton.addEventListener("ActionPerformed", convertLocalToHomeMoney);
+</pre>
+
+ <p>
+
+ The currency converter is now working and it's time to test it. Try it with
+ different currencies by changing the home and local cities in the settings view.
+ </p>
+
+ <div class="fignone" id="GUID-384F2430-3DE9-4006-AC8E-86C5774C3A79__GUID-D5A1648B-B81D-46B0-A15F-C3C8FF2185D7"><a name="GUID-384F2430-3DE9-4006-AC8E-86C5774C3A79__GUID-D5A1648B-B81D-46B0-A15F-C3C8FF2185D7"><!-- --></a><span class="figcap">Figure 1.
+Travel Companion converter view</span>
+
+
+ <br /><img src="Travel_Companion_Converter_Screenshot_1.png" /><br />
+ </div>
+
+ </div>
+
+ <div class="section"><h2 class="sectiontitle">
+Information view</h2>
+
+
+ <p>
+
+ The information view is a summary of relevant information that the user is
+ will often need. Here we'll have a world clock that shows the home and local
+ time, the current weather at home and in the local city, as well as the
+ latest news headlines. We will use ContentPanel controls for all of these.
+ One for the home time, one for the local time, one for the home weather, one
+ for the local weather, and one for all the news headlines.
+ </p>
+
+ <p>
+
+ We'll need to access all of these content panels from outside the view creation
+ function so we'll need global variables to hold references to them:
+ </p>
+
+<pre>
+
+// Info view controls.
+var homeCityTimePanel;
+var localCityTimePanel;
+var homeCityWeatherPanel;
+var localCityWeatherPanel;
+var newsHeadlinesPanel;
+</pre>
+
+ <p>
+
+ We can now proceed and actually implement the creation of the information view:
+ </p>
+
+<pre>
+
+// Creates the info view.
+function createInfoView() {
+ // empty caption text to display the caption bar - custom background using CSS
+ infoView = new ListView(null, "");
+
+ // home city time
+ homeCityTimePanel = new ContentPanel();
+ infoView.addControl(homeCityTimePanel);
+
+ // local city time
+ localCityTimePanel = new ContentPanel();
+ infoView.addControl(localCityTimePanel);
+
+ // separator
+ infoView.addControl(new Separator());
+
+ // home city weather
+ homeCityWeatherPanel = new ContentPanel();
+ infoView.addControl(homeCityWeatherPanel);
+
+ // local city weather
+ localCityWeatherPanel = new ContentPanel();
+ infoView.addControl(localCityWeatherPanel);
+
+ // separator
+ infoView.addControl(new Separator());
+
+ // news headlines
+ newsHeadlinesPanel = new ContentPanel();
+ infoView.addControl(newsHeadlinesPanel);
+}
+</pre>
+
+ <p>
+
+ We already have a function that turns a weather forecast into HTML but we
+ don't have similar functions for time or for news headlines. We'll need
+ that when we want to put content into the time and headline content panels
+ so let's write those functions next.
+ </p>
+
+ <p>
+
+ For time we'll need a function that takes a DateTime object and returns
+ HTML that we can use in the content panel in the information view.
+ </p>
+
+<pre>
+
+// Returns HTML for time.
+function getHTMLForTime(time) {
+ // build HTML buffer
+ var timeBuf = "";
+ timeBuf += "<div class=\"Clock\">";
+ timeBuf += time.hours + ":" + (time.minutes < 10 ? "0" : "") + time.minutes;
+ timeBuf += "</div>";
+ return timeBuf;
+}
+</pre>
+
+ <p>
+
+ The HTML uses a CSS rule that we'll have to define in our stylesheet:
+ </p>
+
+<pre>
+
+/* Clock div */
+.Clock {
+ text-align: center;
+ font-size: 16px;
+ font-weight: bold;
+}
+</pre>
+
+ <p>
+
+ Next up is the function for turning the latest news headlines into HTML.
+ For each news headline we'll generate a div that contains the actual
+ news headline plus a link to the website where the full news article is.
+ Opening URLs should be done using the widget.openURL() method in the
+ S60 Web Runtime but since we don't have that functionality in a PC browser
+ we'll write a wrapper for the function just like we did for the RSS Reader:
+ </p>
+
+<pre>
+
+// Opens a URL.
+function openURL(url) {
+ if (window.widget) {
+ // in WRT
+ widget.openURL(url);
+ } else {
+ // outside WRT
+ window.open(url, "NewWindow");
+ }
+}
+</pre>
+
+ <p>
+
+ Now we can implement the function that turns news headlines into HTML:
+ </p>
+
+<pre>
+
+// Returns HTML for news headlines.
+function getHTMLForNewsHeadlines(newsHeadlines) {
+ var newsBuf = "";
+ for (var i = 0; i < newsHeadlines.length; i++) {
+ newsBuf += "<div class=\"NewsHeadline\">";
+ newsBuf += newsHeadlines[i].headline + "<br/>";
+ newsBuf += "<a href=\"JavaScript:openURL('" + newsHeadlines[i].url + "');\">";
+ newsBuf += "Read more...";
+ newsBuf += "</a>";
+ newsBuf += "</div>";
+ }
+ return newsBuf;
+}
+</pre>
+
+ <p>
+
+ The div that encloses each news headline uses a CSS rule called NewsHeadline.
+ As with all other CSS rules that we use we'll define this one too in
+ the TravelCompanion.css stylesheet file. We also need to add rules for what
+ links should look like in the context of a news headline. We define the link
+ as bold underlined blue text in its normal state and inverse with blue background
+ and white text when focused.
+ </p>
+
+<pre>
+
+/* News headline */
+.NewsHeadline {
+ padding: 0px 0px 10px 0px;
+}
+
+/* Anchor tags in the context of a news headline link */
+.NewsHeadline a {
+ text-decoration: underline;
+ font-weight: bold;
+ color: rgb(0,0,255);
+}
+
+/* Focused anchor tags */
+.NewsHeadline a:focus {
+ background: rgb(0,0,255);
+ color: rgb(255,255,255);
+}
+</pre>
+
+ <p>
+
+ Now we should have everything we need to be able to update the information
+ view content panels when the view is shown. It's time to implement the
+ showInfoView() function:
+ </p>
+
+<pre>
+
+// Displays the info view.
+function showInfoView() {
+ // set current information to controls
+ var homeCity = engine.getHomeCity();
+ var localCity = engine.getLocalCity();
+
+ // set time
+ var homeTime = engine.getHomeTime();
+ var localTime = engine.getLocalTime();
+ homeCityTimePanel.setCaption(homeCity.name + " Time");
+ homeCityTimePanel.setContent(getHTMLForTime(homeTime));
+ localCityTimePanel.setCaption(localCity.name + " Time");
+ localCityTimePanel.setContent(getHTMLForTime(localTime));
+
+ // set weather
+ var homeWeather = engine.getHomeWeather();
+ var localWeather = engine.getLocalWeather();
+ homeCityWeatherPanel.setCaption(homeCity.name + " Weather");
+ homeCityWeatherPanel.setContent(getHTMLForWeather(homeWeather[0]));
+ localCityWeatherPanel.setCaption(localCity.name + " Weather");
+ localCityWeatherPanel.setContent(getHTMLForWeather(localWeather[0]));
+
+ // set headline
+ var newsHeadlines = engine.getNewsHeadlines();
+ newsHeadlinesPanel.setCaption("News Headlines");
+ newsHeadlinesPanel.setContent(getHTMLForNewsHeadlines(newsHeadlines));
+
+ setSubViewSoftkeys();
+ uiManager.setView(infoView);
+}
+</pre>
+
+ <p>
+
+ If you try the view now, everything will seem to work fine. But there
+ is a big problem! We set the content in the content panels when the
+ view is shown but if we stay in the view for an hour the clocks will
+ still show the same time as when we showed the view. What's worse, it's
+ not just the information view that has this problem. The weather forecast
+ view is equally broken.
+ </p>
+
+ </div>
+
+ <div class="section"><h2 class="sectiontitle">
+Updating views with a timer</h2>
+
+
+ <p>
+
+ In order to keep the views up to date we'll need to start a timer that
+ periodically calls a function where we examine whether it's been long
+ enough since the last update of a view that it's time to update the
+ content in that view. Note that we only need to update a view using the
+ timer if the view is actually visible.
+ </p>
+
+ <p>
+
+ That sounds good at first but some things have to be updated more
+ frequently than others. The clocks in our information view have to not
+ only be updated once a minute but immediately when the minute changes.
+ Such accuracy is not needed for the weather forecasts or news headlines.
+ For them it's fine if they are updated once per hour. Except that weather
+ forecasts also have to be updated when the day rolls over to the next as
+ otherwise the forecast will show the wrong day. Because the home and local
+ cities can be in different timezones their days will roll over at
+ different times and thus we have to track these separately.
+ </p>
+
+ <p>
+
+ It turns out that we need no less than five variables to track this.
+ We need one to track the last minute that has been updated to the clocks,
+ one variable is needed to track when the weather was last updated, one
+ to track the day in the home city when the home city weather forecast
+ was updated, one to track the same but for the local city, and one to
+ track when the news headlines were updated. Let's declare those variables
+ and initialize them:
+ </p>
+
+<pre>
+
+// Tracks last updated minute on the clocks.
+var lastUpdatedClockMinute = -1;
+
+// Tracks last update time for weather.
+var weatherLastUpdated = -1;
+
+// Tracks the days when the weather was last updated.
+var lastUpdatedHomeWeatherDay = -1;
+var lastUpdatedLocalWeatherDay = -1;
+
+// Tracks last update time for news headlines.
+var newsHeadlinesLastUpdated = -1;
+</pre>
+
+ <p>
+
+ We'll use the time in millieconds to remember update times and compare
+ how long it's been since an update happened. Since we'll use this quite
+ a lot, let's create a small helper function for it:
+ </p>
+
+<pre>
+
+// Returns the current time in milliseconds.
+function getTimeMillis() {
+ return new Date().getTime();
+}
+</pre>
+
+ <p>
+
+ When we show a view we have to update the appropriate tracking variables
+ so the widget will properly keep track of when a view was updated. That
+ means that we have to add the following to just before we show the
+ information view in showInfoView():
+ </p>
+
+<pre>
+
+// update the tracking variables
+lastUpdatedClockMinute = homeTime.minutes;
+weatherLastUpdated = getTimeMillis();
+lastUpdatedHomeWeatherDay = homeTime.day;
+lastUpdatedLocalWeatherDay = localTime.day;
+newsHeadlinesLastUpdated = getTimeMillis();
+</pre>
+
+ <p>
+
+ In the same way the showWeatherView() function needs the following addition:
+ </p>
+
+<pre>
+
+// update the tracking variables
+weatherLastUpdated = getTimeMillis();
+lastUpdatedLocalWeatherDay = engine.getLocalTime().day;
+</pre>
+
+ <p>
+
+ Now our tracking variables should be updated to the right times whenever views
+ are shown but we still don't have a timer to handle the automatic updating
+ of the views.
+ </p>
+
+ <p>
+
+ We'll set this timer up so that the timer callback function is called once
+ every second so that we can make sure that the clocks don't fall behind. We'll
+ track the timer identifier in a variable:
+ </p>
+
+<pre>
+
+// View updating timer identifier.
+var timerId;
+</pre>
+
+ <p>
+
+ We'll make the timer call a function called updateViews() that we will
+ create shortly but first let's start the timer as the last thing in the
+ init() function:
+ </p>
+
+<pre>
+
+// start timer that keeps views up to date
+timerId = setInterval(updateViews, 1000);
+</pre>
+
+ <p>
+
+ The updateViews() function needs to check what view we are currently in and do
+ the appropriate checks depending on the view. If we're in the information view
+ then we have three things to check. The first thing is to check if the minute
+ has changed on the clock. The second is to check if it's been over 60 minutes
+ since the weather was updated or if either the home or local city has rolled
+ over to the next day. And finally the third to thing to check is if it's been
+ over 60 minutes since the news headlines were updated.
+ </p>
+
+ <p>
+
+ If we are in the weather view then we check if it's been over 60 minutes since
+ the weather was updated or if the local city has rolled over to the next day.
+ Note that the weather forecast view only displays the local weather forecast
+ so we don't have to check for if the home city has rolled over to the next day.
+ </p>
+
+ <p>
+
+ The implementation of the function is therefore as follows:
+ </p>
+
+<pre>
+
+// Timer callback function that gets called once every second to keep views up to date.
+function updateViews() {
+
+ // get the current view
+ var currentView = uiManager.getView();
+
+ // get home and local time as well as time in milliseconds
+ var homeTime = engine.getHomeTime();
+ var localTime = engine.getLocalTime();
+ var now = getTimeMillis();
+
+ if (currentView == infoView) {
+ // only update the clocks if the minute has changed
+ if (homeTime.minutes != lastUpdatedClockMinute) {
+ lastUpdatedClockMinute = homeTime.minute;
+ homeCityTimePanel.setContent(getHTMLForTime(homeTime));
+ localCityTimePanel.setContent(getHTMLForTime(localTime));
+ }
+
+ // update weather if it hasn't been updated in the last hour or if the day has changed
+ if ((now > weatherLastUpdated + (1000 * 60 * 60)) ||
+ (homeTime.day != lastUpdatedHomeWeatherDay) ||
+ (localTime.day != lastUpdatedLocalWeatherDay)) {
+ weatherLastUpdated = now;
+ lastUpdatedHomeWeatherDay = homeTime.day;
+ lastUpdatedLocalWeatherDay = localTime.day;
+ var homeWeather = engine.getHomeWeather();
+ var localWeather = engine.getLocalWeather();
+ homeCityWeatherPanel.setContent(getHTMLForWeather(homeWeather[0]));
+ localCityWeatherPanel.setContent(getHTMLForWeather(localWeather[0]));
+ }
+
+ // update news headlines if they haven't been updated in the last hour
+ if (now > newsHeadlinesLastUpdated + (1000 * 60 * 60)) {
+ newsHeadlinesLastUpdated = now;
+ var newsHeadlines = engine.getNewsHeadlines();
+ newsHeadlinesPanel.setContent(getHTMLForNewsHeadlines(newsHeadlines));
+ }
+ } else if (currentView == weatherView) {
+ // update weather if it hasn't been updated in the last hour or if the day has changed
+ if ((now > weatherLastUpdated + (1000 * 60 * 60)) ||
+ (localTime.day != lastUpdatedLocalWeatherDay)) {
+ weatherLastUpdated = now;
+ lastUpdatedLocalWeatherDay = localTime.day;
+ updateWeatherForecast();
+ }
+ }
+}
+</pre>
+
+ <div class="fignone" id="GUID-384F2430-3DE9-4006-AC8E-86C5774C3A79__GUID-CBE870F8-DE6F-47D9-BE2B-F7D756DC8A40"><a name="GUID-384F2430-3DE9-4006-AC8E-86C5774C3A79__GUID-CBE870F8-DE6F-47D9-BE2B-F7D756DC8A40"><!-- --></a><span class="figcap">Figure 2.
+Travel Companion information view</span>
+
+
+ <br /><img src="Travel_Companion_Info_Screenshot_1.png" /><br />
+ </div>
+
+ </div>
+
+ <div class="section"><h2 class="sectiontitle">
+What we have learned</h2>
+
+
+ <p>
+
+ The Travel Companion widget is now completed! We have learned to implement
+ complex widgets with multiple views using the WRTKit. We have also learned
+ how to keep information in views up to date using a timer. And we implemented
+ the widget without any dependencies to how the business logic engine was
+ implemented. That will come in handy if you want to continue developing this
+ widget by substituting the mock engine with one that actually uses real
+ world data. You are now ready to tackle any challenge using the WRTKit!
+ </p>
+
+ </div>
+
+ </div>
+
+<div>
+<div class="familylinks">
+<div class="parentlink"><strong>Parent topic:</strong> <a href="WRTKit_Travel_Companion_Tutorial-GUID-be79ba64-fa03-4968-964e-d7dcc42d7053.html">Travel Companion</a></div>
+</div>
+</div>
+
+</body>
+</html>
\ No newline at end of file