Sunday 26 April 2009

Master-Detail View in ZK

In my latest ZK application, I implemented a typical master-detail view: a split bar in the middle; a tree view on the left and a table/grid on the right. Whenever an item in the treeview is clicked, the grid on the right-hand-side is updated to display the details of the clicked treeview item. The only thing 'special' about this application is that I factored the master (treeview) and details (grid) views as separate files and the main window/page uses <include> to put them together:
<?page title="" contentType="text/html;charset=UTF-8"?>
<zk>
<window border="none" width="100%" height="100%">
 <hbox spacing="0" width="100%" height="100%">
  <include src="analytical.zul"/>
  <splitter collapse="before"/>
  <include src="metricDetails.zul"/>
 </hbox>
</window>
</zk>

The <include> complicates things slightly: the master view which is firing the event has no visibility of who is going to handle the event. Therefore, the event's target field is set to null so that the event is broadcast to all root-level components on the page - including the included details view.

The event sending code is shown below. Note that the treeview of the master view is built using model and renderers and the event sending code is embedded in the renderer.

public class MetricTreeitemRenderer implements TreeitemRenderer {

 @Override
 public void render(Treeitem item, Object data) throws Exception {
  SimpleTreeNode t = (SimpleTreeNode)data;
  Metric metric = (Metric)t.getData();
  ... // construct Treecells
  Treerow tr = null;
  ... // construct the Treerow
  
  final Event e=new Event("onMetricClick", null, metric);
  tr.addEventListener(Events.ON_CLICK, new EventListener(){

   @Override
   public void onEvent(Event arg0) throws Exception {
    Events.postEvent(e);
   }
   
  });
 }
}
The event handling side is part of the included details view file:
<?page title="Metric Details" contentType="text/html;charset=UTF-8"?>
<?init class="org.zkoss.zkplus.databind.AnnotateDataBinderInit" ?>
<zk>
<window id="win" title="Metric Details" border="none" width="100%" height="100%">
<attribute name="onMetricClick">
... handle the event by populating the grid 
</attribute>
<grid id="grid" vflex="true" width="100%" height="100%">

  <columns sizable="true">
   <column label=""/>
   <column label=""/>
  </columns>
  <rows>
...
  </rows>
 </grid>
</window>
</zk>
Note that even though the <window> is inside of the <zk> tag, it is still the root component (since it has no parent component in the .zul file). Also, although the .zul file has been included in the main file, it seems that it still has its own life cycle and its root component is unchanged.

Thursday 9 April 2009

Error: Not enough storage...

For the last few days I was having problems on my IE6. Every time I use Outlook WebMail to open a modal window - e.g. bringing up the address book, I would be greeted with an error message box saying 'not enough storage is available to complete this operation'. I tolerated the problem for all this time because I could still send mails and attach files, etc. But today, I had to use IE to create a travel request for my trip to Delhi and this problem is stopping me from filling in the request form (and the travel request web application does not work on Firefox). So I was stuck and the clock is ticking for I need to finish the travel request today.

After some digging from Google I found the solution: it was caused by the User Agent string being more than 260 characters long. Huh? I was gobsmacked when I saw this. But it really works: after I deleted all entries in the 'HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\5.0\User Agent\Post Platform', (don't forget to close all instances of IE after that) my problem disappeared. Then I did some experiment to figure out what was happening.

First of all, it is well known among web designers/programmers that different browsers render the pages differently although HTML and CSS have been standardised for many years. Hence, the User Agent string is checked by many web applications to find out what browser is being used. In IE, the user agent can be retrieved using a simple javascript function: navigator.userAgent. The way Microsoft IE gets the user agent string is by appending all the values under the above registry entry. You can see this by creating some new values under the above registry entry. You may get a user agent string like: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1) ; New Value #1; lsfjsafj sf;dsfj sakf lksjf salkfjas lkfjlksfj safkjsa lkfsajf ;lksjflksajf lksa;fj salkfjsa kfdsalk). As more values being inserted in the entry, the user agent string will get longer and longer, until it exceeds 260 characters, then it will simply return: Mozilla/4.0 (compatible; MSIE 6.0), obviously some default value without appending any values from the Windows registry.

That would have been fine if there were no other side effects. Unfortunately, maybe some other Microsoft jscript libraries have not catered for this and produce the 'not enough storage...' problem.

In his blog, James Thompson blamed toolbars and spywares for the extra values in the registry entry. In my case, all the values in the registry entry were from Microsoft - it looks like everytime I upgraded .NET, a new value was created:

So if you have been doggedly upgrading .NET all the way from 1.0 to 3.5 like me, then you would be experiencing the same problem as well. Looks like Microsoft does a more thorough job than those spyware vendors.