Tuesday, September 4, 2012

Browsers, Browsers, Browsers

After several years of working with HTML, CSS and now GWT and Javascript, it has become quite clear that each browser is going to do things slightly different than others.  This just keeps the engineer on their toes; adds some danger to the mix; provides for some fun with borders and gradients and colors and buttons.

Here's some lessons I've learned recently in getting my GWT application to run across Safari, Chrome, Firefox, Internet Explorer and the Webkit mobile phone browsers.

1. Drawing on a canvas.  My application uses a third party javascript drawing package that uses a canvas for drawing elaborate diagrams.  This works great on all my browsers, except Internet Explorer. Nothing is drawn.  Alas, Internet Explorer doesn't have this native canvas built into it and must be given one.  In my main html file the addition of:

       <!--[if IE]><script language="javascript" type="text/javascript" src="excanvas.js"></script><![endif]-->

did the trick.

2. Right click popup menus.  Any right click you do in a browser produces the typical browser popup menu.  The one to View Source, or Open in New Window.  However, what about when I want to implement my own right click popups and put up my own menus.  In my main html file the addition of:


<body oncontextmenu = "return false;">


did the trick here too.  Now only my popup menus show up and nothing else.


3.  Gradients.  Those light to dark or dark to light backgrounds that make your screen really stand out and look slick.  The following displays a white to blue gradient and works on all browsers.


filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFF', endColorstr='#F3F7FB'); /* IE compatible */

background: -webkit-gradient(linear, left top, left bottom, from(#FFFFFF), to(#F3F7FB)); /* Webkit compatible */

background: -moz-linear-gradient(top,  #FFFFFF,  #F3F7FB); /* Firefox compatible */ 

4. Mobile phone.  Any browser based application, like GWT, should also run on all the mobile platform browsers by default.  But what if you application is just too big to fit nicely or to be useable on a mobile platform?  In this case, you should think about presenting the data in a different view on a mobile device as opposed to being on laptop/desktop computer with adequate screen real estate.  Here's two critical things I did to build a mobile version of my GWT app:

 First - how to detect if my application is trying to be run on Android or iPhone?

        // Is this an Android or iPhone device?
        if (Navigator.getUserAgent() != null)
        {
            if (Navigator.getUserAgent().toLowerCase().contains("android") ||
                Navigator.getUserAgent().toLowerCase().contains("iphone"))
            {
                mobileDevice = true;
            }
        }

Second - how to scale my view to fill the screen on the detect smartphone?

<meta name="viewport" content="width=device-width,initial-scale=1.0" />

Was added to my main html file.  In my case, rather than show my entire GWT application on a mobile device, I chose to show just a list of objects with the ability to touch each one and see more details.  Something simple, something usable, something informative, something that fits on the phone.

As I continue down the path of GWT....I'm sure there will be more browser tweaks needed...keeps me on my toes.

  


Thursday, August 2, 2012

GWT Tricks #3

I love when a simple and elegant solution can be easily integrated into my software.  That doesn't always happen, but I truly believe in the KISS principle, especially when architecting and building complex UI applications that have lots of moving parts.

It was brought to my attention that my empty GWT tables were displaying "1-1 of 0" for my SimplePager display.  This was not my code, but was coming from Googles GWT pager implementation.  A web search showed this was an issue that a lot of folks were complaining about.

To be fair, there's no data in the table, and it clearly says "0" items.   Some web searches showed solutions about overriding GWT code and reimplementing the counter mechanisms.  That led me on my way to a solution.  If my table was empty, I want to display my own text, something like "0 of 0", otherwise, I want to let GWT do the calculation.

The solution was to create my own class that extends the GWT SimplePager and then override the createText() method that displays the counter information:



public class MyPager extends SimplePager
{
    public MyPager(final TextLocation center, final Resources pagerResources, final boolean showFastForwardButton,
                       final int fastForwardRows, final boolean showLastPageButton)
    {
        super(center, pagerResources, showFastForwardButton, fastForwardRows, showLastPageButton);
    }


    // Bug with pager that says 1-1 of 0 when the list is empty. fix it to say 0 of 0.
    @Override
    protected String createText()
    {
        final HasRows display = getDisplay();
        final int dataSize = display.getRowCount();

        if (dataSize == 0)
        {
            return "0 of 0";
        }
        else
        {
            return super.createText();
        }
    }
}

Then just use this new pager for my table:

MyPager pager = new MyPager(SimplePager.TextLocation.CENTER, pagerResources, false, 0, true);


Friday, June 1, 2012

GWT - Flash - Swing [Lessons learned]

Approximately one year ago I joined a new startup company and had to decide what technology would be used to build a new highly graphical application.  The requirements were :

  • display dashboard pseudo realtime charts and tables
  • display graphs of objects and their associations and links
  • make it feel like a state of the art application with some coolness factor
  • make it usable and intuitive
  • make it scale
So I built some sample screens using Java Swing, the Google Web Toolkit and Adobe's Flash.  I was able to somewhat build the same screen using each of these technologies.  Long story short.....Java Swing was eliminated since we wanted to run in a web browser with no installation required.  Adobe Flash was eliminated since it would not run on various Apple devices and required a lot of specialization.  This left the Google Web Toolkit.  I had never used it, but had just come off learning Oracle's ADF Technology which actually has a lot in common.   Also, the development environment would be Java with Google doing the javascript generation for me. Being a Java Swing expert put me right in the driver's seat.  

- Advice to any Java Swing experts out there.....learn GWT.  It's a very easy transition. -

To get a jump, I bought the Essential GWT book and started reading and experimenting.  I also started reading and experimenting with the copious online documentation about GWT.  Turns out that the stackoverflow web site would prove extremely valuable for answering detailed technical questions.

My first task was to architect the directory structure and modeling for the application.  Using a MVP (Model, View, Presenter) model was the way to go.  This would allow me to later change the view code to use any widgets (maybe Droid stuff?) without changing the model or presenter code.  I may never do this with my application, but at least it's architected to get there someday.  In a nutshell, the View classes do the widget creation and layout.  The Presenter code handles all callbacks and handlers to push data to the widgets.  The Model code gets data from my db into data structures that I can access asynchronously using rpc AsyncCallback mechanisms.

Everything seemed to fall into place as the application was built.   A spot for images, dialogs, events, tables, panels and third party javascript integration was created.  At this point, any new feature is more of a cut and paste of an existing feature, which is exactly where a product starts to mature.  

I am very impressed with the GWT performance as well.  Drawing tables and charts and lists is very quick and efficient.  Integration with some javascript tools has been quite easy and reliable with the JSNI implementation.  CSS overriding of the GWT widgets has allowed me to completely brand the application to our company style and give it a sophisticated look and feel.  No gwt-ext or ext-gwt here.

Here's to releasing the product and showing some screen shots here soon....




Tuesday, March 20, 2012

Auto Refreshing Your UI?

It seems that forever, there's been this battle between building an application that automatically refreshes when data changes or provides the user with a refresh button to press at their leisure. One can see the benefit of both. Let's say your interface is displaying a large graphical map of data that a user has sized, shaped, and customized to their liking. In comes a database update (probably from another user) and the application automatically redraws the graphical map, removing all the customizations that the user has spent time doing. Not good. Maybe lighting up a "refresh to see new data" button would have been better in this case.

Let's say a user is looking at a table of data showing objects and statuses. Due to an event in the system, one of the objects has gone from a green status to red. This is a case where an automatic refresh is in order otherwise how will a user know of this change in condition?

So given different circumstances, multi-user applications, event processing applications and the like, how can I build an application that automatically refreshes. My goal has always been to never have a "refresh" button on my menu bar. Having one, shows an application that has not been architected or designed for ultimate ease of use and an application that some users might find broken or out of date frequently.

Real World Example

Using GWT for my application development, I built a GWT UI server backend that my UI clients connect with asynchronously to "get" and "set" data. A hibernate DB backend server allows my GWT UI server to "get" and "set" data via a REST api. So all the moving parts are nicely in place. A DB storing all the data, a UI server that interfaces with the DB server and provides asynchronous data to any UI client that connects to it.

How to keep a client view auto refreshed?

The first part was to get my UI server in sync with the DB server. In one of my UI views, I show a table to objects, let's call them "widgets". These widgets have a name, description, update date and a status. My UI client will ask my UI server for a list of these objects to then feed into my GWT table. My UI server could make a call over to the DB server to get these objects, but how to keep in sync with changes that can occur and how to make this perform ok?

The Magic.

Upon initial connection and startup, my UI server gets all of the "widgets" from the DB server and stores them. It then starts a timer, going off every second, which ask the DB server via REST, if any of these widgets has changed (created, deleted, modified). For the most part this call returns "nothing to do" and the timer goes back to sleep. However, a key part of this is that my UI server always has the latest data in its data structure and always keeps it up to date (at least within a second or two). If a change does occur, the UI server data structure is updated and a date stamp is created for this update.

Along comes a UI client that connects to the UI server and asks for the widget data for the GWT table. The UI server already has a data structure ready to go and returns the data instantly to the client. The table is drawn. Any other UI clients connecting will get the exact same results. All the UI clients share this UI server. When the UI client has completed populating and displaying the table, it in turn starts a timer. Each time the timer goes off, it asks the UI server if any of the "widgets" have changed. The UI server returns the date stamp of the last change and UI client uses this to determine if it already saw this change or not. If not, the UI clients get the new data and updates the GWT table.

In summary, the UI server's job is to ask the DB server about changes using a timer and keeps the data structure up to date with the DB. The UI client's job is to ask the UI server about any changes it has, also using a timer. Since all UI clients share the same UI server, they are all in sync all the time and all see the same underlying data.

In demoing my application, I always get the comments of "this application is very fast" and "it sees updates very quickly", and of course "why don't all application refresh like this?"

In a future blog, I'll cover this more with some sample code and diagrams. For now, give you users the most usable application you can. Software is great at the mundane tasks....updating data structures!





Thursday, January 26, 2012

Steve Jobs Biography

For Christmas I received Steve Jobs biography. My family knows that I work in high tech and that I design user interfaces and applications and fell in love with my recent MacBook Pro, my first "Apple" product.

This is the first book that I've read cover to cover in quite a while. Most of my reading is technical articles, blogs, online books, etc. where I only have a few minutes to figure something out, learn a new technology or get an answer to a technical question.

As I went through the book, it became very nostalgic. I started my career in the early 80's at Digital...saw the first PC they made, saw a "color" screen appear and this thing called a mouse too. I look back now and feel so lucky that I was part of the user interface group, designing applications using DECWindows (and later Motif) and working with the User Interface lab, observing users and learning how someone interacts with a device. The whole interaction and experience is what has differentiated Apple from the beginning and was driven by Steve Jobs. Sure, they came up with great devices that did wonderful things and were so cool, but so did others, it was just that theirs were so elegant, simple and user friendly.

I look at the user interfaces I have designed and that I continue to design and I now have a more critical view of them. When a user lands on my screen, do they know what to do? Does it make sense? If they do the wrong thing, is it clear why that operation didn't work and what they should do instead? Do they need to read a manual to figure it out?

It is fascinating to me that since 1980 to now, 2012, UI design really hasn't changed at all. Buttons, menus, scrollbars, trees, tables, etc. are still the same. Just like an artist with a canvas and paint, it's the combination of colors, layout, textures that make his painting into art. Those who can take a complex set of data and a complex task and make into the most simple, logical, and easy operation end up with the most usable products.

I judge my applications by my users. How quickly are they doing productive work with it? Can I get them to the right screen with 1 click or 1 touch or 1 operation? Is my Product Manager out demoing and using the application without asking me anything about it? No one reads the manuals these days. The application has to "just work."

So today I work on user interfaces developed with GWT. I also design products for the Android interface. Any feature or layout or function I can imagine can be done with the GWT widget set. Any look or color or size or shape can be done with CSS. For Android, a smaller/touch screen presents a different set of challenges, but really forces me to think even simpler, more straightforward and work towards an elegant solution.

Steve Jobs was very demanding, knew what he wanted and would not be happy until he saw it and reading his biography has certainly left a mark on me. Steve thought something was total crap, horrible, unusable until one final tweak made it "perfect." So strive for quality - prototype - adjust - rework - open your eyes to the environment around you - and shape your work into something elegant. You are one tweak away from perfection.



Wednesday, December 14, 2011

Doing that cool reflection thing....

We've all seen applications, websites, tv advertising, logos, etc. that have a reflection under them. It's the new cool thing to do. I'm sure there are probably many ways to do this, but I'll share in this blog one way that I did it with my GWT based application.

I'll start with the end result that I achieved...our login dialog box:



First, I built a panel that has a background gradient and rounded edges on the border. It's a GWT FlexTable with a css style setup.

final FlexTable loginFlex = new FlexTable();
loginFlex.setStyleName("my-DialogStyle");

Inside my CSS file, I have:

.my-DialogStyle {
background: #FFFFFF;

filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFF', endColorstr='#999999'); /* IE compatible */
background: -webkit-gradient(linear, left top, left bottom, from(#FFFFFF), to(#999999)); /* Webkit compatible */
background: -moz-linear-gradient(top, #FFFFFF, #999999); /* Firefox compatible */

border:1px solid #666666;
border-radius: 8px 8px 8px 8px;
-moz-border-radius: 8px 8px 8px 8px;
-webkit-border-radius: 8px 8px 8px 8px;

padding: .5em 2em .5em 2em;
}

Once I had this working and appearing on the screen, I then needed to make the reflection. To do this, I found this web site:


http://www.generateit.net/reflection/index.htm

You load up your image, which for me was a screen shot of my login dialog. You pick how much reflection you want (I picked 20%) and your background color (which for me was white). The web site generates a PNG file that you can save.

In my case, I only wanted the reflection part of my image, so using a graphics tool (like Photoshop, or PaintShopPro or Gimp) I captured the reflection part into a new PNG file:




The last step was to draw my reflection on my screen "attached" to the bottom of my login dialog box and center this on my screen too. I used a LayoutPanel to hold my FlexTable and my reflection image:

final Image reflection = new Image(loginreflection());
final LayoutPanel mainPanel = new LayoutPanel();
mainPanel.add(flexPanel);
mainPanel.setWidgetTopHeight(flexPanel, (Window.getClientHeight() / 2) - (flexPanel.getOffsetHeight() / 2), Unit.PX, flexPanel.getOffsetHeight(), Unit.PX);
mainPanel.setWidgetLeftWidth(flexPanel, (Window.getClientWidth() / 2) - (flexPanel.getOffsetWidth() / 2), Unit.PX, flexPanel.getOffsetWidth(), Unit.PX);

mainPanel.add(reflection);
mainPanel.setWidgetTopBottom(reflection, (Window.getClientHeight() / 2) + (flexPanel.getOffsetHeight() / 2) + 1,Unit.PX, 0, Unit.PX);
mainPanel.setWidgetLeftWidth(reflection, (Window.getClientWidth() / 2) - (flexPanel.getOffsetWidth() / 2), Unit.PX, flexPanel.getOffsetWidth(), Unit.PX);

For a really cool effect, you can also add:

mainPanel.animate(1000);

but animation is for another blog. Enjoy!

Saturday, October 1, 2011

GWT Tricks #2

I want to have a dialog box or a display on my screen where the user can just hit the "Return" key and not have to click on my OK button. It might be a data entry form and they are typing, tabbing, typing, tabbing and should not have to take their hands off the keyboard to finish...just hit Enter or Return.

To do this, you'll need to create a class for your button that listens for a Key down. Here's how:

1. First create a class that you can reuse on any form or display you like:

public class ButtonPressListener implements KeyDownHandler
{
private final Button button;

public ButtonPressListener(final Button button)
{
this.button = button;
}

@Override
public void onKeyDown(final KeyDownEvent key)
{
if (key.getNativeEvent().getKeyCode() == KeyCodes.KEY_ENTER)
{
button.click();
}
}

}
This class will see a KeyDown event, check that it was the Enter key and then press your button. So if you pass in your default button or OK button, it gets activated when the user presses enter. Here's how:

First create your button -
private final Button    okButton     = new Button();
okButton.setText("OK");
Now create your listener, passing the button you want activated when the user hits Enter -
final ButtonPressListener listener = new ButtonPressListener(okButton);
Now, if your dialog box or form has other input fields, you want each of them to see an Enter key press and activate your OK button. In this example, we have a username and password field on our screen:
usernameTextBox.addKeyDownHandler(listener);
passwordTextBox.addKeyDownHandler(listener);

Now that you know how to setup a key listener, you can create all sorts of conveniences for your user and let them fly through your UI screens.