org.symbian.wrttools.doc.WRTKit/html/WRTKit_Travel_Companion_functionality-GUID-384f2430-3de9-4006-ac8e-86c5774c3a79.html
changeset 230 7848c135d915
parent 229 716254ccbcc0
child 231 611be8d22832
equal deleted inserted replaced
229:716254ccbcc0 230:7848c135d915
     1 <?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">
       
     2 <html lang="en" xml:lang="en">
       
     3 <head>
       
     4 <meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
       
     5 <meta name="copyright" content="(C) Copyright 2005" />
       
     6 <meta name="DC.rights.owner" content="(C) Copyright 2005" />
       
     7 <meta content="concept" name="DC.Type" />
       
     8 <meta name="DC.Title" content="Functionality" />
       
     9 <meta scheme="URI" name="DC.Relation" content="WRTKit_Travel_Companion_Tutorial-GUID-be79ba64-fa03-4968-964e-d7dcc42d7053.html" />
       
    10 <meta content="XHTML" name="DC.Format" />
       
    11 <meta content="GUID-384F2430-3DE9-4006-AC8E-86C5774C3A79" name="DC.Identifier" />
       
    12 <meta content="en" name="DC.Language" />
       
    13 <link href="commonltr.css" type="text/css" rel="stylesheet" />
       
    14 <title>
       
    15 Functionality</title>
       
    16 </head>
       
    17 <body id="GUID-384F2430-3DE9-4006-AC8E-86C5774C3A79"><a name="GUID-384F2430-3DE9-4006-AC8E-86C5774C3A79"><!-- --></a>
       
    18 
       
    19 
       
    20 
       
    21     <h1 class="topictitle1">
       
    22 Functionality</h1>
       
    23 
       
    24     <div>
       
    25 
       
    26         <div class="section"><h2 class="sectiontitle">
       
    27 Weather forecast</h2>
       
    28 
       
    29             
       
    30             <p>
       
    31 
       
    32                 Let's continue by implementing the weather forecast view. This view will
       
    33                 be entirely composed of non-foldable ContentPanel controls. We'll have one
       
    34                 panel that displays the city for which the forecast is for and one panel
       
    35                 for each day of the five-day forecast. In order to make it easy to change
       
    36                 the number of days the forecast is for we'll store references to the forecast
       
    37                 panels in an array. Thus, we need to add two global variables to the widget:
       
    38             </p>
       
    39 
       
    40 <pre>
       
    41 
       
    42 // Weather view controls.
       
    43 var weatherCityPanel;
       
    44 var weatherContentPanels;
       
    45 </pre>
       
    46 
       
    47             <p>
       
    48 
       
    49                 The next step is to create the actual view in the createWeatherView() function.
       
    50                 Of course the actual content for the content panels won't be known until at
       
    51                 runtime when we know what city the forecast is for and what the actual weather
       
    52                 forecast is. Still, we can create the actual content panels and just set their
       
    53                 content later so this is not a problem.
       
    54             </p>
       
    55 
       
    56 <pre>
       
    57 
       
    58 // Creates the weather view.
       
    59 function createWeatherView() {
       
    60     // empty caption text to display the caption bar - custom background using CSS
       
    61     weatherView = new ListView(null, "");
       
    62     
       
    63     // heading panel for city
       
    64     weatherCityPanel = new ContentPanel();
       
    65     weatherView.addControl(weatherCityPanel);
       
    66     
       
    67     // create five content panels - one for each day in the 5-day forecast
       
    68     weatherContentPanels = [];
       
    69     for (var i = 0; i &lt; 5; i++) {
       
    70         var weatherContentPanel = new ContentPanel();
       
    71         weatherView.addControl(weatherContentPanel)
       
    72         weatherContentPanels.push(weatherContentPanel);
       
    73     }
       
    74 }
       
    75 </pre>
       
    76 
       
    77             <p>
       
    78 
       
    79                 When we show the weather view we have to check what the current local city
       
    80                 is and set the weatherCityPanel's content to a suitable HTML fragment that
       
    81                 will work as a heading for the weather forecast. In addition to that we'll
       
    82                 have to retrieve the weather forecast from the business logic engine and then
       
    83                 create HTML from that for each day in the forecast and set it to the five
       
    84                 content panels that we are storing references to in the weatherContentPanels
       
    85                 array. The caption for the weather forecast panels will be a string that
       
    86                 indicates the day that the forecast is for.
       
    87             </p>
       
    88 
       
    89             <p>
       
    90 
       
    91                 Creating the HTML fragment for the forecast heading doesn't sound so hard
       
    92                 but generating HTML for a weather forecast for five days sounds a bit tricky.
       
    93                 Let's create a separate function to do that. Remember that the weather object
       
    94                 that the engine is returning to us has two properties: temperature and type.
       
    95                 The temperature is in the preferred temperature unit and the type is one of
       
    96                 the type codes, e.g. "Sunny". We'll use it to match it up with a weather icon.
       
    97             </p>
       
    98 
       
    99 <pre>
       
   100 
       
   101 // Returns HTML for one day of weather forecast.
       
   102 function getHTMLForWeather(weather) {
       
   103     // build weather icon file name string
       
   104     var weatherIcon = "Weather" + weather.type + ".png";
       
   105     
       
   106     // build temperature string
       
   107     var temperatureStr = weather.temperature + "&amp;deg;" + engine.getTemperatureUnit().toUpperCase();
       
   108     
       
   109     // build weather HTML
       
   110     var weatherBuf = "";
       
   111     weatherBuf += "&lt;table class=\"WeatherForecastDayTable\"&gt;&lt;tr&gt;";
       
   112         weatherBuf += "&lt;td class=\"WeatherForecastIconCell\"&gt;";
       
   113             weatherBuf += "&lt;img src=\"" + weatherIcon + "\"/&gt;";
       
   114         weatherBuf += "&lt;/td&gt;";
       
   115         weatherBuf += "&lt;td class=\"WeatherForecastTemperatureCell\"&gt;";
       
   116             weatherBuf += temperatureStr;
       
   117         weatherBuf += "&lt;/td&gt;";
       
   118     weatherBuf += "&lt;/tr&gt;&lt;/table&gt;";
       
   119     
       
   120     return weatherBuf;
       
   121 }
       
   122 </pre>
       
   123 
       
   124             <p>
       
   125 
       
   126                 The HTML that we are generating is a table with a single row with two cells.
       
   127                 The left cell has the weather icon image and the right cell has the temperature.
       
   128                 We are using three CSS style rules for the table and we naturally need to create
       
   129                 those too in the TravelCompanion.css file:
       
   130             </p>
       
   131 
       
   132 <pre>
       
   133 
       
   134 /* Table for one day of weather forecast information */
       
   135 .WeatherForecastDayTable {
       
   136     margin: auto;
       
   137     border-spacing: 0px;
       
   138 }
       
   139 
       
   140 /* Table cell for weather icon */
       
   141 .WeatherForecastIconCell {
       
   142     line-height: 1px;
       
   143     font-size: 1px;
       
   144     vertical-align: middle;
       
   145 }
       
   146 
       
   147 /* Table cell for temperature information */
       
   148 .WeatherForecastTemperatureCell {
       
   149     padding: 0px 0px 0px 10px;
       
   150     vertical-align: middle;
       
   151 }
       
   152 </pre>
       
   153 
       
   154             <p>
       
   155 
       
   156                 Now we have a way to turn a weather forecast into HTML that we can use in a
       
   157                 ContentPanel control. We'll do that in a function we call updateWeatherForecast().
       
   158                 The caption for each weather forecast panel will indicate the day that the
       
   159                 forecast is for. The first weather object in the array that the engine returns
       
   160                 is for today and the subsequent ones are for coming days.
       
   161             </p>
       
   162 
       
   163 <pre>
       
   164 
       
   165 // Updates the weather forecast.
       
   166 function updateWeatherForecast() {
       
   167     // get local time and weather
       
   168     var localTime = engine.getLocalTime();
       
   169     var localWeather = engine.getLocalWeather();
       
   170     
       
   171     // set the weather for each day in the forecast
       
   172     for (var i = 0; i &lt; 5; i++) {
       
   173         // figure out day name
       
   174         var day = (localTime.day + i) % 7;
       
   175         var dayName = localTime.dayNames[day];
       
   176         
       
   177         // set weather to content panel
       
   178         weatherContentPanels[i].setCaption((i == 0 ? "Today, " : "") + dayName);
       
   179         weatherContentPanels[i].setContent(getHTMLForWeather(localWeather[i]));
       
   180     }
       
   181 }
       
   182 </pre>
       
   183 
       
   184             <p>
       
   185 
       
   186                 We are now ready to implement the showWeatherView() function:
       
   187             </p>
       
   188 
       
   189 <pre>
       
   190 
       
   191 // Displays the weather view.
       
   192 function showWeatherView() {
       
   193     // set heading city panel
       
   194     weatherCityPanel.setContent("&lt;div class=\"WeatherCityPanel\"&gt;" + engine.getLocalCity().name + " 5-day Forecast("&lt;/div&gt;");
       
   195     
       
   196     // update the weather forecast before showing the view
       
   197     updateWeatherForecast();
       
   198     
       
   199     setSubViewSoftkeys();
       
   200     uiManager.setView(weatherView);
       
   201 }
       
   202 </pre>
       
   203 
       
   204             <p>
       
   205 
       
   206                 The weatherCityPanel gets a heading that matches the currently configured local city.
       
   207                 We're using another CSS rule for that so we'll have to add it to our stylesheet:
       
   208             </p>
       
   209 
       
   210 <pre>
       
   211 
       
   212 /* City heading panel for weather forecast view */
       
   213 .WeatherCityPanel {
       
   214     font-size: 14px;
       
   215     font-weight: bold;
       
   216     padding: 0px 0px 10px 0px;
       
   217 }
       
   218 </pre>
       
   219 
       
   220             <p>
       
   221 
       
   222                 The weather forecast view and functionality is now ready to be tested.
       
   223             </p>
       
   224 
       
   225         </div>
       
   226 
       
   227         <div class="section"><h2 class="sectiontitle">
       
   228 Currency converter</h2>
       
   229 
       
   230             
       
   231             <p>
       
   232 
       
   233                 It's time to move on to the currency converter. This view is going to have two
       
   234                 TextField controls. One for home currency and one for local currency. In addition
       
   235                 there will be two FormButton controls to convert from the home currency to the
       
   236                 local currency, and vice versa. We'll need references to the textfields so that
       
   237                 we can retrieve their values when the form buttons are pressed:
       
   238             </p>
       
   239 
       
   240 <pre>
       
   241 
       
   242 // Converter view controls.
       
   243 var homeMoneyField;
       
   244 var localMoneyField;
       
   245 </pre>
       
   246 
       
   247             <p>
       
   248 
       
   249                 Creating the view is quite straight forward:
       
   250             </p>
       
   251 
       
   252 <pre>
       
   253 
       
   254 // Creates the converter view.
       
   255 function createConverterView() {
       
   256     // empty caption text to display the caption bar - custom background using CSS
       
   257     converterView = new ListView(null, "");
       
   258     
       
   259     // home money
       
   260     homeMoneyField = new TextField();
       
   261     converterView.addControl(homeMoneyField);
       
   262     
       
   263     // local money
       
   264     localMoneyField = new TextField();
       
   265     converterView.addControl(localMoneyField);
       
   266     
       
   267     // home to local
       
   268     var homeToLocalButton = new FormButton(null, "Convert Home to Local");
       
   269     converterView.addControl(homeToLocalButton);
       
   270     
       
   271     // local to home
       
   272     var localToHomeButton = new FormButton(null, "Convert Local to Home");
       
   273     converterView.addControl(localToHomeButton);
       
   274 }
       
   275 </pre>
       
   276 
       
   277             <p>
       
   278 
       
   279                 Notice that the textfields don't have any caption or text at this point. We will
       
   280                 set that just before the view is displayed because the caption will depend on
       
   281                 what the home and local cities are configured to.
       
   282             </p>
       
   283 
       
   284             <p>
       
   285 
       
   286                 Also notice that we don't have any event listeners for the buttons at this point.
       
   287                 That's because we haven't actually written any functions that will implement
       
   288                 the currency conversion yet. But before we do that we'll implement the
       
   289                 function to show the view:
       
   290             </p>
       
   291 
       
   292 <pre>
       
   293 
       
   294 // Displays the converter view.
       
   295 function showConverterView() {
       
   296     // set captions and reset fields
       
   297     homeMoneyField.setCaption("Home Currency (" + engine.getHomeCity().currency + ")");
       
   298     homeMoneyField.setText("");
       
   299     localMoneyField.setCaption("Local Currency (" + engine.getLocalCity().currency + ")");
       
   300     localMoneyField.setText("");
       
   301     
       
   302     setSubViewSoftkeys();
       
   303     uiManager.setView(converterView);
       
   304 }
       
   305 </pre>
       
   306 
       
   307             <p>
       
   308 
       
   309                 You can now test the view but it won't actually convert any currency until
       
   310                 we give our form buttons event listeners and write the code that will be
       
   311                 called when the buttons are pressed.
       
   312             </p>
       
   313 
       
   314             <p>
       
   315 
       
   316                 We'll implement that in two functions. One to convert from home to local and
       
   317                 another to convert in the other direction. The functions take the current
       
   318                 text value from the corresponding field and then pass it to the engine to do
       
   319                 the conversion. The result is then placed in the other of the two fields,
       
   320                 formatted so that the result has exactly two digits.
       
   321             </p>
       
   322 
       
   323 <pre>
       
   324 
       
   325 // Called when the user clicks on the "convert home to local" button
       
   326 // in the converter view. (rounds to two decimals)
       
   327 function convertHomeToLocalMoney() {
       
   328     var homeMoney = parseFloat(homeMoneyField.getText());
       
   329     var localMoney = engine.convertHomeToLocalMoney(homeMoney).toFixed(2);
       
   330     localMoneyField.setText(localMoney);
       
   331 }
       
   332 
       
   333 // Called when the user clicks on the "convert local to home" button
       
   334 // in the converter view. (rounds to two decimals)
       
   335 function convertLocalToHomeMoney() {
       
   336     var localMoney = parseFloat(localMoneyField.getText());
       
   337     var homeMoney = engine.convertLocalToHomeMoney(localMoney).toFixed(2);
       
   338     homeMoneyField.setText(homeMoney);
       
   339 }
       
   340 </pre>
       
   341 
       
   342             <p>
       
   343 
       
   344                 Now that the functions are implemented we can add the event listeners to our
       
   345                 form buttons. We'll add this code right after where the buttons are created in
       
   346                 the createConverterView() function:
       
   347             </p>
       
   348 
       
   349 <pre>
       
   350 
       
   351 homeToLocalButton.addEventListener("ActionPerformed", convertHomeToLocalMoney);
       
   352 localToHomeButton.addEventListener("ActionPerformed", convertLocalToHomeMoney);
       
   353 </pre>
       
   354 
       
   355             <p>
       
   356 
       
   357                 The currency converter is now working and it's time to test it. Try it with
       
   358                 different currencies by changing the home and local cities in the settings view.
       
   359             </p>
       
   360 
       
   361             <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. 
       
   362 Travel Companion converter view</span>
       
   363 
       
   364                 
       
   365                 <br /><img src="Travel_Companion_Converter_Screenshot_1.png" /><br />
       
   366             </div>
       
   367 
       
   368         </div>
       
   369 
       
   370         <div class="section"><h2 class="sectiontitle">
       
   371 Information view</h2>
       
   372 
       
   373             
       
   374             <p>
       
   375 
       
   376                 The information view is a summary of relevant information that the user is
       
   377                 will often need. Here we'll have a world clock that shows the home and local
       
   378                 time, the current weather at home and in the local city, as well as the
       
   379                 latest news headlines. We will use ContentPanel controls for all of these.
       
   380                 One for the home time, one for the local time, one for the home weather, one
       
   381                 for the local weather, and one for all the news headlines.
       
   382             </p>
       
   383 
       
   384             <p>
       
   385 
       
   386                 We'll need to access all of these content panels from outside the view creation
       
   387                 function so we'll need global variables to hold references to them:
       
   388             </p>
       
   389 
       
   390 <pre>
       
   391 
       
   392 // Info view controls.
       
   393 var homeCityTimePanel;
       
   394 var localCityTimePanel;
       
   395 var homeCityWeatherPanel;
       
   396 var localCityWeatherPanel;
       
   397 var newsHeadlinesPanel;
       
   398 </pre>
       
   399 
       
   400             <p>
       
   401 
       
   402                 We can now proceed and actually implement the creation of the information view:
       
   403             </p>
       
   404 
       
   405 <pre>
       
   406 
       
   407 // Creates the info view.
       
   408 function createInfoView() {
       
   409     // empty caption text to display the caption bar - custom background using CSS
       
   410     infoView = new ListView(null, "");
       
   411     
       
   412     // home city time
       
   413     homeCityTimePanel = new ContentPanel();
       
   414     infoView.addControl(homeCityTimePanel);
       
   415     
       
   416     // local city time
       
   417     localCityTimePanel = new ContentPanel();
       
   418     infoView.addControl(localCityTimePanel);
       
   419     
       
   420     // separator
       
   421     infoView.addControl(new Separator());
       
   422     
       
   423     // home city weather
       
   424     homeCityWeatherPanel = new ContentPanel();
       
   425     infoView.addControl(homeCityWeatherPanel);
       
   426     
       
   427     // local city weather
       
   428     localCityWeatherPanel = new ContentPanel();
       
   429     infoView.addControl(localCityWeatherPanel);
       
   430     
       
   431     // separator
       
   432     infoView.addControl(new Separator());
       
   433     
       
   434     // news headlines
       
   435     newsHeadlinesPanel = new ContentPanel();
       
   436     infoView.addControl(newsHeadlinesPanel);
       
   437 }
       
   438 </pre>
       
   439 
       
   440             <p>
       
   441 
       
   442                 We already have a function that turns a weather forecast into HTML but we
       
   443                 don't have similar functions for time or for news headlines. We'll need
       
   444                 that when we want to put content into the time and headline content panels
       
   445                 so let's write those functions next.
       
   446             </p>
       
   447 
       
   448             <p>
       
   449 
       
   450                 For time we'll need a function that takes a DateTime object and returns
       
   451                 HTML that we can use in the content panel in the information view.
       
   452             </p>
       
   453 
       
   454 <pre>
       
   455 
       
   456 // Returns HTML for time.
       
   457 function getHTMLForTime(time) {
       
   458     // build HTML buffer
       
   459     var timeBuf = "";
       
   460     timeBuf += "&lt;div class=\"Clock\"&gt;";
       
   461         timeBuf += time.hours + ":" + (time.minutes &lt; 10 ? "0" : "") + time.minutes;
       
   462     timeBuf += "&lt;/div&gt;";
       
   463     return timeBuf;
       
   464 }
       
   465 </pre>
       
   466 
       
   467             <p>
       
   468 
       
   469                 The HTML uses a CSS rule that we'll have to define in our stylesheet:
       
   470             </p>
       
   471 
       
   472 <pre>
       
   473 
       
   474 /* Clock div */
       
   475 .Clock {
       
   476     text-align: center;
       
   477     font-size: 16px;
       
   478     font-weight: bold;
       
   479 }
       
   480 </pre>
       
   481 
       
   482             <p>
       
   483 
       
   484                 Next up is the function for turning the latest news headlines into HTML.
       
   485                 For each news headline we'll generate a div that contains the actual
       
   486                 news headline plus a link to the website where the full news article is.
       
   487                 Opening URLs should be done using the widget.openURL() method in the
       
   488                 S60 Web Runtime but since we don't have that functionality in a PC browser
       
   489                 we'll write a wrapper for the function just like we did for the RSS Reader:
       
   490             </p>
       
   491 
       
   492 <pre>
       
   493 
       
   494 // Opens a URL.
       
   495 function openURL(url) {
       
   496     if (window.widget) {
       
   497         // in WRT
       
   498         widget.openURL(url);
       
   499     } else {
       
   500         // outside WRT
       
   501         window.open(url, "NewWindow");
       
   502     }
       
   503 }
       
   504 </pre>
       
   505 
       
   506             <p>
       
   507 
       
   508                 Now we can implement the function that turns news headlines into HTML:
       
   509             </p>
       
   510 
       
   511 <pre>
       
   512 
       
   513 // Returns HTML for news headlines.
       
   514 function getHTMLForNewsHeadlines(newsHeadlines) {
       
   515     var newsBuf = "";
       
   516     for (var i = 0; i &lt; newsHeadlines.length; i++) {
       
   517         newsBuf += "&lt;div class=\"NewsHeadline\"&gt;";
       
   518             newsBuf += newsHeadlines[i].headline + "&lt;br/&gt;";
       
   519             newsBuf += "&lt;a href=\"JavaScript:openURL('" + newsHeadlines[i].url + "');\"&gt;";
       
   520             newsBuf += "Read more...";
       
   521             newsBuf += "&lt;/a&gt;";
       
   522         newsBuf += "&lt;/div&gt;";
       
   523     }
       
   524     return newsBuf;
       
   525 }
       
   526 </pre>
       
   527 
       
   528             <p>
       
   529 
       
   530                 The div that encloses each news headline uses a CSS rule called NewsHeadline.
       
   531                 As with all other CSS rules that we use we'll define this one too in
       
   532                 the TravelCompanion.css stylesheet file. We also need to add rules for what
       
   533                 links should look like in the context of a news headline. We define the link
       
   534                 as bold underlined blue text in its normal state and inverse with blue background
       
   535                 and white text when focused.
       
   536             </p>
       
   537 
       
   538 <pre>
       
   539 
       
   540 /* News headline */
       
   541 .NewsHeadline {
       
   542     padding: 0px 0px 10px 0px;
       
   543 }
       
   544 
       
   545 /* Anchor tags in the context of a news headline link */
       
   546 .NewsHeadline a {
       
   547     text-decoration: underline;
       
   548     font-weight: bold;
       
   549     color: rgb(0,0,255);
       
   550 }
       
   551 
       
   552 /* Focused anchor tags */
       
   553 .NewsHeadline a:focus {
       
   554     background: rgb(0,0,255);
       
   555     color: rgb(255,255,255);
       
   556 }
       
   557 </pre>
       
   558 
       
   559             <p>
       
   560 
       
   561                 Now we should have everything we need to be able to update the information
       
   562                 view content panels when the view is shown. It's time to implement the
       
   563                 showInfoView() function:
       
   564             </p>
       
   565 
       
   566 <pre>
       
   567 
       
   568 // Displays the info view.
       
   569 function showInfoView() {
       
   570     // set current information to controls
       
   571     var homeCity = engine.getHomeCity();
       
   572     var localCity = engine.getLocalCity();
       
   573     
       
   574     // set time
       
   575     var homeTime = engine.getHomeTime();
       
   576     var localTime = engine.getLocalTime();
       
   577     homeCityTimePanel.setCaption(homeCity.name + " Time");
       
   578     homeCityTimePanel.setContent(getHTMLForTime(homeTime));
       
   579     localCityTimePanel.setCaption(localCity.name + " Time");
       
   580     localCityTimePanel.setContent(getHTMLForTime(localTime));
       
   581     
       
   582     // set weather
       
   583     var homeWeather = engine.getHomeWeather();
       
   584     var localWeather = engine.getLocalWeather();
       
   585     homeCityWeatherPanel.setCaption(homeCity.name + " Weather");
       
   586     homeCityWeatherPanel.setContent(getHTMLForWeather(homeWeather[0]));
       
   587     localCityWeatherPanel.setCaption(localCity.name + " Weather");
       
   588     localCityWeatherPanel.setContent(getHTMLForWeather(localWeather[0]));
       
   589     
       
   590     // set headline
       
   591     var newsHeadlines = engine.getNewsHeadlines();
       
   592     newsHeadlinesPanel.setCaption("News Headlines");
       
   593     newsHeadlinesPanel.setContent(getHTMLForNewsHeadlines(newsHeadlines));
       
   594     
       
   595     setSubViewSoftkeys();
       
   596     uiManager.setView(infoView);
       
   597 }
       
   598 </pre>
       
   599 
       
   600             <p>
       
   601 
       
   602                 If you try the view now, everything will seem to work fine. But there
       
   603                 is a big problem! We set the content in the content panels when the
       
   604                 view is shown but if we stay in the view for an hour the clocks will
       
   605                 still show the same time as when we showed the view. What's worse, it's
       
   606                 not just the information view that has this problem. The weather forecast
       
   607                 view is equally broken.
       
   608             </p>
       
   609 
       
   610         </div>
       
   611 
       
   612         <div class="section"><h2 class="sectiontitle">
       
   613 Updating views with a timer</h2>
       
   614 
       
   615             
       
   616             <p>
       
   617 
       
   618                 In order to keep the views up to date we'll need to start a timer that
       
   619                 periodically calls a function where we examine whether it's been long
       
   620                 enough since the last update of a view that it's time to update the
       
   621                 content in that view. Note that we only need to update a view using the
       
   622                 timer if the view is actually visible.
       
   623             </p>
       
   624 
       
   625             <p>
       
   626 
       
   627                 That sounds good at first but some things have to be updated more
       
   628                 frequently than others. The clocks in our information view have to not
       
   629                 only be updated once a minute but immediately when the minute changes.
       
   630                 Such accuracy is not needed for the weather forecasts or news headlines.
       
   631                 For them it's fine if they are updated once per hour. Except that weather
       
   632                 forecasts also have to be updated when the day rolls over to the next as
       
   633                 otherwise the forecast will show the wrong day. Because the home and local
       
   634                 cities can be in different timezones their days will roll over at
       
   635                 different times and thus we have to track these separately.
       
   636             </p>
       
   637 
       
   638             <p>
       
   639 
       
   640                 It turns out that we need no less than five variables to track this.
       
   641                 We need one to track the last minute that has been updated to the clocks,
       
   642                 one variable is needed to track when the weather was last updated, one
       
   643                 to track the day in the home city when the home city weather forecast
       
   644                 was updated, one to track the same but for the local city, and one to
       
   645                 track when the news headlines were updated. Let's declare those variables
       
   646                 and initialize them:
       
   647             </p>
       
   648 
       
   649 <pre>
       
   650 
       
   651 // Tracks last updated minute on the clocks.
       
   652 var lastUpdatedClockMinute = -1;
       
   653 
       
   654 // Tracks last update time for weather.
       
   655 var weatherLastUpdated = -1;
       
   656 
       
   657 // Tracks the days when the weather was last updated.
       
   658 var lastUpdatedHomeWeatherDay = -1;
       
   659 var lastUpdatedLocalWeatherDay = -1;
       
   660 
       
   661 // Tracks last update time for news headlines.
       
   662 var newsHeadlinesLastUpdated = -1;
       
   663 </pre>
       
   664 
       
   665             <p>
       
   666 
       
   667                 We'll use the time in millieconds to remember update times and compare
       
   668                 how long it's been since an update happened. Since we'll use this quite
       
   669                 a lot, let's create a small helper function for it:
       
   670             </p>
       
   671 
       
   672 <pre>
       
   673 
       
   674 // Returns the current time in milliseconds.
       
   675 function getTimeMillis() {
       
   676     return new Date().getTime();
       
   677 }
       
   678 </pre>
       
   679 
       
   680             <p>
       
   681 
       
   682                 When we show a view we have to update the appropriate tracking variables
       
   683                 so the widget will properly keep track of when a view was updated. That
       
   684                 means that we have to add the following to just before we show the
       
   685                 information view in showInfoView():
       
   686             </p>
       
   687 
       
   688 <pre>
       
   689 
       
   690 // update the tracking variables
       
   691 lastUpdatedClockMinute = homeTime.minutes;
       
   692 weatherLastUpdated = getTimeMillis();
       
   693 lastUpdatedHomeWeatherDay = homeTime.day;
       
   694 lastUpdatedLocalWeatherDay = localTime.day;
       
   695 newsHeadlinesLastUpdated = getTimeMillis();
       
   696 </pre>
       
   697 
       
   698             <p>
       
   699 
       
   700                 In the same way the showWeatherView() function needs the following addition:
       
   701             </p>
       
   702 
       
   703 <pre>
       
   704 
       
   705 // update the tracking variables
       
   706 weatherLastUpdated = getTimeMillis();
       
   707 lastUpdatedLocalWeatherDay = engine.getLocalTime().day;
       
   708 </pre>
       
   709 
       
   710             <p>
       
   711 
       
   712                 Now our tracking variables should be updated to the right times whenever views
       
   713                 are shown but we still don't have a timer to handle the automatic updating
       
   714                 of the views.
       
   715             </p>
       
   716 
       
   717             <p>
       
   718 
       
   719                 We'll set this timer up so that the timer callback function is called once
       
   720                 every second so that we can make sure that the clocks don't fall behind. We'll
       
   721                 track the timer identifier in a variable:
       
   722             </p>
       
   723 
       
   724 <pre>
       
   725 
       
   726 // View updating timer identifier.
       
   727 var timerId;
       
   728 </pre>
       
   729 
       
   730             <p>
       
   731 
       
   732                 We'll make the timer call a function called updateViews() that we will
       
   733                 create shortly but first let's start the timer as the last thing in the
       
   734                 init() function:
       
   735             </p>
       
   736 
       
   737 <pre>
       
   738 
       
   739 // start timer that keeps views up to date
       
   740 timerId = setInterval(updateViews, 1000);
       
   741 </pre>
       
   742 
       
   743             <p>
       
   744 
       
   745                 The updateViews() function needs to check what view we are currently in and do
       
   746                 the appropriate checks depending on the view. If we're in the information view
       
   747                 then we have three things to check. The first thing is to check if the minute
       
   748                 has changed on the clock. The second is to check if it's been over 60 minutes
       
   749                 since the weather was updated or if either the home or local city has rolled
       
   750                 over to the next day. And finally the third to thing to check is if it's been
       
   751                 over 60 minutes since the news headlines were updated.
       
   752             </p>
       
   753 
       
   754             <p>
       
   755 
       
   756                 If we are in the weather view then we check if it's been over 60 minutes since
       
   757                 the weather was updated or if the local city has rolled over to the next day.
       
   758                 Note that the weather forecast view only displays the local weather forecast
       
   759                 so we don't have to check for if the home city has rolled over to the next day.
       
   760             </p>
       
   761 
       
   762             <p>
       
   763 
       
   764                 The implementation of the function is therefore as follows:
       
   765             </p>
       
   766 
       
   767 <pre>
       
   768 
       
   769 // Timer callback function that gets called once every second to keep views up to date.
       
   770 function updateViews() {
       
   771     
       
   772     // get the current view
       
   773     var currentView = uiManager.getView();
       
   774     
       
   775     // get home and local time as well as time in milliseconds
       
   776     var homeTime = engine.getHomeTime();
       
   777     var localTime = engine.getLocalTime();
       
   778     var now = getTimeMillis();
       
   779     
       
   780     if (currentView == infoView) {
       
   781         // only update the clocks if the minute has changed
       
   782         if (homeTime.minutes != lastUpdatedClockMinute) {
       
   783             lastUpdatedClockMinute = homeTime.minute;
       
   784             homeCityTimePanel.setContent(getHTMLForTime(homeTime));
       
   785             localCityTimePanel.setContent(getHTMLForTime(localTime));
       
   786         }
       
   787         
       
   788         // update weather if it hasn't been updated in the last hour or if the day has changed
       
   789         if ((now &gt; weatherLastUpdated + (1000 * 60 * 60)) ||
       
   790                 (homeTime.day != lastUpdatedHomeWeatherDay) ||
       
   791                 (localTime.day != lastUpdatedLocalWeatherDay)) {
       
   792             weatherLastUpdated = now;
       
   793             lastUpdatedHomeWeatherDay = homeTime.day;
       
   794             lastUpdatedLocalWeatherDay = localTime.day;
       
   795             var homeWeather = engine.getHomeWeather();
       
   796             var localWeather = engine.getLocalWeather();
       
   797             homeCityWeatherPanel.setContent(getHTMLForWeather(homeWeather[0]));
       
   798             localCityWeatherPanel.setContent(getHTMLForWeather(localWeather[0]));
       
   799         }
       
   800         
       
   801         // update news headlines if they haven't been updated in the last hour
       
   802         if (now &gt; newsHeadlinesLastUpdated + (1000 * 60 * 60)) {
       
   803             newsHeadlinesLastUpdated = now;
       
   804             var newsHeadlines = engine.getNewsHeadlines();
       
   805             newsHeadlinesPanel.setContent(getHTMLForNewsHeadlines(newsHeadlines));
       
   806         }
       
   807     } else if (currentView == weatherView) {
       
   808         // update weather if it hasn't been updated in the last hour or if the day has changed
       
   809         if ((now &gt; weatherLastUpdated + (1000 * 60 * 60)) ||
       
   810                 (localTime.day != lastUpdatedLocalWeatherDay)) {
       
   811             weatherLastUpdated = now;
       
   812             lastUpdatedLocalWeatherDay = localTime.day;
       
   813             updateWeatherForecast();
       
   814         }
       
   815     }
       
   816 }
       
   817 </pre>
       
   818 
       
   819             <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. 
       
   820 Travel Companion information view</span>
       
   821 
       
   822                 
       
   823                 <br /><img src="Travel_Companion_Info_Screenshot_1.png" /><br />
       
   824             </div>
       
   825 
       
   826         </div>
       
   827 
       
   828         <div class="section"><h2 class="sectiontitle">
       
   829 What we have learned</h2>
       
   830 
       
   831             
       
   832             <p>
       
   833 
       
   834                 The Travel Companion widget is now completed! We have learned to implement
       
   835                 complex widgets with multiple views using the WRTKit. We have also learned
       
   836                 how to keep information in views up to date using a timer. And we implemented
       
   837                 the widget without any dependencies to how the business logic engine was
       
   838                 implemented. That will come in handy if you want to continue developing this
       
   839                 widget by substituting the mock engine with one that actually uses real
       
   840                 world data. You are now ready to tackle any challenge using the WRTKit!
       
   841             </p>
       
   842 
       
   843         </div>
       
   844 
       
   845     </div>
       
   846 
       
   847 <div>
       
   848 <div class="familylinks">
       
   849 <div class="parentlink"><strong>Parent topic:</strong> <a href="WRTKit_Travel_Companion_Tutorial-GUID-be79ba64-fa03-4968-964e-d7dcc42d7053.html">Travel Companion</a></div>
       
   850 </div>
       
   851 </div>
       
   852 
       
   853 </body>
       
   854 </html>