Blog do projektu Open Source JavaHotel

środa, 29 grudnia 2010

Tooltip and GWT

I'd like to add a tooltip to my GWT application to achieve the effect as below, additional information while hovering over an element.





Unfortunately, GWT does not support tooltip as a standard. But no problem to implement it - just add action on onMouseOver event to display tooltip window and action on onMouseOut action to remove it.
PopupTip
So now it is enough to create a label like:
private class LabTip extends PopupTip {
  LabTip() {
    Label l = new Label("Label")
    initWidget(l);
    setMessage("Help test - look how it looks like !");
  }
and it works as expected.

But it is enough for labels (simple widgets) only. What about Button - more complex widget. What's more important - I'd like to have some buttons with tooltip enabled and some buttons without that feature.
So I'd like to achieve to following goals:
  1. One common reusable tooltip component to have the same look and feel.
  2. Button widget with tooltip enabled and without tooltip at all and the code which uses that button is unaware of that (encapsulation).
Java does not allow multiply inheritance so we cannot simply create "tooltiped" button like that:
class ToolTipButton extends Button, PopupTip 
 More complicated approach is required. There is also another problem that widget being tooltiped should be  derived from PopupTip, this class cannot be a class component.
For the buttons I'm using the following API methods only: addClickHandler, setEnabled and isEnabled.Unfortunately, Composite class (the base class for PopupTip) does not inherit these methods, Composite class is based on the Widget class. These methods are available starting from FocusWidget class
http://google-web-toolkit.googlecode.com/svn/javadoc/2.1/index.html?overview-summary.html
So the only solution is to create additional interface  IGFocusWidget and Decorator pattern. IGFocusWidget interface is a Decorator and Button class as is a component. Interface exposes necessary method and in the class body redirects all methods to the appropriate Button methods. To make the whole solution more universal instead of Button class a more general FocusWidget can be used. In case of Button (FocusWidget) not "tooltiped" a concrete Decorator is not derived from PopupTip class to avoid overloading with unused functionality.

So the final class structure is as follows.
For "tooltiped" component
IGFocusWidget (Decorator interface)- FocusToolTipedWidget  (Decorator concrete class)- PopupTip (tooltip functionality). FocusWidget/Button (Decorator component)
For non-tooltiped component - as above but without PopupTip base class.


Implementation:
I'm using factory for producing Buttons and IGFocuseWidget to hide implementation details. Image buttons are created as "tooltiped" and text buttons are not tooltiped.

ButtonFactory
GFocusWidgetFactory

Usage example - after creation of button the user is unaware of the tooltip functionality. They share the same interface.
TestApp

Running example (installed on Google App Engine)
http://javahoteltest.appspot.com/

poniedziałek, 27 grudnia 2010

Byliśmy na koncercie

W dniu 26 grudnia 2010 byliśmy na koncercie inaugurującym IV Festiwal Bożonarodzeniowy Incarnatus Est organizowany przez Filharmonię im R. Traugutta. Ale koncert nam się nie podobał, wyszliśmy rozczarowani.
Organizatorzy chcieli w sposób efektowny rozpocząć festiwal, więc na inaugurację wybrali bardzo znane dzieło, "Mesjasza" Jerzego Fryderyka Handla. Na miejscu okazało się, że to tylko wybór z całego dzieła, same "najlepsze partie solowe" z bardzo ograniczoną orkiestrą. Ale "Mesjasz" to przecież historia opowiedziana muzycznymi środkami, od zapowiedzi "Drogę dla Pana przygotujcie na pustyni" do finału " Zasiadającemu na tronie i Barankowi błogosławieństwo i cześć, i chwała, i moc, na wieki wieków!". Jest wątpliwe, czy wybór na zasadzie "the best of" ma w tym wypadku wiele sensu. Jeśli stały za tym ograniczenia budżetowe, to przecież można było dobrać inny repertuar na miarę posiadanych środków.
Dobrym pomysłem było uzupełnienie niewykonywanych fragmentów lektorem odczytującym tekst pomijanych partii. Ale tej informacji zabrakło dla słuchaczy, zaś na wydrukowanym programie widać tylko angielskie tytuły  wykonywanych arii i pod spodem tekst po polsku - zapewne słuchacze sądzili, że to polskie tłumaczenie tego, co jest śpiewane. Gdyby informacja była przekazana w sposób bardziej kompletny może słuchacze byliby w stanie uchwycić ciągłość całej historii.
Innym problem był wybór miejsca koncertu - kościół Św Anny na Krakowskim Przedmieściu. Niestety, ale w czasie koncertu drzwi do kościoła były otwarte i muzyka musiała się przebijać przez szmer powodowany przez sznur  nieustająco przechodzących boczną nawą kościoła osób nawiedzających bożonarodzeniową szopkę. Wyraźnie przeszkadzało to także wykonawcom, na przykład w efektownej arii "The trumpet shall sound" solista, orkiestra i trąbka bardziej przeszkadzali sobie wzajemnie niż współpracowali.
W efekcie na końcu wykonawcy zebrali bardzo wątłe oklaski. Ale raczej powinno to być adresowane do organizatorów, niż do samych wykonawców, którymi byli przecież znani soliści z Warszawskiej Opery Kameralnej oraz zespół Concerto Avenna, których pamiętamy z innych doskonałych wykonań muzyki barokowej.

niedziela, 19 grudnia 2010

Disabling test case

I added very simple feature to BoaTester framework. After creating disabled file in test case directory this test is ignored during test execution. The content of this file is not important, it can contain explanation while this test case is temporarily switched off.

Just like:

testcase {directory}
  test1
     {test case content}
     disabled

It is very convenient because it is possible to run test suite and one test case does not block the execution. The test case still exist and is visible so we can anytime come back to this test and resolve the issue related to this test.