In a recent project, I came across a peculiar requirement.
Modified version of the requirement:
1. Define a static variable in base class (say Code)
2. Define a property in base class that accesses Code (say Message)
3. Modify the value of Code in derived class
4. BaseInstance.Message should access the value of Code defined in base class whereas DerivedInstance.Message should access the one defined in derived class.
So I tried the following
namespace StaticTest
{
class Base
{
protected static int Code = 1;
public String Message
{
get
{
switch (Code)
{
case 1:
return "One";
case 2:
return "Two";
}
return "Default";
}
}
}
class Derived : Base
{
protected static new int Code = 2;
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Base.Message: " + new Base().Message);
Console.WriteLine("Derived.Message: " + new Derived().Message);
Console.Read();
}
}
}
This did not work and the output was
Base.Message: One
Derived.Message: One
Turns out that Message needs to be redefined in Derived to be able to access the new value of Code. With a lot of derived classes, this was impractical and Message’s getter was a bit more involved than what I have written above.
I found a neat solution by Dave Booker posted here.
Define a custom attribute class
[AttributeUsage(AttributeTargets.Class, Inherited = true)]
public class CodeAttribute : Attribute
{
public int Code;
public CodeAttribute(int code)
{
Code = code;
}
}
Then define attribute values for the 2 classes:
[CodeAttribute(1)]
class Base
{ ... }
[CodeAttribute(2)]
class Derived
{ ... }
Now delete the Code property from the classes and modify Message to retrieve the code like this:
public String Message
{
get
{
int Code = ((CodeAttribute) Attribute.GetCustomAttribute(this.GetType(), typeof(CodeAttribute))).Code;
switch (Code)
{
case 1:
return "One";
case 2:
return "Two";
}
return "Default";
}
}
This returned the values as expected. If the derived class is not supplied with an attribute value, it just inherits the value from its parent. So not exactly a static variable but it behaves like one that can be inherited and overriden if necessary. Quite elegant!
The original requirement was to eliminate any instances of both classes. This meant Message had to be a static property. I haven’t been able to figure out how to do that … specifically how to replace “this.GetType()” with something static that returns which class the property was invoked with rather than the class which it was defined in (which is what the reflection based methods do).
Any ideas? Other than getting into IL code to see if and how this can be done?
I conducted a workshop on OpenGL today. It was in the same college where I completed my Engineering, SFIT Borivali. I had done it for the first time in 2003. And I remember how nervous I was because I was in the 2nd year and almost everyone who participated was a senior! Although everyone was from 2nd year this time, it wasn’t much different. I was as nervous when I started off because I had done this 3 years back and couldn’t go through the content even once. However I had saved all the material used earlier and this saved me lots of time.
I was nostalgic all the time. Same college, same labs, not the same machines but I had worked on these machines before moving out. Brought back all those memories. All new faces but the same curiosity which made me spend an entire semester struggling to figure out how VC++ 6 is different from Turbo C and why Turbo C won’t compile the OpenGL programs that I had downloaded! And how GLUT came to my rescue before my curiosity died while meddling with the Windows API! In the rush to make a living by working on stuff that the industry pays for, that curiosity has had to take a backseat after I got out from college. But it felt very nice to get back after such a long time! If someone could pay for my material needs while I did this, nothing like it!
Ajesh came along to help the participants. Thanx a ton man! He clicked a few snaps. Ill put them up in the wokshops section. Now back to the present and back to the task at hand
SmartGWT widgets can render themselves sensibly using the data source definition. So for a grid, we don’t need to define the columns explicitly. However, we can override the rendering of some or all columns as needed.
Assume that our data source and data looks like this:
class CompanyDataSource extends DataSource {
public CompanyDataSource(String id) {
setID(id);
DataSourceTextField companyName = new DataSourceTextField("company", "Company");
DataSourceFloatField price = new DataSourceFloatField("price", "Price");
DataSourceDateField lastChanged = new DataSourceDateField("lastChanged", "Last Changed");
setFields(companyName, price, lastChanged);
}
}
"3m Co", "71.72", "9/1 01:25 AM"
And the grid that renders this data
DataSource dataSource = new CompanyDataSource(“companyList1”);
dataSource.setClientOnly(true);
ListGrid companyGrid = new ListGrid();
companyGrid.setHeight(300);
companyGrid.setWidth(500);
companyGrid.setTitle("SmartGWT grid");
companyGrid.setDataSource(dataSource);
companyGrid.setAutoFetchData(true);
To override the display format of lastChanged column, one approach would be
ListGridField lastChangedField = new ListGridField("lastChanged", "Last Changed (new title)", 180);
CellFormatter dateFormatter = new CellFormatter(){
public String format(Object value, ListGridRecord record, int rowNum, int colNum) {
DateTimeFormat inputFormat = DateTimeFormat.getFormat("d/M hh:mm a");
DateTimeFormat outputFormat = DateTimeFormat.getFormat("MMM dd HH 'hours' mm 'minutes'");
Date inputDate = inputFormat.parse(value.toString());
String output = outputFormat.format(inputDate);
return output;
}
};
lastChangedField.setCellFormatter(dateFormatter);
companyGrid.setFields(lastChangedField);
We define a ListGridField with the same name “lastChanged” as in the data source. SmartGWT will use this name to do the merge. Our custom cell formatter matches the input date format and returns it in a different format.
But now the grid will only display this field. To cause it to display other data source fields as they are, we need to call
companyGrid.setUseAllDataSourceFields(true);
We can also override the date format in the data source itself so that all widgets sourcing this data will reflect it. As I was thinking about this, I came across this post on the SmartGWT forums. The API will support this functionality soon and as that thread also mentions, for formatting dates, you can use ListGrid.setDateFormatter() and DateItem.setDisplayFormat().
Thats it for this time. Ill keep posting tidbits as I learn along the way.
GWT-Ext Store instances are all over my code. And I am populating them by various means. While migrating from GWT-Ext to SmartGWT, converting Stores to DataSources will probably take up a lot of time. I was wondering if I could migrate and test only the grids first and deal with the stores later. Code below could help do just that. It creates a DataSource from a Store. You can use this data source to populate SmartGWT grids and when the grids are working fine, replace the stores completely. Isn’t exactly a life saver but nevertheless. Have tested it only on a trivial store.
It doesn’t matter but assume that the RecordDef used to create the Store looks like this:
RecordDef recordDef = new RecordDef(new FieldDef[] {
new StringFieldDef("company"),
new FloatFieldDef("price"),
new FloatFieldDef("change"),
new FloatFieldDef("pctChange"),
new DateFieldDef("lastChanged", "n/j h:ia"),
new StringFieldDef("symbol"),
new StringFieldDef("industry")
});
Create a DataSource with the same fields:
private DataSource createDataSource(Store store){
DataSource dataSource = new DataSource();
dataSource.setClientOnly(true);
String[] fields = store.getFields();
for(String field:fields) {
DataSourceField smartgwtField = new DataSourceField();
smartgwtField.setName(field);
dataSource.addField(smartgwtField);
}
return dataSource;
}
Add a method that copies records from the Store to the data source created above and call it in the Store’s onLoad handler
public void copyStore(Store store, DataSource dataSource) {
Record[] records = store.getRecords();
String[] fields = store.getFields();
for(Record gwtextRecord:records) {
ListGridRecord smartgwtRecord = new ListGridRecord();
for(String field:fields) {
smartgwtRecord.setAttribute(field, gwtextRecord.getAsString(field));
}
dataSource.addData(smartgwtRecord);
}
}
For heavy stores, this code will probably punish the browser and column data types are ignored as well but it is meant only for the dev environment until all components have been replaced eventually.
PS: If you need it, here is a small sample with GWT-Ext and SmartGWT grids being populated from the same RPC method. You will need to add gwtext.jar and smartgwt.jar and use Cypal studio plugin or add compile/run scripts.
I needed to install Trac on my laptop. Trac is an enhanced wiki and issue tracking system for software development projects. I had used it about 2 years back and had liked it then. However, I had never installed it myself. I assumed it will be like any other installation. But just after starting out, I realized that I was grossly mistaken. Installing Trac and getting it running with the webadmin plugin and users configured for your projects is a little more than a post-work headache.
I have the following setup:
- OS: Vista business 32-bit
- Python: Not already installed on my system
After installation, we will be running Trac 0.10.4 with webadmin plugin and users configured for a project. This installation will be running on Apache and we won’t be using Trac’s standalone webserver (tracd). I am not using Trac’s subversion feature since I am already running VisualSVN server (and I love its ease of use). Ill try to switch sometime later if thats not another royal pain.
It turns out that the steps are quite simple … if you happen to know them.
You should have the Trac installation running now. Backup is as simple as creating a copy of the “projects” folder. If you can’t see the admin link on the upper right corner after all this, be prepared to spend the night getting it to show up. Start here!
Finally, if you have any Trac tips up your sleeve, I would love to read them. Things such as setting up multiple projects, having different sets of users for projects …
Update (27/11): Help Mumbai page with all relevant phone numbers: http://helpmumbai.pinstorm.com/
There is a lot of trouble in Mumbai, India right now. There are terrorists throughout the city and if you switch the television on at this moment (2 AM), you will lose your nerves. If you want to touchbase with your dear ones here but are not able to get through, leave a message with your and your friend’s numbers. I will try to get through to them as frequently as I can. If you are in Mumbai and can help folks, try and answer the queries here or leave your number here.
Blood needed at various hospitals (source: IBN live stream):
St. George’s hospital: (022) 22620242
JJ Hospital: (022) 23739031
CNN IBN Live Streaming: http://tinyurl.com/644733
DFAT emergency number: 1300 555 135 (via @AnneBB)
http://twitter.com/squorch/status/1025372562
http://twitter.com/Asfaq/statuses/1025385789
Mumbai police telephone numbers: http://www.mumbaipolice.org/imp_telnfax.htm
Wikipedia article: http://en.wikipedia.org/wiki/26_November_2008_Mumbai_attacks
Update: There are people at MumbaiHelp who can help as well http://mumbaihelp.blogspot.com/2008/11/can-we-help.html
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
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.
While working with a GWT-Ext application, I found that most of the Combo boxes used are just meant to be readonly drop down lists. Like the style 2 combo boxes we had in VB. A 2D array with display and value fields is all that is needed. Yet, every combo needs 6-7 lines to get going.
This utility method may be handy in such situations:
public static ComboBox getDropDownCombo(Object[][] data, String fieldLabel, String emptyText, int width, int listWidth)
{
Store store = new SimpleStore(new String[]{"display", "value"}, data);
ComboBox combo = new ComboBox();
combo.setEditable(false);
combo.setStore(store);
combo.setDisplayField("display");
combo.setValueField("value");
combo.setMode(ComboBox.LOCAL);
combo.setTriggerAction(ComboBox.ALL);
if(fieldLabel != null)
combo.setFieldLabel(fieldLabel);
else
combo.setHideLabel(true);
if(width != -1)
combo.setWidth(width);
if(listWidth != -1)
combo.setListWidth(listWidth);
if(emptyText != null)
combo.setEmptyText(emptyText);
else
// if there is no empty text, select the first value by default
combo.setValue(data[0][1].toString());
return combo;
}
Sample usage could be:
String[][] data = {{ "Mark as read", "1"}, {"Mark as unread", "2"}, {"Add star", "3"}, {"Remove star", "4"}};
ComboBox cmbMin = UIHelper.getDropDownCombo(data, "Actions", "[Select]", 275, -1);
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!