Nov 19 2008

SmartGWT 1.0

Tag: Gwt, Web, smartgwtAbhijeet Maharana @ 1:45 am

SmartGWT 1.0, a web application library based on SmartClient and GWT, was released this Monday. From the release announcement at Sanjiv’s blog and the showcase demos, it is evident that this library packs a lot of power and is definitely worth checking out. I have come across SmartClient only recently. And now that I know of it, Ill try and get acquainted with it when I can.

Links:
SmartClient: http://www.smartclient.com/
SmartGWT: http://code.google.com/p/smartgwt/
Visual Builder videos: http://www.smartclient.com/technology/visualbuilder.jsp


Oct 26 2008

Google chat and FoxClocks

Tag: Chat, Firefox, WebAbhijeet Maharana @ 11:13 pm

Google Chat

It once happened that I did not recollect adding someone on GTalk and yet the contact showed up in my buddy list. I thought maybe the other guy did and that I forgot about it after accepting the request. Then it started happening very frequently and I had no clue.

Well, it turns out that if you communicate frequently with some people, GMail automatically allows them to chat with you and see when you are online. Its great to make new friends and learn from new people but sometimes, its just better to know who is on your buddy list! To turn this otherwise helpful feature off, log into your Gmail account and go to Settings >> Chat. Select “Only allow people that I’ve explicitly approved to chat with me and see when I’m online.”


FoxClocks

If you work across timezones, you will probably agree that having to remember / calculate the time at your client’s end isn’t always a fun thing to do. I had a couple of Timezone widgets added to my iGoogle page but I didn’t find them compelling. Just last week, I noticed Andy McDonald’s FoxClocks as a recommended extension on the Firefox add-on page. One look at the screenshot and I blinked only after it was installed. Needless to say, its a very well-made, unobtrusive extension which sits in the statusbar / toolbar and is right there when you need it. Highly customizable and highly recommended.


Sep 28 2008

GWT-Ext and jQuery input mask plugin

Tag: Ext, Gwt, Java, Javascript, Programming, WebAbhijeet Maharana @ 1:59 am

Yesterday, while dabbling with jQuery and getting amazed by the wealth of plugins and effects available for this library, I came across http://digitalbush.com/2008/07/31/masked-input-plugin-114/. It allows you to fit text fields with an input mask to allow only fixed-width input in a certain format. I had seen it first in MS Access a long long time ago.

To use it with GWT-Ext, include jquery.js and jquery.maskedinput.js in your host HTML file. Use <script></script> and not <script/> to avoid wasting time later.

<script language = "javascript" type="text/javascript" src="js/jquery.js" ></script>
<script language = "javascript" type="text/javascript" src="js/jquery.maskedinput.js" ></script>

Now write some native code to call the plugin’s methods:

private native void addPlaceholder(String placeholder, String maskString) /*-{
	$wnd.$.mask.addPlaceholder(placeholder, maskString);
}-*/;
 
private native void mask(String id, String maskString, String placeholderString) /*-{
	if(placeholderString != null)
		$wnd.$('#' + id).mask(maskString, {placeholder:placeholderString});
	else
		$wnd.$('#' + id).mask(maskString);
}-*/;

Add the mask to a text field:

addPlaceholder("~", "[+-]");
textField.doOnRender(new Function(){
	public void execute() {
		mask(textField.getId(), "Rs. ~9999.99/-", " ");
	}
});

This will only allow values of the type “Rs. +2345.50/-” with “Rs. ” and “/-” already filled in for the user.

Update: See this: http://gwt-ext.com/forum/viewtopic.php?f=9&t=2984. Thanks mdeg and vanderbill!


Sep 03 2008

Google Chrome

Tag: WebAbhijeet Maharana @ 2:16 am

Google Chrome is all over the place – websites, blogs, Twitter, here, there …. Instinctively, I checked it out just now and my first reaction was “Ah! Its sexy!”. I am sold on the UI alone. Its simple, clean, futuristic. And sexy! I am not going to post the nitty gritty details because you can read about it here. And of course, the comic book!

  • The UI, as I have mentioned floored me completely. I like sleek looking apps. Everyone does!
  • Task manager: Right click the Chrome task bar button or the title bar ..err.. tab bar to get the Task Manager. Kill individual tabs and plugins to your heart’s content! I killed the Flash plugin and all tabs displayed an error message where Flash content was present. But the tabs and everything else were working fine. This also shows detailed “stats for nerds” in a tab.
  • Google Gears: Its integrated right into the browser. Speed difference is quite evident and specially applicable to application shortcuts on the desktop.
  • Developer tools: It has a sleek looking DOM inspector. Its like Firebug but a lot could be added. One thing Ill miss for sure is the “Inspect element” button in Firebug. Although I can right click a page element and inspect it, it would have been lot better if it was also within the DOM inspector. Or is it tucked in somewhere and I missed it?

Chrome has generated a lot of excitement. It would be great to see how it influences the web and the developers out there. Till then, I have a few things to figure out:

  • How to get the menu bar back (if there is one).
  • How to get the status bar to always show up. Not seeing the status bar even for a second gives me creeps!
  • What sites to browse with incognito.
  • What works and what doesn’t with this shiny new toy.

More than all this, after the terrible experience I had while developing for IE6 few years back, I am hoping that Chrome will clear up some of the mess that web development is. I haven’t had a serious brush with Webkit till now. But I guess its about time to do that.

Update: Jyoti had a weird “The application failed to initialize properly” error and she managed to track it down to this issue: http://code.google.com/p/chromium/issues/detail?id=38. Looks like a lot of people having trouble with it.


Aug 15 2008

GWT-Ext enhanced HTMLEditor

Tag: Ext, Gwt, Programming, WebAbhijeet Maharana @ 11:45 pm

Quite sometime back, Khadaa commented that Dan’s HTMLEditor would be a good plugin to have as part of the GWT-Ext-UX project. I have just committed the GWT-Ext wrapper code. The wrapper code is quite small but I was stuck with some nasty bugs which took some time to squish. And I learnt a couple of things in the process.

Logs say that quite a number of readers arrived here searching for GWT-Ext HtmlEditor. Check out from SVN to start using the widget right away. Only the styles plugin is in. Undo/redo and images plugins are pending. Will try to work on them soon. If you want to add them to the project yourself, go right ahead.

Related links:


Aug 11 2008

PicLens and Pencil

Tag: Links, WebAbhijeet Maharana @ 1:16 am

PicLens

Just fell in love with this one moments ago! I had installed its Firefox extension version “just like that” while browsing the Mozilla addons site. Half an hour back, Preshit sent me a Flickr link. I happened to click the run image on one of the photos and PicLens fired up as I watched. It jumped out of Firefox, took the entire screen and transformed the dull 2D view to a fullscreen 3D view. It made viewing the pics lot more easy and pleasurable. And I decided I like it.

Edit: PicLens is now Cooliris. See the comments.

Pencil

This one has been receiving quite some attention lately and I see why. Its a very simple and effective diagramming tool. Lets you create diagrams and UI prototypes in a jiffy. After having to switch tools when I switch OSes (and I do that once in a while to get a different experience), this one is a must-have extension for my fox. The stock stencils that come with it are good enough. And, I am eagerly waiting for more stencils to become available.


Aug 01 2008

Search GWT-Ext forums better

Tag: Ext, Gwt, Links, WebAbhijeet Maharana @ 1:47 am

Gwt-Ext forum threads have quite a lot of solutions contributed by users. But the forum search is a real pain and I have to struggle a lot for finding what I am looking for.

Use this *very helpful* Google custom search for searching the forums and most likely you will find your question already answered: http://www.google.com/coop/cse?cx=014252995673596707595%3Ao37mulitp-e.

I wonder why I didn’t think of this before seeing Sanjiv’s post!


Jun 11 2008

Gwt-Ext 2.0.4 is out

Tag: Ext, Gwt, Java, Programming, WebAbhijeet Maharana @ 10:37 pm

Gwt-Ext 2.0.4 was released today. Mario announced the release at http://gwt-ext.com/forum/viewtopic.php?f=12&t=1622. I quote from the release notes.

Features

  • Support for GWT 1.5 RC1
  • FF3 Support
  • PageBus
    Messaging support which allows loosely coupled components to communicate with each other via traditional pubhish / subscribe paradigm. See demo in Showcase under ‘Miscellaneous -> Publish Subscribe’

  • Eclipse Project Files
    You can now use GWTExt directly from SVN as an Eclipse project. You just need to add the GWT_HOME variable to point to the GWT Directory in Eclipse
    Windows|Preferences|Java|Build Path|Classpath Variables

Changes

  • Various Bug Fixes
  • Fixed Memory leak when add and remove Panels (Mix of GWT and GWT-Ext)

GwtExtUx Changes

  • FileTreePanel
  • SwfUploadPanel
  • CustomReader
  • Removed individual UX from GwtExtUx.gwt.xml. This means whenever a UX is needed, They have to be added individually in the users gwt.xml file.
  • Latest patch in Multiselect.js including memory leak fixes, drag back, etc…

Download the latest version from http://gwt-ext.com/download/. Gwt-Ext-UX is being subjected to some last minute tests and a new version should be out in a couple of days.

If you have just started, the forums are always buzzing with activity and you are most welcome. These beginner screencasts may also be helpful.


Jun 04 2008

Gwt-Ext Custom Reader

Tag: Ext, Gwt, Java, Javascript, Programming, WebAbhijeet Maharana @ 11:36 pm

Screenshot

If I had to populate a Gwt-Ext store with data in arbitrary format,

  1. I could parse data on the client and use a MemoryProxy + ArrayReader or

  2. I could have the server do the parsing and send JSON data to the client which could then be handled by a JsonReader for populating the store.

This thread at Gwt-Ext.com made me wonder if a good third option would be to have a reader that can be used directly with the store and proxy mechanism and that allows one to write parsing logic in Java on the client. I have attempted a CustomReader that does just that. You can use it with a proxy that fetches remote data.

CustomReader registers an Ext user extension of the same name. Ill refer to them as JavaCustomReader and JSCustomReader to avoid confusion. JavaCustomReader has a static method for registering the user extension.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
...
static {
	init();
}
...
private static native void init()/*-{
	$wnd.Ext.namespace("GwtExt");
 
        $wnd.GwtExt.CustomReader = function(meta, recordType, readerInstance) {
	      	meta = meta || {};
	       	this.readerInstance = readerInstance;
	        $wnd.GwtExt.CustomReader.superclass.constructor.call(this);
	};
 
	$wnd.Ext.extend($wnd.GwtExt.CustomReader, $wnd.Ext.data.DataReader, {
	      	read : function(response){
	       		return this.readerInstance.@com.maharana.gwtextcustomreader.client.CustomReader::read(Lcom/google/gwt/core/client/JavaScriptObject;)(response);
	        	},
 
        	readRecords : function(o){
			alert('Custom reader does not work with local data.');
        	}
        });
}-*/;

JSCustomReader is passed one additional parameter when it is instantiated. This parameter is a reference to the JavaCustomReader that created it.

1
2
3
protected native JavaScriptObject create(JavaScriptObject config, JavaScriptObject recordDef)/*-{
	return new $wnd.GwtExt.CustomReader(config, recordDef, this);
}-*/;

JSCustomReader’s read() method is called by a proxy which has finished loading remote data. The proxy expects a return object with the success status, total record count and actual records as its fields. JSCustomReader invokes JavaCustomReader.read() which looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public JavaScriptObject read(JavaScriptObject response) {
	ReaderResult r = handleRemoteResponse(new RemoteResponse(response));
	JavaScriptObject o = JavaScriptObjectHelper.createObject();
 
	JavaScriptObjectHelper.setAttribute(o, "success", r.success);
 
	JavaScriptObject[] jsRecords = new JavaScriptObject[r.records.length];
	for(int i =0; i<r.records.length;i++)
		jsRecords[i] = r.records[i].getJsObj();
 
	JavaScriptObjectHelper.setAttribute(o, "records", JavaScriptObjectHelper.convertToJavaScriptArray(jsRecords));
	JavaScriptObjectHelper.setAttribute(o, "totalRecords", r.records.length);
 
	return o;
}
 
// subclass and put your parsing logic here
public abstract ReaderResult handleRemoteResponse(RemoteResponse remoteResponse);

In turn, it handles the to/from JavaScriptObject stuff and calls handleRemoteResponse(). Users just need to provide their parsing code in this method in derived classes. RemoteResponse and ReaderResult are convenience classes.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class RemoteResponse {
	JavaScriptObject response;
 
	public RemoteResponse(JavaScriptObject response) {
		this.response = response;
	}
	public String getResponseText() {
		return JavaScriptObjectHelper.getAttribute(response, "responseText");
	}
	public String getResponseXML() {
		return JavaScriptObjectHelper.getAttribute(response, "responseXML");
	}
}
 
class ReaderResult {
	public final boolean success;
	public final Record[] records;
 
	public ReaderResult(boolean success, Record[] records) {
		this.success = success;
		this.records = records;
	}
}

This completes CustomReader. As an example, I made a simple CSV parsing reader as mentioned in that thread at Gwt-Ext.com. This reader gets stock quotes from Yahoo finance as a CSV file and creates records out of them.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
RecordDef recordDef = new RecordDef(  
	new FieldDef[]{  
        	new StringFieldDef("name"),
                new StringFieldDef("lasttrdate"),
                new StringFieldDef("lasttrval")
        }
); 
 
CustomReader c = new CustomReader(recordDef,1){
       	 public ReaderResult handleRemoteResponse(RemoteResponse remoteResponse) {
 
       		String csvalue = remoteResponse.getResponseText();
 
       		String[] lines = csvalue.split("\n");
       		Record[] records = new Record[lines.length];
 
       		for(int i=0; i<lines.length; ++i)
       		{
       			String[] columns = lines[i]. replace('\"', ' ').split(",");
       			records[i] = this.recordDef.createRecord(columns);
       		}
 
       		return new ReaderResult(true, records);
       	}
};

For getting the file from Yahoo, I made a utility Servlet Redirect.java which fetches the contents of a url and passes it to the client.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	String queryString = request.getQueryString();
	String address = queryString.split("url=")[1];
	URL url = new URL(address);
 
	PrintStream out = new PrintStream(response.getOutputStream());
	String inputLine = "";
	BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()));
	while((inputLine = br.readLine()) != null)
	{
		// System.out.println(inputLine);
		out.println(inputLine);
	}
 
	out.close();
}

It is invoked by an HttpProxy on the client as follows:

1
2
3
4
5
6
...
String url = "http://download.finance.yahoo.com/d/quotes.csv?s=INFY+XOM+BBDb.TO+JNJ+MSFT+GOOG+YHOO&f=nd1l1";
DataProxy proxy = new HttpProxy("redirect?url=" + url);
 
Store store = new Store(proxy, c);	// CustomReader c from above
...

Once we have the utility servlet and CustomReader as part of the project, I think it will be relatively easier to populate stores with any arbitrary format data. Feel free to drop your comments / suggestions. I would love to hear them.

Download Eclipse project from Gwt-Ext.com or Rapidshare

Reference: GwtProxy by michal.bergmann


May 16 2008

Gwt-Ext and Number Madness

Tag: Ext, Gwt, Java, Javascript, Programming, WebAbhijeet Maharana @ 11:52 pm

Gwt-Ext Number Madness screenshotThis is the 3rd form of my game Number madness. I had first written it using TurboC during the vacation after junior college. And then as a Firefox extension. Both are available in the projects section.

Using Gwt-Ext for writing something like this sounds a bit silly. But it did make me learn something new: button templates; thanks to gwtext+ and sjivan. I have described the program below in brief. You can download Eclipse project from the link at the end of this post.

An Ext button is made up of a table with 3 columns. All three columns have parts of the button sprite as their background image and the center TD holds a <button> element. You can see this template in Button.java above the setTemplate() method definition:

1
2
3
4
5
6
7
8
9
10
<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap">
	<tbody>
		<tr>
	     		<td class="x-btn-left"><i>&#160;</i></td>
	     		<td class="x-btn-center">
	     			<em unselectable="on"><button class="x-btn-text" type="{1}">{0}</button></em></td>
	     		<td class="x-btn-right"><i>&#160;</i></td>
	     	</tr>
	</tbody>
</table>

We can override this template to make the button look as we want it to. My modified template looks as shown below. There is only one extra CSS class for the table (see notes at end):

1
2
3
4
5
6
7
8
9
10
<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap mybutton">
	<tbody>
		<tr>
	     		<td class="x-btn-left"><i>&#160;</i></td>
	     		<td class="x-btn-center">
	     			<em unselectable="on"><button class="x-btn-text" type="{1}">{0}</button></em></td>
	     		<td class="x-btn-right"><i>&#160;</i></td>
	     	</tr>
	</tbody>
</table>

This enables us to use CSS nesting to define x-btn-left, x-btn-center, x-btn-right and x-btn-text with the attributes we want while preventing the normal buttons from being affected. Thus we can use both Ext’s buttons and out custom buttons at the same time. I have defined them as:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
.mybutton .x-btn-right {
	background: transparent url('button_right_06.png') no-repeat scroll right; 
	height: 150px;
	padding-right: 15px;
}
 
.mybutton .x-btn-left {
	background: transparent url('button_left_06.png') no-repeat scroll right; 
	height: 150px;
	padding-right: 15px;
}
 
.mybutton .x-btn-center {
	background: transparent url('button_06.png') repeat-x center; 
	height:150px;
	width:80px;
	text-align:center;
}
 
.mybutton .x-btn-text {
	line-height: 150px;
	font-family: Arial, Helvetica, sans-serif;
	font-size:60px;
	font-weight:bold;
}

I have used custom images that make up the button’s left, center and right components. I have also changed the appearance of the text displayed on the button.

Now that we have the buttons which make up the game board, lets take a brief look at the rest of the game. An integer array holds the numbers that map to each button on the board. This array is populated randomly at start. Although the board is 2D, I decided to use a 1D array as it turned out to be slightly simpler while populating the random numbers. So arr2D[i][j] becomes arr1D[i * numcols + j] where numcols is the number of columns in each row.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private void generateRandomNumbers()
{
	int i,j;
	int temp;
	boolean suitable;
	int total = numRows*numCols-1;
 
	for(i=0;i<=total;i++)
	{
		do
		{
			suitable = true;
			temp = (int) Math.round(Math.random() * total);
			for(j=0;j<i;j++)
			{
				if(numbers[j] == temp)
				{
					suitable = false;
					break;
				}
			}
		}while(!suitable);
 
		numbers[i] = temp;
	}
}

Once the array is ready, I set the Panel’s layout to TableLayout with 3 columns and call createGrid() to create buttons that make up the grid. Every button knows its (row,column) position and the blank square is made up of an invisible button.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
private void createGrid()
{
	for(int i=0; i<numRows; ++i)
	{
		for(int j=0; j<numCols; ++j)
		{
			int index = i*numCols + j;
 
			String label = String.valueOf(numbers[i*numCols + j]);
			final Button btn = new Button(label);
			btn.setTemplate(buttonTemplate);
 
			// listener is an instance of SquareListener
			btn.addListener(listener);
 
			// every button keeps track of its row and column number
			final int finali = i, finalj=j;
			btn.addListener("render", new Function(){
				public void execute() {
					JavaScriptObjectHelper.setAttribute(btn.getJsObj(), "row", finali);
					JavaScriptObjectHelper.setAttribute(btn.getJsObj(), "col", finalj);
				}
			});
 
			// empty square = invisible button
			// maintain a class-level reference to the empty square
			if (numbers[index] == 0)
			{
				emptyButton = btn;
				btn.setVisible(false);
			}
 
			add(btn);
		}
	}
}

The button listener checks if the clicked button is adjacent to the empty square. If it is, it swaps numbers in the array and on the buttons. The invisible button is now made visible and clicked button becomes invisible. I have added a fade in and fade out effect. However, this is shaky and sometimes the button doesn’t fade in for too long. It does irritate a bit. After this, the endgame is checked i.e. if numbers in the array are in ascending order.

I have left out some code to keep the post short. You can download the complete project from Gwt-Ext.com or Rapidshare.

Note:

  1. Since our new template just has an extra CSS class, the whole template thing could be avoided by calling btn.setCls(“mybutton”). This was an after-thought when I was done playing with the template.
  2. When you change the template, keep the <button> element otherwise you will get an exception at load time
    1
    2
    3
    4
    5
    
    [ERROR] Unable to load module entry point class com.maharana.gwtextnumbermadness.client.MainModule (see associated exception for details)
    com.google.gwt.core.client.JavaScriptException: JavaScript TypeError exception: btnEl has no properties
    	at com.google.gwt.dev.shell.ModuleSpace.invokeNative(ModuleSpace.java:481)
    	at com.google.gwt.dev.shell.ModuleSpace.invokeNativeHandle(ModuleSpace.java:225)
    	...
  3. Also keep the x-btn-center CSS class name otherwise you will get an exception when the button is clicked
    1
    2
    3
    4
    5
    
    [WARN] Exception thrown into JavaScript
    com.google.gwt.core.client.JavaScriptException: JavaScript TypeError exception: this.el.child("td.x-btn-center " + this.buttonSelector) has no properties
    	at com.google.gwt.dev.shell.ModuleSpace.invokeNative(ModuleSpace.java:481)
    	at com.google.gwt.dev.shell.ModuleSpace.invokeNativeVoid(ModuleSpace.java:270)
    	...

References:

  1. Images for new button template: http://www.jankoatwarpspeed.com/post/2008/04/30/make-fancy-buttons-using-css-sliding-doors-technique.aspx
  2. CSS nesting: http://webdesignfromscratch.com/css-inheritance-cascade.cfm
  3. Centering block level elements: http://dorward.me.uk/www/centre/#content

Do let me know if you have any corrections or suggestions.


Next Page »