Toolkit productivity tools project

Im finally pushed the first release of toolkit productivity tools library, which I use as a companion for all my Vaadin apps and hope it will be useful for somebody else.

The project home is here -
http://code.google.com/p/tpt
and contains, in addition to sources, jdk 1.6 compiled binaries, demo web app, short manual book and the
live demo
as well. Thanks to Joonas for Finnish i18n files for the demo :slight_smile:

Unfortunately, I did not get done my further findings with custom layout and templating engine but hope to finish them in Xmas holidays, so this will go for version 1.1

Dmitri

Great stuff! Thanks for contributing.

This is really great! There are many useful components in tpt that you need in larger applications - now in one package.

Really nice! Great to see such extensive and well documented contributions from the community. Keep up the good work!

By the way, I was browsing through the TPT source code and saw you had your own TPTRunnable to solve the problem of using ThreadLocal and background threads. I’ve also encountered this problem myself and found a simple solution of using an
InheritableThreadLocal
instead of plain ThreadLocal. Just wanted to share this solution in case it might be useful. :slight_smile:

Thanks, Teemu,

never looked at ITL, for an unknown reason :), need to look at it closer definetly.

Thank you for sharing this, it’s wonderfull!

Anyway I have to highlight a little imperfection:

In TPTMultiView the method

addView(String, Class<Component>);

is a little bit weird:

addView("test", (Class<Component>) MyComponent.class);

even if MyCommponent is actually extending Component.

The signature should be probably the following:

public class TPTMy

<T extends Component> void addView(String, Class<T>) // If I remember it correctly

Thank you very much for this brilliant piece of code.

Ivan

Hi Ivan !

Glad TPT seems to be useful not only for me and thanks for pointing to this line, this should be definitely beautified !

As for this feature, this was a quick try for lazy initialization, but for now Im thinking that probably this vesion of method better to be removed at all and in order to have a lazy view initialization it is more correct to implement a TPTView interface in your view and catch a viewActivated calls each time your view is being displayed. However, for adding TPTMultiView into existing application it still might be useful adding a class instead of instance, so old component will be lazy initialized on first access… What do you think ?

Created a ticket
#4

(upd: and fixed in trunk / r16 )

I completely agree. I was not thinking about it. Maybe it can be useful to add a little paragraph to the, very beatiful, docs.

Thank you,

Ivan

Version 1.1 of the
Toolkit Productivity Tools
just has been released and uploaded to
Directory
.
Live Demo
has been also updated.

The main changes are as follows:

  1. Added a pdf document viewer - a component you can use to display small and large (and very large) pdf documents to your application users - documents are displayed page-by-page in a google books manner, so only the page images being read are downloaded to the client computer. With this component you can display very large - 10K pages and hundreds of gigabytes size PDF files - we’re using it in several book reading projects, where end-users reads hi-resolution scanned books on-line.

You can check the
live demo
to see how it works.

Viewer uses standard UI components from Vaadin core and does not require any custom widgetset. Thanks to Vaadin’s table component - it does all the dirty job for lazy loading of pages.

And attaching the viewer to your project as simple as adding a couple of lines:

File pdfFile = new File ( "/path/to/doc.pdf" );
DocumentViewer v = new DocumentViewer (v);
addComponent ( v);

v.loadDocument ( new PdfDocument ( pdfFile ) );
  1. Added formatting support to i18n component. Now you can use formatting (according to Java Formatter) tokens ( such as %s , %d and so on) in your translation files and bind them to values inside the code, for example:

lang.properties:

app.version=Version %s

and java code:

String version = "1.0.0";
myLabel = new Label ( TM.get ( "app.version" , version ) );

i18n provides automatic management of translation files for your Vaadin application. Translation files are located in standard java .property files you usually use for Swing and server-side locale resources and can be dropped to your theme folder for automatic pickup. Once dropped, you can just query for translation via TM.get(“…”); static method - a key value for appropriate language will be automatically returned.

  1. Very small but often used (at least by me) TPTMessagePanel component - it allows you to add V and H centered label to the parent layout and saves you from 4 to 10 lines of code :slight_smile:

  2. Mist bugfixes and code cleanups took place as well.

Hope these components will be useful for anyone else. Any comments , bugs and suggestions are always more than welcome :slight_smile:

P.S. Version 1.1 is a bit larger in size in comparison to previous one - this is because it includes IcePDF open source edition jar’s which are needed for pdf document viewer. Should I split it and made download less in size - just let me know.

Maintenance release 1.1.1 of
TPT
is now available on
Directory
.

Several reported issues were fixed there as well as download package reduced by extracting tpt-demo.war to a separate download link and also reducing the number of required IcePDF jar files (for the PDF viewer component).

Also, PDF viewer component has now more intelligence deps checking code, so if IcePDF jars are not found on a classpath, the proper message will be rendered to the user (instead of pdf document contents) instead of NoClassDefFound error.

Dmitri

The toolkit is really good, but the internationalization section is not very useful. The main drawback is it does not handle dynamic language change, and that is a must for portlets. The user can decide to change the language at any moment and the change should be transparent to the developer. In fact, I think the standard way of Java I18n with bundles and the ResourceBundle.getBundle(bundleBaseName).get(messageKey) covers almost the same, except the custom layouts. But here the problem is the same: it’s not dynamic.

IMO I18n should be integrated inside Vaadin or enable hooks/listeners/whatever in Vaadin to perform that task. Whenever the automatic translation be not available, notify the application to perform it in some other way. I’ve thought AOP could be a transparent to Vaadin way to do it by intercepting calls. The drawback is execution can be slowed too much.

Regards
Aniceto

Aniceto, thanks for your opinion, yes, dynamic language change would be great, but you just described the main issues with this feature implementation in Vaadin.

By the way, in one of our Swing apps I did use some kind of hook pattern (from there, TPT’s translation manager came):

  • Any part of UI can register language change listener to a translation manager
  • Then, language is changed through the translation manager api call
  • All listeners invoked and titles, captions, messages are replaced

In Vaadin, third step should also require repaint the client side.

Would it be sufficient and more or less usable if this scheme will be added to TPT ? Because most of out web apps does not require realtime language change, I did not implement it yet in TPT. But if this way will be usabe and interested for others, I can quickly add the feature.

So, in general, this will look like as follows:

In init method of your window / compound widget class:

public MyWindow extends Window implements LanguageChangeEvent
{
   TM.addLanguageChangeListener(this);
   ...
   languageChanged(); // this is to set initial titles to buttons and labels
}

...
...
...

public void langugageChanged()
{
   MyButton.setCaption ( TM.get("button.titile"));
   setTitle ( TM.get("window.title"));
}

And somewhere as a language selection combo box event:

TM.setDefaultLanguage( "" + languagesPopup.getValue());

Hey, thanks for the great work! Sorry if this is being posted in the wrong place, but I am having issues getting the PDF viewer to work properly.

I am currently using Vaadin 6.4.8 along with the Google App Engine, and I currently have tpt-core, icepdf-core, icepdf-pro, and icepdf-pro-intl in my library.

The code that I am using in my implementation so far is the basic code shown in your handbook:

DocumentViewer viewer = new DocumentViewer();
File pdfFile = new File("VAADIN/themes/ProfileTheme/files/sitepdf.pdf);
viewer.loadDocument(new PdfDocument(pdfFile));

However, when trying to run the program I come across the following error:

Nov 24, 2010 10:51:08 AM com.vaadin.terminal.gwt.server.GAEApplicationServlet service
SEVERE: javax.servlet.ServletException: java.lang.RuntimeException: java.awt.geom.Rectangle2D$Float is a restricted class. Please see the Google  App Engine developer's guide for more details.: javax.servlet.ServletException: java.lang.RuntimeException: java.awt.geom.Rectangle2D$Float is a restricted class. Please see the Google  App Engine developer's guide for more details.
	at com.vaadin.terminal.gwt.server.AbstractApplicationServlet.handleServiceException(AbstractApplicationServlet.java:966)
	at com.vaadin.terminal.gwt.server.AbstractApplicationServlet.service(AbstractApplicationServlet.java:523)
	at com.vaadin.terminal.gwt.server.GAEApplicationServlet.service(GAEApplicationServlet.java:242)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:806)
	at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
	at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:58)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
	at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
	at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:122)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
	at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
	at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
	at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
	at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
	at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
	at com.google.apphosting.utils.jetty.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:70)
	at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
	at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:349)
	at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
	at org.mortbay.jetty.Server.handle(Server.java:326)
	at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
	at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:923)
	at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:547)
	at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
	at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
	at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
	at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
Caused by: java.lang.RuntimeException: java.awt.geom.Rectangle2D$Float is a restricted class. Please see the Google  App Engine developer's guide for more details.
	at eu.livotov.tpt.gui.vdv.formats.PdfDocument.<init>(PdfDocument.java:79)
	at com.example.testgae.ResumePDF.<init>(ResumePDF.java:13)
	at com.example.testgae.ContentPanel.init(ContentPanel.java:29)
	at com.example.testgae.ContentPanel.<init>(ContentPanel.java:24)
	at com.example.testgae.MainPage.init(MainPage.java:28)
	at com.example.testgae.MainPage.<init>(MainPage.java:15)
	at com.example.testgae.TestgaeApplication.init(TestgaeApplication.java:11)
	at com.vaadin.Application.start(Application.java:549)
	at com.vaadin.terminal.gwt.server.AbstractApplicationServlet.startApplication(AbstractApplicationServlet.java:1146)
	at com.vaadin.terminal.gwt.server.AbstractApplicationServlet.service(AbstractApplicationServlet.java:459)
	... 27 more
Caused by: java.lang.NoClassDefFoundError: java.awt.geom.Rectangle2D$Float is a restricted class. Please see the Google  App Engine developer's guide for more details.
	at com.google.appengine.tools.development.agent.runtime.Runtime.reject(Runtime.java:51)
	at org.icepdf.core.pobjects.PRectangle.<init>(PRectangle.java:112)
	at org.icepdf.core.pobjects.Page.getMediaBox(Page.java:1185)
	at org.icepdf.core.pobjects.Page.getCropBox(Page.java:1224)
	at org.icepdf.core.pobjects.Page.getPageBoundary(Page.java:1063)
	at org.icepdf.core.pobjects.Page.getSize(Page.java:940)
	at org.icepdf.core.pobjects.Page.getSize(Page.java:923)
	at org.icepdf.core.pobjects.Document.getPageDimension(Document.java:823)
	at eu.livotov.tpt.gui.vdv.formats.PdfDocument.openDocument(PdfDocument.java:161)
	at eu.livotov.tpt.gui.vdv.formats.PdfDocument.<init>(PdfDocument.java:76)
	... 36 more

Nov 24, 2010 10:51:09 AM com.vaadin.terminal.gwt.server.GAEApplicationServlet service
SEVERE: javax.servlet.ServletException: java.lang.RuntimeException: java.awt.geom.Rectangle2D$Float is a restricted class. Please see the Google  App Engine developer's guide for more details.: javax.servlet.ServletException: java.lang.RuntimeException: java.awt.geom.Rectangle2D$Float is a restricted class. Please see the Google  App Engine developer's guide for more details.
	at com.vaadin.terminal.gwt.server.AbstractApplicationServlet.handleServiceException(AbstractApplicationServlet.java:966)
	at com.vaadin.terminal.gwt.server.AbstractApplicationServlet.service(AbstractApplicationServlet.java:523)
	at com.vaadin.terminal.gwt.server.GAEApplicationServlet.service(GAEApplicationServlet.java:242)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:806)
	at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
	at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:58)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
	at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
	at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:122)
	at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
	at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
	at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
	at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
	at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
	at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
	at com.google.apphosting.utils.jetty.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:70)
	at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
	at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:349)
	at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
	at org.mortbay.jetty.Server.handle(Server.java:326)
	at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
	at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:923)
	at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:547)
	at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
	at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
	at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
	at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
Caused by: java.lang.RuntimeException: java.awt.geom.Rectangle2D$Float is a restricted class. Please see the Google  App Engine developer's guide for more details.
	at eu.livotov.tpt.gui.vdv.formats.PdfDocument.<init>(PdfDocument.java:79)
	at com.example.testgae.ResumePDF.<init>(ResumePDF.java:13)
	at com.example.testgae.ContentPanel.init(ContentPanel.java:29)
	at com.example.testgae.ContentPanel.<init>(ContentPanel.java:24)
	at com.example.testgae.MainPage.init(MainPage.java:28)
	at com.example.testgae.MainPage.<init>(MainPage.java:15)
	at com.example.testgae.TestgaeApplication.init(TestgaeApplication.java:11)
	at com.vaadin.Application.start(Application.java:549)
	at com.vaadin.terminal.gwt.server.AbstractApplicationServlet.startApplication(AbstractApplicationServlet.java:1146)
	at com.vaadin.terminal.gwt.server.AbstractApplicationServlet.service(AbstractApplicationServlet.java:459)
	... 27 more
Caused by: java.lang.NoClassDefFoundError: java.awt.geom.Rectangle2D$Float is a restricted class. Please see the Google  App Engine developer's guide for more details.
	at com.google.appengine.tools.development.agent.runtime.Runtime.reject(Runtime.java:51)
	at org.icepdf.core.pobjects.PRectangle.<init>(PRectangle.java:112)
	at org.icepdf.core.pobjects.Page.getMediaBox(Page.java:1185)
	at org.icepdf.core.pobjects.Page.getCropBox(Page.java:1224)
	at org.icepdf.core.pobjects.Page.getPageBoundary(Page.java:1063)
	at org.icepdf.core.pobjects.Page.getSize(Page.java:940)
	at org.icepdf.core.pobjects.Page.getSize(Page.java:923)
	at org.icepdf.core.pobjects.Document.getPageDimension(Document.java:823)
	at eu.livotov.tpt.gui.vdv.formats.PdfDocument.openDocument(PdfDocument.java:161)
	at eu.livotov.tpt.gui.vdv.formats.PdfDocument.<init>(PdfDocument.java:76)
	... 36 more

At this point I am not sure if I am just making a careless error somewhere, or if the Toolkit productivity tools is just not compatable with the Google App Engine.

Any help would be greatly appriciated :slight_smile:

Thanks!

Hi Nick !

TPT ( the PDF viewer) uses an external IcePDF engine to render PDF documents into page ratser images and it seems it just uses internally some AWT components which are not supported by GAE. So Im afraid, unless IcePDF will get GAE support, PDF viewer option will not work there… :frowning:

P.S. In addition to IcePDF, the viewer itself is caching rendered pages as a disk files in a temporary folder, so this could be an also issue on GAE (however, easily resolvable I suppose).

Dmitri

hey thanks for the quick response! :slight_smile:

aww that is unfortunate that icePDF doesnt work will GAE, guess i’ll just have to find another way. :frowning:

thanks again,
nick

Thanks for sharing. This stuff is really helpful.

Hi, Dmitri!

After upgrading to Vaadin 6.5.0 have problems with TPT’s OptionDialog.
After pressing the button have:


OptionDialog dlg = new OptionDialog(TPTApplication.getCurrentApplication());
dlg.showMessageDialog("title", "text", null);

So message dialog is open and then I try to press “Yes” button and have exception:


com.vaadin.Application terminalError
SEVERE: Terminal error:
com.vaadin.event.ListenerMethod$MethodException
Cause: java.lang.RuntimeException: Invalid option dialog state or buttons: com.vaadin.ui.Window.removeWindow(Lcom/vaadin/ui/Window;)V
	at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:510)
	at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:162)
	at com.vaadin.ui.AbstractComponent.fireEvent(AbstractComponent.java:1166)
	at com.vaadin.ui.Window.fireClose(Window.java:1323)
	at com.vaadin.ui.Window.removeWindow(Window.java:1467)
	at com.vaadin.ui.Window.close(Window.java:1136)
	at com.vaadin.ui.Window.changeVariables(Window.java:1097)
	at com.vaadin.terminal.gwt.server.AbstractCommunicationManager.handleVariableBurst(AbstractCommunicationManager.java:1288)
	at com.vaadin.terminal.gwt.server.AbstractCommunicationManager.handleVariables(AbstractCommunicationManager.java:1214)
	at com.vaadin.terminal.gwt.server.AbstractCommunicationManager.doHandleUidlRequest(AbstractCommunicationManager.java:730)
	at com.vaadin.terminal.gwt.server.CommunicationManager.handleUidlRequest(CommunicationManager.java:296)
	at com.vaadin.terminal.gwt.server.AbstractApplicationServlet.service(AbstractApplicationServlet.java:483)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:852)
	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
	at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
	at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.RuntimeException: Invalid option dialog state or buttons: com.vaadin.ui.Window.removeWindow(Lcom/vaadin/ui/Window;)V
	at eu.livotov.tpt.gui.dialogs.OptionDialog.finihDialog(OptionDialog.java:207)
	at eu.livotov.tpt.gui.dialogs.OptionDialog.windowClose(OptionDialog.java:214)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:490)
	... 24 more

Could you update TPT to work with Vaadin 6.5.0?

Thanks in advance.

Hi Mikhail !

thanks a lot for noting !
did not yet try 6.5 but definitely will do this weekend as it has to be tweaked for this new release.

Thanks,
Dmitri

Just FYI, tpt repository will be broken for several hours today due to project structure reorganization, migration to github and new version commits. Once this is done, new version of TPT will become available for everyone :slight_smile: