Newsletter | Advertise | App Shop | CONTACT   
     
Saturday, September 06 2008  
Welcome to SymbianOne - symbian OS, UIQ, series 60 programers, S60, wireless developers, device makers, and mobile industry architects
Home arrow Reviews arrow The Symbian OS View Server: Advanced Techniques
HomeNewsJobsArticlesReviewsEventsMagsAbout UsLBS
FREE STUFF Job Posting / Developer Programs / Free Telecom Papers / Directory
Free IT Wireless / RCR Wireless News / Total Telecom / Symbian Search / N95 Blog / Symbian Blogs
SymbianOne Newsletter

Symbian newsletter
 Subscribe to the free SymbianOne Monitor Newsletter - 2X A Month!

remove
subscribe
SymbianOne



or Register HERE

SymbianOne Sponsors


Sponsor


Main Menu
Home
News
Jobs
Articles
Reviews
Events
Mags
About Us
LBS

Mobile Industry News
Sony Ericsson Confirms Commitment to Share Project Capuchin with Developer Community
Symbian Developer News
EDGE, HSPA and LTE Continue to Lead and Innovate Mobile Broadband
Industry News
Calling all Symbian developers! Take your turn in the spotlight ...
Smartphoneshow
Highly anticipated Nokia N96 begins shipping
Symbian News
Tip - mycitymate venue and lbs api available
Industry News
GSMA'S Global Mobile Awards 2009 And Mobile Innovation EMEA Tournament Now Open For Entry
Industry News
3DVU expands coverage of 3D virtual world mobile navigation with entire Germany
Location Services (LBS)

Sponsored Events
symbian smartphoneshow 2008
NewsFeeds


Symbian one RSS feed Add the SymbianOne RSS feed to your reader 

Get daily email updates:


by FeedBurner

 
For The Developer

AT & T devcentral
 AT&T Developer Program - Mobile Application Development Best Practices

Free White Papers

Device Gallery


Sendo X

post a job

Symbian Careers
FREE Job Posting!

FREE STUFF

 

 

SymbianOne Stuff!

Mobile Application Store 

 SymbianOne Mosh

SymbianOne Feature Article

The Platform Promise: S60 Devices From Samsung - Java technology was heralded as write-once-run-everywhere - we know the reality was somewhat different. As the first Samsung S60 devices arrive in the SymbianOne offices Richard Bloor asks if the S60 platform serves Symbian C++ developers better. In this article Bloor tests the Samsung SGH-G810, SGH-I550, SGH-L870, and SGH-I8510 (INNOV8) S60 devices.

Need A Wireless Developer?... Post Your Free Job Listing in our Career Center Today!
The Symbian OS View Server: Advanced Techniques Print E-mail
Written by Daniel Rocha   
Wednesday, 27 July 2005
Daniel Rocha follows up the earlier introduction to the Symbian OS View Server with a look at more advanced techniques, such as changing menus and CBAs according to the view being displayed.

This article resumes from the point where the article The Symbian OS View Server stopped. I will present some advanced features you can add to your programs using some nice tricks with the View Server and UI Control Framework APIs. These include changing menus and CBAs according to the view being displayed, sending messages from one view to another and using external application views.

General Information
Changing the menu bar

In the previous article we defined a single menu in a resource file with the following code:

<code>
 
RESOURCE EIK_APP_INFO
    {
    menubar = r_ViewServer_menubar;
    cba = R_AVKON_SOFTKEYS_OPTIONS_EXIT;
    }
 
RESOURCE MENU_BAR r_ViewServer_menubar
    {
    titles =
        {
        MENU_TITLE {menu_pane = r_ViewServer_menu;}
        };
    }
 
RESOURCE MENU_PANE r_ViewServer_menu
    {
    items = 
        {
        MENU_ITEM {command = EViewServerChangeCmd; txt = "Change View";},
        MENU_ITEM {command = EAknSoftkeyExit;   txt = "Exit";}
        };
    }
 
</code>

The line menubar = r_ViewServer_menubar; within EIK_APP_INFO struct defines the default menu bar for the application. This is the menu bar that is going to be displayed in every view that does not define its own menu. That's why you saw the same menu bar in all the views of our first application: they were not interested in having a different menu bar, so they didn't change the default one. This approach works fine if you have few views and you can concentrate all the actions needed in a single menu. However, in more complex applications, you will certainly need specific menu for each view's specific actions, and I will show you how to do that.

First of all, we need to define all the menus our views are going to use, and that is done, as usual, in the resource file:

<code>
 
RESOURCE EIK_APP_INFO
    {
    menubar = r_ViewServer_menubar;
    cba = R_AVKON_SOFTKEYS_OPTIONS_EXIT;
    }
    
 
RESOURCE MENU_BAR r_ViewServer_menubar
    {
    titles =
        {
        MENU_TITLE {menu_pane = r_ViewServer_menu;}
        };
    }
 
RESOURCE MENU_PANE r_ViewServer_menu
    {
    items = 
        {
        MENU_ITEM {command = EViewServerChangeCmd; txt = "Second View";},
        MENU_ITEM {command = EViewServerLaunchCalendarCmd; txt = "Launch Calendar";},
        MENU_ITEM {command = EAknSoftkeyExit;   txt = "Exit";}
        };
    }
 
 
// menubar for view two;
 
RESOURCE MENU_BAR r_ViewServer_menubar_two
    {
    titles =
        {
        MENU_TITLE {menu_pane = r_ViewServer_menu_two;}
        };
    }
 
RESOURCE MENU_PANE r_ViewServer_menu_two
    {
    items = 
        {
        MENU_ITEM {command = EViewServerAboutCmd; txt = "Third View";},
        MENU_ITEM {command = EViewServerFirstCmd;   txt = "Previous";}
        };
    }
    
// menubar for about view;
    
RESOURCE MENU_BAR r_ViewServer_menubar_about
    {
    titles =
        {
        MENU_TITLE {menu_pane = r_ViewServer_menu_about;}
        };
    }
 
RESOURCE MENU_PANE r_ViewServer_menu_about
    {
    items = 
        {
        MENU_ITEM {command = EViewServerParamCmd; txt = "Parameter View";},
        MENU_ITEM {command = EViewServerChangeCmd;   txt = "Previous";}
        };
    }
    
// menubar for param view
    
RESOURCE MENU_BAR r_ViewServer_menubar_param
    {
    titles =
        {
        MENU_TITLE {menu_pane = r_ViewServer_menu_param;}
        };
    }
 
RESOURCE MENU_PANE r_ViewServer_menu_param
    {
    items = 
        {
        MENU_ITEM {command = EViewServerFirstCmd; txt = "First View";},
        MENU_ITEM {command = EViewServerAboutCmd;   txt = "Previous";}
        };
    }
    
 
</code>

Wow! A whole lot of new menus: r_ViewServer_menubar, r_ViewServer_menubar_two, r_ViewServer_menubar_about and r_ViewServer_menubar_param. Note the EViewServer*Cmd commands, they are necessary for event handling and are defined in ViewServer.hrh file, and included in both the resource file (for definition) and in the AppUi class (for checking and command handling). Note also that the menus themselves are not associated with any particular view; that leaves us with a great deal of flexibility in choosing the right menu for each view at runtime, using code within the view. Let's see how to do this.

First, let us add two more view classes so we can make it clearer how easy menu and CBA switching with the view server is. Those classes are: CViewServerAboutView and CViewServerParamView. The updated class model follows:

View Server Updated Class Model
Fig. 1 - Updated Class Model

You can see that our new classes are nothing but standard views similar to those we are used to building: simple classes that inherit from CCoeControl and MCoeView base classes. So, we have defined the menus in the resource file, but how do we associate each one with a given view? The answer is straightforward: When a view is activated you must replace the current menu bar with some other, more suitable to the view being activated; this code has to be placed, as expected, in the view's ViewActivatedL() member function. The code below is implemented in the CViewServerMenuView class.

<code>
 
//activates this view, called by the framework
void CViewServerAboutView::ViewActivatedL(const TVwsViewId& /*aPrevViewId*/,
                                     TUid /*aCustomMessageId*/,
                                     const TDesC8& /*aCustomMessage*/) {  
  
<strong>  CEikonEnv* eikonEnv = CEikonEnv::Static();
  MEikAppUiFactory* appUiFactory = eikonEnv->AppUiFactory();
  CEikMenuBar* menuBar = appUiFactory->MenuBar();
  
  menuBar->StopDisplayingMenuBar();
  menuBar->SetMenuTitleResourceId(R_VIEWSERVER_MENUBAR_TWO);
                       </strong>
  Window().SetOrdinalPosition(0);                                  
  MakeVisible(ETrue);
}
 
</code>

Line CEikonEnv* eikonEnv = CEikonEnv::Static(); gets a pointer to this application's CEikonEnv instance. You could also use the iEikonEnv pointer available to the view class. MEikAppUiFactory* appUiFactory = eikonEnv->AppUiFactory(); gets a pointer to this application's AppUiFactory, responsible for breaking the dependency of the AppUi on controls. From this pointer, you get a pointer to the CEikMenuBar, which represents the current menu bar being displayed by your application.

The next two lines are the most important one, as the code on them is responsible for the actual menu bar switching: menuBar->StopDisplayingMenuBar(); makes the current menu bar invisible, while menuBar->SetMenuTitleResourceId(R_VIEWSERVER_MENUBAR_TWO); sets the new Resource ID of the menu bar, which is the same R_VIEWSERVER_MENUBAR_TWO menu resource we have defined in the resource file. Note that SetMenuTitleResourceId is only used by Series 60; other environments will most likely use the ChangeMenuBarL() member function to perform the same task. And that's pretty much it: define a menu in the resource file, get a reference to it in the ViewActivatedL() function and perform the menu switching. Also, do not forget that all menu events (represented by the command item in the resource file definition) will still be handled by the CViewServerAppUi class, in the same way they were before. Add a handler for each menu command that performs a useful task; in our case, the R_VIEWSERVER_MENUBAR_TWO has two commands: EViewServerAboutCmd, which when handled by the AppUi activates the CViewServerAboutView, and EViewServerFirstCmd, that sends us back to the first view.

Changing the CBA

The CBA (Command Button Actions) is the area where commands can be accessed directly by the device's softkeys. That means that a developer making use of the CBA does not need to track keyboard and softkey events directly, but instead they will only deal with high-level commands, defined in the ".hrh" file and associated with the CBA in the Resource file. This saves you from the obligation of dealing with all possible key events that may be fired by the user for the simple action of opening a menu. Of course, if your application needs full key-event handling, you are free handling this yourself and not use the CBA.

Command Button Actions
Fig. 2 - The CBA highlighted.

First of all, we must define all the CBAs we want to use in the resource file as follows:

<code>
 
// CBA for about view
 
RESOURCE CBA r_ViewServer_cba_about {
 
  buttons = { 
    CBA_BUTTON { txt = "MyOptions"; id = EAknSoftkeyOptions; },
    CBA_BUTTON { txt = "Previous"; id = EViewServerChangeCmd;}
  };
  
}
</code>

This CBA will be used by the CViewServerAboutView view class. It has two commands associated with it: EAnkSoftkeyOptions, which is standard for Series 60, and defined in avkon.hrh; and EViewServerChangeCmd, defined in ViewServer.hrh. The handling of these commands is done exactly in the same way as for menu commands: in CViewServerAppUi's HandleCommandL() function.

Changing the CBA is exactly like changing the menu: in the ViewActivateL() method of your view class, grab a reference to the CEikonEnv class, then use it to obtain a reference to the AppUiFactory, and from this to the CBA. This is shown in the code below, extracted from the CViewServerAboutView class.

<code>
 
//activates this view, called by the framework
void CViewServerAboutView::ViewActivatedL(const TVwsViewId& /*aPrevViewId*/,
                                     TUid /*aCustomMessageId*/,
                                     const TDesC8& /*aCustomMessage*/) {  
  
  CEikonEnv* eikonEnv = CEikonEnv::Static();
  MEikAppUiFactory* appUiFactory = eikonEnv->AppUiFactory();
  CEikMenuBar* menuBar = appUiFactory->MenuBar();
  <strong>CEikButtonGroupContainer* cba = appUiFactory->Cba();</strong>
  
  menuBar->StopDisplayingMenuBar();
  menuBar->SetMenuTitleResourceId(R_VIEWSERVER_MENUBAR_ABOUT);
<strong>  cba->SetCommandSetL(R_VIEWSERVER_CBA_ABOUT);
  cba->DrawDeferred();</strong>
                       
  Window().SetOrdinalPosition(0);                                  
  MakeVisible(ETrue);
}
 
</code>

The highlighted code shows how to obtain a pointer to the current CBA from the appUiFactory object. Once you have it, all you need to do is call SetCommandSetL(); on the current CBA, which takes as parameter the Resource ID of the new CBA that will be displayed. This Resource ID is obviously defined in the resource file as shown previously. You must also call DrawDeferred() so that the Window server draws the new CBA as soon as it has the possibility to do it. And that's pretty much it! You can see the newly-changed CBA in the picture below:

The newly changed CBA
Fig. 3 - The newly-changed CBA.
Sending messages from one view to another

When activating a different view, you can optionally send a message to it. This is very useful when you need to communicate some information that the next view will need for its normal processing. For example, in a simple wizard-like application, you can pass the values chosen in the current view to the next one so it chooses to display a different group of settings available to the user based on the selection made on the previous view. Doing so is only a matter of calling the complete version of the ActivateViewL() function, which takes four parameters: Application ID, View ID, Parameter ID and the actual message being sent.

Recall our menu definition for the CViewServerAboutView class:

<code>
 
RESOURCE MENU_PANE r_ViewServer_menu_about
    {
    items = 
        {
        MENU_ITEM {command = EViewServerParamCmd; txt = "Parameter View";},
        MENU_ITEM {command = EViewServerChangeCmd;   txt = "Previous";}
        };
    }
 
</code>

In our example, the "Parameter View" menu option is associated with the EViewServerParamCmd, which is meant to be handled by the HandleCommandL() function of the CViewServerAppUi class. So let's take a look at the function definition:

<code>
 
// handle any menu commands
void CViewServerAppUi::HandleCommandL(TInt aCommand) {
  switch(aCommand) {
    case EEikCmdExit:
    case EAknSoftkeyExit:
      Exit();
      break;  
    case EViewServerChangeCmd: {
      ActivateViewL(TVwsViewId(KUidViewServerApp,KMenuViewId));
      break;
    }
    case EViewServerAboutCmd: {
      ActivateViewL(TVwsViewId(KUidViewServerApp,KAboutViewId));
      break;
    }
    case EViewServerParamCmd: {
  <strong>    TBuf<128> text; 
      CAknTextQueryDialog* dlg = new(ELeave)CAknTextQueryDialog(text); 
      
      dlg->PrepareLC(R_PARAM_DIALOG); 
      if(dlg->RunLD()) {
        TUid uid = {1};
        TBuf8<128> tbuf;
        tbuf.Copy(text);
        ActivateViewL(TVwsViewId(KUidViewServerApp,KParamViewId),TUid::Uid(1),tbuf);
  </strong>    }
      break;
    }
    case EViewServerFirstCmd: {
      ActivateViewL(TVwsViewId(KUidViewServerApp,KViewId));
      break;
    }
    case EViewServerLaunchCalendarCmd: {
      ActivateViewL(TVwsViewId(KCalendarId,KDayViewId));
      break;
    }
    default:
      Panic(EViewServerBasicUi);
      break;
  }
}
 
</code>

The highlighted code shows us launching a standard Series 60 dialog (also defined in the resource file) to obtain some data input from the user, which will be passed forward to the next view. It could be a hardcoded message as well, no problems about that. TBuf8<128> tbuf; tbuf.Copy(text); converts the TBuf16 into the TBuf8 needed by the ActivateViewL() function. After the conversion, all we need to do is call

<code>
ActivateViewL(TVwsViewId(KUidViewServerApp,KParamViewId),TUid::Uid(1),tbuf);
</code>

And the text entered by the user is passed on to the next view, to be used in any way it likes. In our case, we will be printing the data on the screen, so there's not really a need for defining several message TUids, so we just pass the value "1", as it could be 0, 10, or Susan, if you like that :) The use of message ids is useful in the case of a view that can receive messages that should be interpreted in different ways, so you'd need to specify which way you want the message to be interpreted.

Unsurprisingly enough, we need to do something with the value in the CViewServerParamView so we can check that the parameter was passed correctly. Here is the code that does just that:

<code>
 
//activates this view, called by the framework
void CViewServerParamView::ViewActivatedL(const TVwsViewId& /*aPrevViewId*/,
                                          TUid /*aCustomMessageId*/,
                                          const TDesC8& aCustomMessage) {  
    
  CEikonEnv* eikonEnv = CEikonEnv::Static();
  MEikAppUiFactory* appUiFactory = eikonEnv->AppUiFactory();
  CEikMenuBar* menuBar = appUiFactory->MenuBar();
  CEikButtonGroupContainer* cba = appUiFactory->Cba();
  
  menuBar->StopDisplayingMenuBar();
  menuBar->SetMenuTitleResourceId(R_VIEWSERVER_MENUBAR_PARAM);
  cba->SetCommandSetL(R_AVKON_SOFTKEYS_OPTIONS_EXIT);
  cba->DrawDeferred();
  
<strong>  if(aCustomMessage.Length()>0) {
    if(param) {
      delete param;
      param = NULL;
    }
    param = HBufC::NewL(aCustomMessage.Length());
    param->Des().Copy(aCustomMessage);
  }</strong>  
  Window().SetOrdinalPosition(0);  
  MakeVisible(ETrue);
}
 
</code>

Besides changing the menu and the CBA as we have already learned to do, this code copies the message received when the view was activated into an HBufC8*, that is an instance variable of the CViewServerParamView. Later on, this buffer's contents are drawn on the screen by the Draw() function:

<code>
 
// Draw this application's view to the screen
void CViewServerParamView::Draw(const TRect& /*aRect*/) const {
  CWindowGc& gc = SystemGc();
  TRect rect = Rect();
  TPoint point(0,0);
  const CFont* font = iEikonEnv->NormalFont();
  _LIT(KTitle,"ViewServer - View Four");
  _LIT(KCredit,"Parameter:");
 
  gc.SetBrushColor(KRgbBlack);
  gc.Clear(rect);
  gc.SetPenColor(KRgbWhite);
  gc.UseFont(font);
  
  point.iX = rect.Width()/2 - font->TextWidthInPixels(KTitle)/2;
  point.iY = rect.Height()/2;
  
  gc.DrawText(KTitle,point);
  gc.DiscardFont();
  font = iEikonEnv->AnnotationFont();
  
<strong>  HBufC* text = HBufC::NewLC(KCredit().Length() + param->Length());
  TPtr16 ref = text->Des();
  ref.Append(KCredit);
  ref.Append(*param);</strong>
  
  point.iX = rect.Width()/2 - font->TextWidthInPixels(*text)/2;
  point.iY += font->AscentInPixels() + 10;
  
  gc.UseFont(font);  
<strong>  gc.DrawText(*text,point);</strong>
  gc.DiscardFont();
  
  CleanupStack::PopAndDestroy();
}
 
</code>

You can use the emulator to run this test and check that the parameter passed is really there and is drawn nicely to the screen.

Utilizing external application views

Ok, we are almost there, and this one is really easy: just use the very same ActivateViewL() function you have been using throughout this article; the only two changes that must be done are: pass the application ID of the target application, not ours, and pass the id of the view you want to activate in that application.

The command that will launch the external view is defined in the ViewServer.hrh, associated in the resource file as below:

<code>
 
RESOURCE MENU_PANE r_ViewServer_menu
    {
    items = 
        {
        MENU_ITEM {command = EViewServerChangeCmd; txt = "Second View";},
        MENU_ITEM {command = EViewServerLaunchCalendarCmd; txt = "Launch Calendar";},
        MENU_ITEM {command = EAknSoftkeyExit;   txt = "Exit";}
        };
    }
 
</code>
 
<p>and handled in the CViewServerAppUi as follows:</p>
 
<code>
 
// handle any menu commands
void CViewServerAppUi::HandleCommandL(TInt aCommand) {
  switch(aCommand) {
    ...
    case EViewServerLaunchCalendarCmd: {
      ActivateViewL(TVwsViewId(KCalendarId,KDayViewId));
      break;
    }
 }
 
</code>

As you can see, the ActivateViewL() function takes now the KCalendarId parameter, that specifies the Application ID of the Calendar application, and the KDayViewId, that specifies the ID of the "Day" view of the same application. These values are declared earlier on the class, and have been taken from the Utilizing External Application Views v1.0 document by Forum Nokia. In this document you will find the application and message ids for many frequently used applications.

Conclusion

I shown you how the use of the Symbian View Server can help you develop complex applications more easily and with cleaner code, leading to less bugs, easier code maintenance and stronger portability. The use of the view server forces you to correctly layer your application in a way that means you can always change one part of the system without impacting the others. I also illustrated how to use semi-dynamic menus and dynamic CBAs for making the User Interface of the application more predictable and thus, easier to learn for the end user.

Most of the code create here will work, with some minor adjustments, in any version of the Symbian OS which has a View Server, so it is not tied to Series 60, UIQ or whatever; it is perfectly portable code.

In the next article I will close the View Server series by making use of the Series 60-only AvkonViews, that make even easier to use the view server by automating most of the view, menu and CBA switching, with an intensive use of the Resources file instead of C++ code.

See you there!


Many thanks to Daniel Rocha of rawsocket.org for permission to reproduce thus article.

 

Google
 
Share This Item with others - del.icio.us / Furl / Digg
Share on Facebook

Contribute to the SymbianOne Symbian Search!

Mobile Technology Blogs

 
blogger.gif

Mobile Technology Blogs, News, and RSS Feeds... Looking for more news, tips, commentary, and blogger discussions? Check out these excellent feeds for more on wireless technologies and mobile application development. Got a feed to share? Please tell us about it...

SymbianOne Sponsored Links and Events

 The European Navigation Event, October 7th and 8th 2008... where retail meets industry - The fourth edition of the No. 1 European Navigation Event will take place in the inspiring environment of the High Tech Campus in Eindhoven, The Netherlands.

Smartphone Show, 21-22 October 2008, Earls Court 2, London - The 10th annual Smartphone Show promises to be the best ever with more opportunities to see innovative technology in action and meet the key personnel driving it. 

 LBSZone.com - for developers interested in mobile location-based services
Geospatial & LBS News - Stay abreast of geospatial technologies with daily updates

See Your Message Here

Featured Symbian Career

Featured Careers...

ADDED EXPOSURE FROM SIMPLYHIRED - POST YOUR JOB FOR 30 DAYS FOR JUST $49!

Post your Symbian Career Ad for free at SymbianOne!





Visit the  SymbianOne MOSH

Syndicate


WINKsite
add to google reader
Subscribe in NewsGator Online
SymbianOne Feedster
Technocrati
SymbianOne Bloglines
AvantGo

SymbianOne on AvantGo!
Get Daily Updates!


SymbianOne FeedBlitz

Popular Stuff!

Industry Events
September 2008
MTWTFSS
1
2
3
4
5

Must Read Articles

Symbian Tools & SDKs

UIQ


News and Blogs

Top of 

Page

(c)2003 - 2008, SymbianOne - All rights reserved