| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> |
| <html> |
| <head> |
| <META NAME="keywords" CONTENT="netbeans,magazine,NetBeans,Platform, |
| Development,example,sample,article,RCP,application,swing,GUI"> |
| <META NAME="description" CONTENT="NetBeans Magazine: Bluemarine - Swing and the NetBeans Platform in the Real World"> |
| <meta http-equiv=Content-Type content="text/html; charset=windows-1252"> |
| <title>Bluemarine: Swing and the NetBeans Platform in the Real World</title> |
| <style> |
| <!-- |
| p.Noparagraphstyle, li.Noparagraphstyle, div.Noparagraphstyle |
| {line-height:120%; |
| text-autospace:none; |
| font-size:12.0pt; |
| font-family:Times; |
| color:black;} |
| p.NB-Corpo, li.NB-Corpo, div.NB-Corpo |
| {text-align:left; |
| text-indent:5.65pt; |
| line-height:16.0pt; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:black; |
| letter-spacing:-.05pt;} |
| p.NB-Interttulo, li.NB-Interttulo, div.NB-Interttulo |
| {line-height:120%; |
| page-break-after:avoid; |
| text-autospace:none; |
| font-size:13.0pt; |
| font-family:"Verdana"; |
| color:#0075A2; |
| font-weight:bold;} |
| p.NB-Interttulo2, li.NB-Interttulo2, div.NB-Interttulo2 |
| {line-height:12.0pt; |
| page-break-after:avoid; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:#0081C7; |
| font-weight:bold;} |
| p.NB-Cdigointerno, li.NB-Cdigointerno, div.NB-Cdigointerno |
| {line-height:10.0pt; |
| text-autospace:none; |
| font-size:8.0pt; |
| font-family:"Verdana"; |
| color:black;} |
| p.NB-Notadica, li.NB-Notadica, div.NB-Notadica |
| {text-align:left; |
| line-height:13.0pt; |
| tab-stops:14.15pt; |
| text-autospace:none; |
| font-size:10.0pt; |
| font-family:"Verdana"; |
| color:#0081C7; |
| letter-spacing:.05pt;} |
| p.NB-Tips, li.NB-Tips, div.NB-Tips |
| {text-align:right; |
| line-height:13.0pt; |
| tab-stops:22.7pt; |
| text-autospace:none; |
| font-size:10.0pt; |
| font-family:"Verdana"; |
| color:black; |
| letter-spacing:.05pt;} |
| p.Legenda1, li.Legenda1, div.Legenda1 |
| {text-align:left; |
| text-indent:5.65pt; |
| line-height:16.0pt; |
| text-autospace:none; |
| font-size:10.0pt; |
| font-family:Arial; |
| color:black; |
| letter-spacing:-.05pt;} |
| p.NB-Legendaimagem, li.NB-Legendaimagem, div.NB-Legendaimagem |
| {line-height:12.0pt; |
| tab-stops:14.15pt; |
| text-autospace:none; |
| font-size:10.0pt; |
| font-family:"Verdana"; |
| color:black; |
| letter-spacing:.05pt;} |
| span.NB-NegritoTcnico |
| {font-family:"Verdana"; |
| color:black; |
| letter-spacing:.05pt; |
| font-weight:bold; |
| vertical-align:baseline;} |
| span.NB-Legendanegrito |
| {font-weight:bold;} |
| div.NB-Cdigointerno1 {line-height:10.0pt; |
| text-autospace:none; |
| font-size:8.0pt; |
| font-family:"Verdana"; |
| color:black;} |
| div.NB-Corpo1 {text-align:left; |
| text-indent:5.65pt; |
| line-height:16.0pt; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:black; |
| letter-spacing:-.05pt;} |
| div.NB-Interttulo1 {line-height:120%; |
| page-break-after:avoid; |
| text-autospace:none; |
| font-size:13.0pt; |
| font-family:"Verdana"; |
| color:#0075A2; |
| font-weight:bold;} |
| div.NB-Interttulo21 {line-height:12.0pt; |
| page-break-after:avoid; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:#0081C7; |
| font-weight:bold;} |
| div.NB-Notadica1 {text-align:left; |
| line-height:13.0pt; |
| tab-stops:14.15pt; |
| text-autospace:none; |
| font-size:10.0pt; |
| font-family:"Verdana"; |
| color:#0081C7; |
| letter-spacing:.05pt;} |
| div.NB-Tips1 {text-align:right; |
| line-height:13.0pt; |
| tab-stops:22.7pt; |
| text-autospace:none; |
| font-size:10.0pt; |
| font-family:"Verdana"; |
| color:black; |
| letter-spacing:.05pt;} |
| div.Noparagraphstyle1 {line-height:120%; |
| text-autospace:none; |
| font-size:12.0pt; |
| font-family:Times; |
| color:black;} |
| li.NB-Cdigointerno1 {line-height:10.0pt; |
| text-autospace:none; |
| font-size:8.0pt; |
| font-family:"Verdana"; |
| color:black;} |
| li.NB-Corpo1 {text-align:left; |
| text-indent:5.65pt; |
| line-height:16.0pt; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:black; |
| letter-spacing:-.05pt;} |
| li.NB-Interttulo1 {line-height:120%; |
| page-break-after:avoid; |
| text-autospace:none; |
| font-size:13.0pt; |
| font-family:"Verdana"; |
| color:#0075A2; |
| font-weight:bold;} |
| li.NB-Interttulo21 {line-height:12.0pt; |
| page-break-after:avoid; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:#0081C7; |
| font-weight:bold;} |
| li.NB-Notadica1 {text-align:left; |
| line-height:13.0pt; |
| tab-stops:14.15pt; |
| text-autospace:none; |
| font-size:10.0pt; |
| font-family:"Verdana"; |
| color:#0081C7; |
| letter-spacing:.05pt;} |
| li.NB-Tips1 {text-align:right; |
| line-height:13.0pt; |
| tab-stops:22.7pt; |
| text-autospace:none; |
| font-size:10.0pt; |
| font-family:"Verdana"; |
| color:black; |
| letter-spacing:.05pt;} |
| li.Noparagraphstyle1 {line-height:120%; |
| text-autospace:none; |
| font-size:12.0pt; |
| font-family:Times; |
| color:black;} |
| p.NB-Cdigointerno1 {line-height:10.0pt; |
| text-autospace:none; |
| font-size:8.0pt; |
| font-family:"Verdana"; |
| color:black;} |
| p.NB-Corpo1 {text-align:left; |
| text-indent:5.65pt; |
| line-height:16.0pt; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:black; |
| letter-spacing:-.05pt;} |
| p.NB-Interttulo1 {line-height:120%; |
| page-break-after:avoid; |
| text-autospace:none; |
| font-size:13.0pt; |
| font-family:"Verdana"; |
| color:#0075A2; |
| font-weight:bold;} |
| p.NB-Interttulo21 {line-height:12.0pt; |
| page-break-after:avoid; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:#0081C7; |
| font-weight:bold;} |
| p.NB-Notadica1 {text-align:left; |
| line-height:13.0pt; |
| tab-stops:14.15pt; |
| text-autospace:none; |
| font-size:10.0pt; |
| font-family:"Verdana"; |
| color:#0081C7; |
| letter-spacing:.05pt;} |
| p.NB-Tips1 {text-align:right; |
| line-height:13.0pt; |
| tab-stops:22.7pt; |
| text-autospace:none; |
| font-size:10.0pt; |
| font-family:"Verdana"; |
| color:black; |
| letter-spacing:.05pt;} |
| p.Noparagraphstyle1 {line-height:120%; |
| text-autospace:none; |
| font-size:12.0pt; |
| font-family:Times; |
| color:black;} |
| span.NB-NegritoTcnico1 {font-family:"Verdana"; |
| color:black; |
| letter-spacing:.05pt; |
| font-weight:bold; |
| vertical-align:baseline;} |
| div.NB-Corpo2 {text-align:left; |
| text-indent:5.65pt; |
| line-height:16.0pt; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:black; |
| letter-spacing:-.05pt;} |
| li.NB-Corpo2 {text-align:left; |
| text-indent:5.65pt; |
| line-height:16.0pt; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:black; |
| letter-spacing:-.05pt;} |
| p.NB-Corpo2 {text-align:left; |
| text-indent:5.65pt; |
| line-height:16.0pt; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:black; |
| letter-spacing:-.05pt;} |
| p.NB-Corpo21 {text-align:left; |
| text-indent:5.65pt; |
| line-height:16.0pt; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:black; |
| letter-spacing:-.05pt;} |
| div.NB-Cdigointerno2 {line-height:10.0pt; |
| text-autospace:none; |
| font-size:8.0pt; |
| font-family:"Verdana"; |
| color:black;} |
| div.NB-Corpo3 {text-align:left; |
| text-indent:5.65pt; |
| line-height:16.0pt; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:black; |
| letter-spacing:-.05pt;} |
| div.NB-Interttulo3 {line-height:120%; |
| page-break-after:avoid; |
| text-autospace:none; |
| font-size:13.0pt; |
| font-family:"Verdana"; |
| color:#0075A2; |
| font-weight:bold;} |
| div.NB-Interttulo22 {line-height:12.0pt; |
| page-break-after:avoid; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:#0081C7; |
| font-weight:bold;} |
| div.NB-Notadica2 {text-align:left; |
| line-height:13.0pt; |
| tab-stops:14.15pt; |
| text-autospace:none; |
| font-size:10.0pt; |
| font-family:"Verdana"; |
| color:#0081C7; |
| letter-spacing:.05pt;} |
| div.NB-Tips2 {text-align:right; |
| line-height:13.0pt; |
| tab-stops:22.7pt; |
| text-autospace:none; |
| font-size:10.0pt; |
| font-family:"Verdana"; |
| color:black; |
| letter-spacing:.05pt;} |
| div.Noparagraphstyle2 {line-height:120%; |
| text-autospace:none; |
| font-size:12.0pt; |
| font-family:Times; |
| color:black;} |
| li.NB-Cdigointerno2 {line-height:10.0pt; |
| text-autospace:none; |
| font-size:8.0pt; |
| font-family:"Verdana"; |
| color:black;} |
| li.NB-Corpo3 {text-align:left; |
| text-indent:5.65pt; |
| line-height:16.0pt; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:black; |
| letter-spacing:-.05pt;} |
| li.NB-Interttulo3 {line-height:120%; |
| page-break-after:avoid; |
| text-autospace:none; |
| font-size:13.0pt; |
| font-family:"Verdana"; |
| color:#0075A2; |
| font-weight:bold;} |
| li.NB-Interttulo22 {line-height:12.0pt; |
| page-break-after:avoid; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:#0081C7; |
| font-weight:bold;} |
| li.NB-Notadica2 {text-align:left; |
| line-height:13.0pt; |
| tab-stops:14.15pt; |
| text-autospace:none; |
| font-size:10.0pt; |
| font-family:"Verdana"; |
| color:#0081C7; |
| letter-spacing:.05pt;} |
| li.NB-Tips2 {text-align:right; |
| line-height:13.0pt; |
| tab-stops:22.7pt; |
| text-autospace:none; |
| font-size:10.0pt; |
| font-family:"Verdana"; |
| color:black; |
| letter-spacing:.05pt;} |
| li.Noparagraphstyle2 {line-height:120%; |
| text-autospace:none; |
| font-size:12.0pt; |
| font-family:Times; |
| color:black;} |
| p.NB-Cdigointerno2 {line-height:10.0pt; |
| text-autospace:none; |
| font-size:8.0pt; |
| font-family:"Verdana"; |
| color:black;} |
| p.NB-Corpo3 {text-align:left; |
| text-indent:5.65pt; |
| line-height:16.0pt; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:black; |
| letter-spacing:-.05pt;} |
| p.NB-Corpo22 {text-align:left; |
| text-indent:5.65pt; |
| line-height:16.0pt; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:black; |
| letter-spacing:-.05pt;} |
| p.NB-Corpo211 {text-align:left; |
| text-indent:5.65pt; |
| line-height:16.0pt; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:black; |
| letter-spacing:-.05pt;} |
| p.NB-Interttulo3 {line-height:120%; |
| page-break-after:avoid; |
| text-autospace:none; |
| font-size:13.0pt; |
| font-family:"Verdana"; |
| color:#0075A2; |
| font-weight:bold;} |
| p.NB-Interttulo22 {line-height:12.0pt; |
| page-break-after:avoid; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:#0081C7; |
| font-weight:bold;} |
| p.NB-Notadica2 {text-align:left; |
| line-height:13.0pt; |
| tab-stops:14.15pt; |
| text-autospace:none; |
| font-size:10.0pt; |
| font-family:"Verdana"; |
| color:#0081C7; |
| letter-spacing:.05pt;} |
| p.NB-Tips2 {text-align:right; |
| line-height:13.0pt; |
| tab-stops:22.7pt; |
| text-autospace:none; |
| font-size:10.0pt; |
| font-family:"Verdana"; |
| color:black; |
| letter-spacing:.05pt;} |
| p.Noparagraphstyle2 {line-height:120%; |
| text-autospace:none; |
| font-size:12.0pt; |
| font-family:Times; |
| color:black;} |
| span.NB-NegritoTcnico2 {font-family:"Verdana"; |
| color:black; |
| letter-spacing:.05pt; |
| font-weight:bold; |
| vertical-align:baseline;} |
| p.NB-Corpo2111 {text-align:left; |
| text-indent:5.65pt; |
| line-height:16.0pt; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:black; |
| letter-spacing:-.05pt;} |
| .style1 {font-size: 9.0pt} |
| p.NB-Corpo21111 {text-align:left; |
| text-indent:5.65pt; |
| line-height:16.0pt; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:black; |
| letter-spacing:-.05pt;} |
| p.NB-Corpo211111 {text-align:left; |
| text-indent:5.65pt; |
| line-height:16.0pt; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:black; |
| letter-spacing:-.05pt;} |
| p.NB-Corpo2111111 {text-align:left; |
| text-indent:5.65pt; |
| line-height:16.0pt; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:black; |
| letter-spacing:-.05pt;} |
| p.NB-Corpo21111111 {text-align:left; |
| text-indent:5.65pt; |
| line-height:16.0pt; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:black; |
| letter-spacing:-.05pt;} |
| p.NB-Corpo21111112 {text-align:left; |
| text-indent:5.65pt; |
| line-height:16.0pt; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:black; |
| letter-spacing:-.05pt;} |
| p.NB-Corpo211111121 {text-align:left; |
| text-indent:5.65pt; |
| line-height:16.0pt; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:black; |
| letter-spacing:-.05pt;} |
| p.NB-Corpo2111111211 {text-align:left; |
| text-indent:5.65pt; |
| line-height:16.0pt; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:black; |
| letter-spacing:-.05pt;} |
| .NB-Listagenstitulos {font-family: Verdana, Arial, Helvetica, sans-serif; |
| color: #FFFFFF; |
| font-size: 14px;} |
| .style2 {font-family: "Courier New", Courier, monospace; font-size: 12px; color: #000000;} |
| .style3 {font-size: 11px; |
| font-weight: bold;} |
| p.NB-Corpo31 {text-align:left; |
| text-indent:5.65pt; |
| line-height:16.0pt; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:black; |
| letter-spacing:-.05pt;} |
| p.NB-Corpo111 {text-align:left; |
| text-indent:5.65pt; |
| line-height:16.0pt; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:black;} |
| p.NB-Corpo1111 {text-align:left; |
| text-indent:5.65pt; |
| line-height:16.0pt; |
| text-autospace:none; |
| font-size:9.0pt; |
| font-family:"Verdana"; |
| color:black;} |
| --> |
| </style> |
| </head> |
| <body bgcolor="#FFFFFF" lang=PT-BR> |
| <table width="770" border="0" cellpadding="0" cellspacing="0"> |
| <tr> |
| <td width="770" height="200"><img src="/images_www/magazine/bluemarine/top_blue_marine_web.jpg" width="770" height="200"></td> |
| </tr> |
| <tr> |
| <td><p class=NB-Corpo31><strong><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'><br> |
| Developing rich desktop Java applications has been historically a painful experience; but now you have new advanced Swing components and a complete application framework in the NetBeans Platform. See how the Platform has made it much easier to develop a complex desktop application and the lessons learned in building it.</span></font></strong></p> |
| <br></td> |
| </tr> |
| <tr> |
| <td><p class=NB-Corpo3><font size=1 color=black |
| face="Verdana"><span lang=EN-US style='font-size:9.0pt'>Like most people |
| working with Java since its early beginnings, my first experience with the |
| technology was with (small) desktop applications: some research stuff during my |
| doctorate and a simple control panel for a healthcare call center. It was the |
| age of AWT, and you really couldn’t do much more. So I soon moved to the server |
| side, where things appeared more robust and promising. They were indeed, and I |
| stayed there for long and became a J2EE Architect. </span></font></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>A few years later, I was attracted to the desktop again |
| because of a rising passion for digital photography. I still encountered many |
| problems, but just before I threw the sponge, Sun and the developer community |
| came to the rescue with SwingLabs, java.net and new versions of NetBeans. Now I |
| am enjoying a (possibly) promising open-source application – blueMarine – which |
| is based on the NetBeans Platform. </span></font></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>In this article, I’ll tell you more about blueMarine’s |
| story and review some of the main NetBeans extension APIs. I’ll show how these |
| APIs are used and customized, while pointing out the problems I faced and how |
| they were fixed. If you know just a little about NetBeans and you’re involved |
| with rich client applications, I think you will enjoy this article.</span></font><br> |
| <br> |
| </p> |
| <p class=NB-Interttulo3><b><font size=4 color="#0075a2" face="Verdana"><span |
| lang=EN-US style='font-size:13.0pt;line-height:120%'>The beginning</span></font></b></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>The first time I ever wrote some Java code for managing |
| my photos was around 2001, after getting bored with the OpenOffice spreadsheet |
| I was using. I exported everything to XML and, by means of an XSLT |
| transformation, defined my own database format which was managed by a very |
| simple GUI based on Swing.</span></font></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>In summer 2003 I made the “big jump” into the world of |
| digital cameras, buying a Nikon D100 (a professional SLR). It was one of the |
| century’s hottest summers in Italy, so I was forced to minimize the number of |
| photo trips: walking outside was simply a pain. Being forced to stay at home, |
| although in the relaxing environment of the Tuscany countryside, I spent most |
| of my holidays studying the NEF format. </span></font></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>NEF is a “RAW file format” that at the time was mostly |
| undocumented. A RAW file format holds the unprocessed data straight from the |
| camera’s CCD sensor and requires processing for being transformed into a |
| quality picture; this processing is often seen as the digital counterpart of |
| the old wet darkroom photo development. Having never owned a wet darkroom, I |
| was intrigued about the possibility of “digitally developing” my photos, and |
| started writing some Java code for this. </span></font></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>At the end of the summer I had created a simple |
| thumbnail navigator with the capability of showing my own photos – blueMarine |
| was born. A year later, the project had the capability of tagging photos with a |
| catalog facility and of publishing galleries on the web. </span></font></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>However, I was irked by the fact that I needed more |
| than a single piece of software to perform tasks such editing, printing, |
| cataloging, archiving and web publishing. So I set about implementing all this |
| workflow in a single application. Also, I decided it was high time I publicly |
| released blueMarine, and so the first alpha release went on SourceForge under |
| the GPL License (later changed to Apache 2.0). You can see one of the first |
| versions in <b><span style='font-weight:bold'>Figure 1</span></b>.</span></font></p> |
| <table width="770" border="0" cellspacing="0" cellpadding="0"> |
| <tr> |
| <td><img src="/images_www/magazine/bluemarine/images/image002.jpg" width="444" height="338"></td> |
| </tr> |
| <tr> |
| <td><p class=NB-Corpo22><strong>Figure 1.</strong> The old blueMarine main window, developed on plain Swing.<br> |
| </p></td> |
| </tr> |
| </table> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>Another force was pushing me on: the challenge of |
| trying Java for digital image processing on a desktop computer. To me it was |
| already evident that Java was good for scientific image manipulation; one |
| example was that engineers at NASA were successfully using JAI, an advanced |
| imaging API. But what about desktop processing for the casual photographer? To |
| demonstrate that Java is good for a wide range of applications is something |
| that I’ve always been pursuing since I started working as a Java consultant |
| more than <br> |
| ten years ago.</span></font><br> |
| <br> |
| </p> |
| <p class=NB-Interttulo3><b><font size=4 color="#0075a2" face="Verdana"><span |
| lang=EN-US style='font-size:13.0pt;line-height:120%'>The frustration</span></font></b></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>Notwithstanding the initial enthusiasm, at the end of |
| 2005 I was pretty frustrated with the project. Performance wasn’t much of an i</span></font><span |
| lang=EN-US style='letter-spacing:0pt'>ssue but I was facing difficulties in |
| developing a rich GUI application using plain Swing. Swing is an excellent API, |
| but when you start using it to build a complex app you discover there’s still a |
| lot of stuff to add. </span></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt;letter-spacing:0pt'>Implementing the missing pieces is |
| no rocket science, but that work wastes a lot of time better spent elsewhere. |
| Re-instantiate the problem for things such as building menus, having actions |
| enabled in a context-sensitive fashion, defining a flexible and working docking |
| mechanism for internal windows... and you’ll find yourself spending most of |
| your time writing generic GUI components, instead of working on the core of |
| your application. </span></font></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt;letter-spacing:0pt'>Until recently, there were few |
| open-source libraries dealing with such issues, and most were unsatisfactory |
| and cumbersome to integrate. There were also the early releases of NetBeans, |
| but I was unsatisfied with their performance. Eclipse and SWT were an option, |
| but I decided I wasn’t really going to study a completely alternative and |
| nonstandard API, with a very low learning ROI and a cumbersome way to integrate |
| with Swing. </span></font></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt;letter-spacing:0pt'>Summing up, I was seriously thinking |
| about giving up with blueMarine – maybe Java wasn’t yet ready for desktop |
| development |
| after all. </span></font><br> |
| <br> |
| </p> |
| <p class=NB-Interttulo3><b><font size=4 color="#0075a2" face="Verdana"><span |
| lang=EN-US style='font-size:13.0pt;line-height:120%'>The Renaissance</span></font></b></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt;letter-spacing:0pt'>However, there were a few concurrent |
| events that saved the project: my participation at JavaPolis at the end of |
| 2005, and the release of NetBeans 5.0 in early 2006. </span></font></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt;letter-spacing:0pt'>At JavaPolis, I breathed the |
| community atmosphere that I had mostly forgotten (three years had passed since |
| my last JavaOne). This renewed my enthusiasm, which was piqued further by |
| Romain Guy’s presentation showing how effective GUIs can be built with Swing. I |
| started looking at Romain’s blog and by following links I got to other blogs |
| such as Joshua Marinacci’s, and from there to all the java.net and JavaDesktop |
| stuff. I discovered there was a great deal of new interest in Swing; good |
| quality Swing components such as at SwingLabs, cool demos – lots of material |
| that I could use. But I still needed a platform. </span></font></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt;letter-spacing:0pt'>A few weeks later, NetBeans 5.0 came |
| out. The new release looked like it had finally fixed the traditional problems |
| of the Platform, so I decided to give it a try. I started disassembling |
| blueMarine, extracting only the imaging code and redesigning it to use the |
| NetBeans Platform. After a few months, the first Early Access builds were ready |
| to be delivered, and I had started using the tool for my own photo management. |
| In the meantime, the zero-issues switch from my former PPC Apple iBook to the new |
| Intel MacBook Pro was a strong sign that my choice had been right. </span></font></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt;letter-spacing:0pt'>Today I’m working on making the new |
| blueMarine stable and usable. New early access builds are available, and I’m |
| running the required quality tests (the complete redesign obviously broke some |
| of the stability of the previous release; that was the price to pay). <b><span |
| style='font-weight:bold'>Figure 2</span></b> shows the Platform-based version |
| of blueMarine at work. </span></font></p> |
| <table width="100%" border="0" cellspacing="0" cellpadding="0"> |
| <tr> |
| <td><img src="/images_www/magazine/bluemarine/images/image004.jpg" width="484" height="326"></td> |
| </tr> |
| <tr> |
| <td><p class=NB-Corpo211><strong>Figure 2.</strong> The main window of the new blueMarine application, developed on the NetBeans Platform.<br> |
| </p></td> |
| </tr> |
| </table> |
| <p class=NB-Interttulo3><b><font size=4 color="#0075a2" face="Verdana"><span |
| lang=EN-US style='font-size:13.0pt;line-height:120%'>The power of the NetBeans |
| Platform </span></font></b></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt;letter-spacing:-.1pt'>Now that you know the origins of |
| blueMarine, I’ll show an overview of the many benefits that NetBeans and Swing |
| brought to its development, as well as some problems I faced and how I fixed |
| them. </span></font><br> |
| <br> |
| </p> |
| <p class=NB-Interttulo22><b><font size=1 color="#0081c7" face="Verdana"><span |
| lang=EN-US style='font-size:9.0pt'>First point: it’s Swing!</span></font></b></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt;letter-spacing:-.1pt'>To me, the fact that the NetBeans |
| Platform is based on regular Swing is a huge advantage over competitors such as |
| Eclipse RCP. If you look around, you can find a much broader choice of Swing |
| components (including “cool” ones which implement animations and effects). </span></font></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt;letter-spacing:-.1pt'>I concretely realized this |
| advantage last June, when Joshua Marinacci released the source of an Aerith |
| Swing component capable of rendering maps, named </span></font><span |
| class=NB-NegritoTcnico2><b><font size=2 color=black face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt;letter-spacing:-.1pt'>JXMapViewer</span></font></b></span><span |
| lang=EN-US style='letter-spacing:-.1pt'> (Aerith was one of the hottest demos |
| at JavaOne 2006). I had been waiting for that moment for several weeks, as one |
| of the features of blueMarine is geo-tagging (associating a geographical position |
| to each photo so they can be shown over a map). Integrating </span><span |
| class=NB-NegritoTcnico2><b><font size=2 color=black face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt;letter-spacing:-.1pt'>JXMapViewer</span></font></b></span><span |
| lang=EN-US style='letter-spacing:-.1pt'> into blueMarine required just a few |
| hours of work; you can see the result in <b><span style='font-weight:bold'>Figure |
| 3</span></b>. The Swing choice was indeed rewarding. </span></p> |
| <table width="100%" border="0" cellspacing="0" cellpadding="0"> |
| <tr> |
| <td><img src="/images_www/magazine/bluemarine/images/image006.jpg" width="419" height="319"></td> |
| </tr> |
| <tr> |
| <td><p class=NB-Corpo2111><strong>Figure 3.</strong> The Map Viewer with geo-tagged photos uses the JXMapViewer component.<br> |
| </p></td> |
| </tr> |
| </table> |
| <p class=NB-Interttulo22><b><font size=1 color="#0081c7" face="Verdana"><span |
| lang=EN-US style='font-size:9.0pt;letter-spacing:-.1pt'>The Module System </span></font></b></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt;letter-spacing:-.1pt'>A NetBeans Platform application is |
| naturally organized into modules – in fact, it’s a set of modules bound |
| together. Each module has a name, a set of version tags, its own classpath, and |
| a list of declared dependencies. The developer can control which subset of the |
| public classes is exposed to other modules, and the platform enforces the |
| dependencies among modules (for instance, preventing a module to be installed |
| if any of the required modules is not present or is too old). </span></font></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt;letter-spacing:-.1pt'>Furthermore, an application can be |
| extended at a later time by publishing new modules packed in <i><span |
| style='font-style:italic'>nbm</span></i> files, and users can set up their own |
| “update center” for downloading updates from the Internet. Individual modules |
| can be digitally signed and the system automatically pops up their license for |
| approval if required. </span></font></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt;letter-spacing:-.1pt'>The blueMarine project takes full |
| advantage of this organization. The core APIs of the application are defined by |
| a relatively small set of modules implementing a workspace manager, photo and |
| thumbnail management and simple thumbnail and photo viewers. The more advanced |
| features, such as the Catalog, the Gallery Manager, and geo-tagging |
| functionality, including the Map Viewer, are implemented in separate and mostly |
| independent modules that act as “clients” of the core APIs. </span></font><br> |
| <br> |
| </p> |
| <p class=NB-Interttulo22><b><font size=1 color="#0081c7" face="Verdana"><span |
| lang=EN-US style='font-size:9.0pt'>DataObjects, Nodes and ExplorerManagers</span></font></b></p> |
| <p class=NB-Corpo3><span class=NB-NegritoTcnico2><b><font size=2 color=black |
| face="Verdana"><span lang=EN-US style='font-size:10.0pt'>ExplorerManager</span></font></b></span><span |
| lang=EN-US>s, </span><span class=NB-NegritoTcnico2><b><font size=2 color=black |
| face="Verdana"><span lang=EN-US style='font-size:10.0pt'>Node</span></font></b></span><span |
| lang=EN-US>s and </span><span class=NB-NegritoTcnico2><b><font size=2 |
| color=black face="Verdana"><span lang=EN-US style='font-size:10.0pt'>DataObject</span></font></b></span><span |
| lang=EN-US>s are probably the most </span><span lang=EN-US style='letter-spacing: |
| 0pt'>useful APIs in NetBeans. With </span><span class=NB-NegritoTcnico2><b><font |
| size=2 color=black face="Verdana"><span lang=EN-US style='font-size: |
| 10.0pt;letter-spacing:0pt'>DataObject</span></font></b></span><span lang=EN-US |
| style='letter-spacing:0pt'>s you can implement your application-specific |
| entities that are mapped to a file on the disk. For instance, blueMarine’s |
| basic entity is </span><span class=NB-NegritoTcnico2><b><font size=2 |
| color=black face="Verdana"><span lang=EN-US style='font-size:10.0pt; |
| letter-spacing:0pt'>PhotoDataObject</span></font></b></span><span lang=EN-US |
| style='letter-spacing:0pt'>, which represents a photo in the database. </span></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt;letter-spacing:0pt'>While </span></font><span |
| class=NB-NegritoTcnico2><b><font size=2 color=black face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt;letter-spacing:0pt'>DataObject</span></font></b></span><span |
| lang=EN-US style='letter-spacing:0pt'>s contain all the status and behavior of |
| your entities, </span><span class=NB-NegritoTcnico2><b><font size=2 color=black |
| face="Verdana"><span lang=EN-US style='font-size:10.0pt;letter-spacing: |
| 0pt'>Node</span></font></b></span><span lang=EN-US style='letter-spacing:0pt'>s |
| can be bound to them for visualization purposes. They can also be aggregated in |
| many different ways (as collections or graphs). The NetBeans Platform provides |
| GUI components, such as tables and lists, which can use a set of </span><span |
| class=NB-NegritoTcnico2><b><font size=2 color=black face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt;letter-spacing:0pt'>Node</span></font></b></span><span |
| lang=EN-US style='letter-spacing:0pt'> objects as their model; among the most |
| common are </span><span class=NB-NegritoTcnico2><b><font size=2 color=black |
| face="Verdana"><span lang=EN-US style='font-size:10.0pt;letter-spacing: |
| 0pt'>BeanTreeView</span></font></b></span><span lang=EN-US style='letter-spacing: |
| 0pt'>, </span><span class=NB-NegritoTcnico2><b><font size=2 color=black |
| face="Verdana"><span lang=EN-US style='font-size:10.0pt;letter-spacing: |
| 0pt'>ContextTreeView</span></font></b></span><span lang=EN-US style='letter-spacing: |
| 0pt'>, and </span><span class=NB-NegritoTcnico2><b><font size=2 color=black |
| face="Verdana"><span lang=EN-US style='font-size:10.0pt;letter-spacing: |
| 0pt'>ListView</span></font></b></span><span lang=EN-US style='letter-spacing: |
| 0pt'>. Finally, an </span><span class=NB-NegritoTcnico2><b><font size=2 |
| color=black face="Verdana"><span lang=EN-US style='font-size:10.0pt; |
| letter-spacing:0pt'>ExplorerManager</span></font></b></span><span lang=EN-US |
| style='letter-spacing:0pt'> controls selections and <br> |
| tree navigation. </span></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt;letter-spacing:0pt'>Yes, this is nothing more than a |
| sophisticated MVC implementation (see <b><span style='font-weight:bold'>Figure |
| 4</span></b>), but an implementation where a lot of boilerplate code has been |
| already written for you. For instance, the Platform APIs take care of things |
| like drag-and-drop support (with such fine details as visual cues during the |
| drag operation), cut-and-paste operations, and context menus.</span></font></p> |
| <table width="100%" border="0" cellspacing="0" cellpadding="0"> |
| <tr> |
| <td><img src="/images_www/magazine/bluemarine/images/image008.jpg" width="550" height="336"></td> |
| </tr> |
| <tr> |
| <td><p class=NB-Corpo21111><strong>Figure 4.</strong> NetBeans MVC components.<br> |
| <br> |
| </p></td> |
| </tr> |
| </table> |
| <p class=NB-Interttulo22><b><font size=1 color="#0081c7" face="Verdana"><span |
| lang=EN-US style='font-size:9.0pt'>The Lookup API</span></font></b></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt;letter-spacing:0pt'>The NetBeans Platform components |
| have a platform-controlled life-cycle (much like EJBs in a container), so they |
| are not directly instantiated. In order to retrieve a reference to an existing |
| module, you use the Lookup API. This API is very similar to other lookup |
| mechanisms. You get a reference to an object starting from its “name”, which is |
| not a string but the corresponding </span></font><span class=NB-NegritoTcnico2><b><font |
| size=2 color=black face="Verdana"><span lang=EN-US style='font-size: |
| 10.0pt;letter-spacing:0pt'>Class</span></font></b></span><span lang=EN-US |
| style='letter-spacing:0pt'> object. </span></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt;letter-spacing:0pt'>For instance, let’s suppose we have |
| a module called </span></font><span class=NB-NegritoTcnico2><b><font size=2 |
| color=black face="Verdana"><span lang=EN-US style='font-size:10.0pt; |
| letter-spacing:0pt'>it.tidalwave.catalog.CatalogImpl</span></font></b></span><span |
| lang=EN-US style='letter-spacing:0pt'> (implementing an interface </span><span |
| class=NB-NegritoTcnico2><b><font size=2 color=black face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt;letter-spacing:0pt'>it.tidalwave.catalog.Catalog</span></font></b></span><span |
| lang=EN-US style='letter-spacing:0pt'>). First you “register” the module by |
| putting a special file in the classpath, under the <i><span style='font-style: |
| italic'>META-INF/services</span></i> directory. The file must be named after |
| the implemented interface and contain the name of the implementation class. |
| Whenever a module is loaded, NetBeans scans for these special files, |
| instantiates the objects and puts them into the “default” </span><span |
| class=NB-NegritoTcnico2><b><font size=2 color=black face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt;letter-spacing:0pt'>Lookup</span></font></b></span><span |
| lang=EN-US style='letter-spacing:0pt'> object, from where any other piece of |
| code can later <br> |
| retrieve it. </span></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt;letter-spacing:0pt'>I usually wrap the lookup code using |
| the Locator pattern, as shown in <b><span style='font-weight:bold'>Listing 1</span></b>, |
| and then perform lookups like this: </span></font></p> |
| <p class="style2">Catalog catalog = |
| CatalogLocator.findCatalog();</span></font></p> |
| <table width="100%" border="1" cellpadding="0" cellspacing="0" bordercolor="#0081C7"> |
| <tr> |
| <td bgcolor="#0081C7"><p class="NB-Listagenstitulos"><strong>Listing 1.</strong> A Locator that uses the Lookup class.</p></td> |
| </tr> |
| <tr> |
| <td><blockquote> |
| <p class="style2"><br> |
| public class CatalogLocator {<br> |
| public static final synchronized Catalog findCatalog() {<br> |
| final Lookup lookup = Lookup.getDefault();<br> |
| final Catalog catalog = (Catalog)lookup.lookup(Catalog.class);<br> |
| <br> |
| if (catalog == null) {<br> |
| throw new RuntimeException("Cannot lookup Catalog");<br> |
| }<br> |
| return catalog;<br> |
| }<br> |
| }<br> |
| </p> |
| </blockquote></td> |
| </tr> |
| </table> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt;letter-spacing:0pt'>This mechanism not only favors |
| decoupling, but it also creates pluggable behavior. For instance, let’s look at |
| the map-rendering capability of blueMarine. As you know, there are many map |
| providers around, such as Google Maps, Microsoft Visual Earth, NASA, and |
| others. I want people to be able to extend blueMarine by plugging new code into |
| it for handling additional map providers. The solution is simple: first define |
| an interface – </span></font><span class=NB-NegritoTcnico2><b><font size=2 |
| color=black face="Verdana"><span lang=EN-US style='font-size:10.0pt; |
| letter-spacing:0pt'>MapProvider</span></font></b></span><span lang=EN-US |
| style='letter-spacing:0pt'> – which declares all the required capabilities, |
| then write alternate implementations, each one in its own module, e.g. </span><span |
| class=NB-NegritoTcnico2><b><font size=2 color=black face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt;letter-spacing:0pt'>GoogleMapProvider</span></font></b></span><span |
| lang=EN-US style='letter-spacing:0pt'>, </span><span class=NB-NegritoTcnico2><b><font |
| size=2 color=black face="Verdana"><span lang=EN-US style='font-size: |
| 10.0pt;letter-spacing:0pt'>MicrosoftVisualEarthMapProvider</span></font></b></span><span |
| lang=EN-US style='letter-spacing:0pt'>, etc. </span></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt;letter-spacing:0pt'>Each implementation is registered in |
| the default </span></font><span class=NB-NegritoTcnico2><b><font size=2 |
| color=black face="Verdana"><span lang=EN-US style='font-size:10.0pt; |
| letter-spacing:0pt'>Lookup </span></font></b></span><span lang=EN-US |
| style='letter-spacing:0pt'>instance, using the same “name”: </span><span |
| class=NB-NegritoTcnico2><b><font size=2 color=black face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt;letter-spacing:0pt'>MapProvider</span></font></b></span><span |
| lang=EN-US style='letter-spacing:0pt'> (multiple registered objects for the |
| same name are allowed). Now, retrieving the objects becomes an easy task. An |
| example is shown in <b><span style='font-weight:bold'>Listing 2</span></b>. |
| You can add modules with new map providers, and the retrieval code will find |
| them at runtime.</span></p> |
| <table width="100%" border="1" cellpadding="0" cellspacing="0" bordercolor="#0081C7"> |
| <tr> |
| <td bgcolor="#0081C7"><p class="NB-Listagenstitulos"><strong>Listing 2.</strong> Retrieving registered objects.</p></td> |
| </tr> |
| <tr> |
| <td><blockquote> |
| <p class="style2"><br> |
| private DefaultComboBoxModel mapProvidersModel =<br> |
| new DefaultComboBoxModel();</p> |
| <p class="style2">private void searchMapProviders() { <br> |
| Result result = Lookup.getDefault().lookup(<br> |
| new Template(MapProvider.class));</p> |
| <p class="style2"> for (Object provider : result.allInstances()) {<br> |
| mapProvidersModel.addElement(provider); <br> |
| }<br> |
| } </p> |
| </blockquote></td> |
| </tr> |
| </table> |
| <p class=NB-Interttulo22><b><font size=1 color="#0081c7" face="Verdana"><span |
| lang=EN-US style='font-size:9.0pt'>The Lookup API also |
| promotes decoupling</span></font></b></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>The default </span></font><span class=NB-NegritoTcnico2><b><font |
| size=2 color=black face="Verdana"><span lang=EN-US style='font-size: |
| 10.0pt'>Lookup</span></font></b></span><span lang=EN-US> instance also contains |
| the current set of selected </span><span class=NB-NegritoTcnico2><b><font |
| size=2 color=black face="Verdana"><span lang=EN-US style='font-size: |
| 10.0pt'>Node</span></font></b></span><span lang=EN-US> objects. This makes it |
| possible to design an effective and loosely-coupled mechanism also for inter-module |
| communication. It’s based on the Observer pattern: some modules publish their |
| node selection to the default </span><span class=NB-NegritoTcnico2><b><font |
| size=2 color=black face="Verdana"><span lang=EN-US style='font-size: |
| 10.0pt'>Lookup</span></font></b></span><span lang=EN-US>, while others listen |
| for changes. And by implementing some filtering related to the kind of |
| information associated to the changed nodes we get to the Publish/<br> |
| Subscribe design pattern.</span></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>For example, in blueMarine there are many ways to |
| navigate the photo database and show a set of thumbnails – by exploring |
| folders, the calendar, photos that share a tag, photos in the same gallery, and |
| so on. The “explorer” modules just publish a selection of </span></font><span |
| class=NB-NegritoTcnico2><b><font size=2 color=black face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt'>Node</span></font></b></span><span |
| lang=EN-US>s bound to </span><span class=NB-NegritoTcnico2><b><font size=2 |
| color=black face="Verdana"><span lang=EN-US style='font-size:10.0pt'>PhotoDataObject</span></font></b></span><span |
| lang=EN-US>s to the default </span><span class=NB-NegritoTcnico2><b><font |
| size=2 color=black face="Verdana"><span lang=EN-US style='font-size: |
| 10.0pt'>Lookup</span></font></b></span><span lang=EN-US>; a Thumbnail Viewer |
| receives notifications and updates itself appropriately (see <b><span |
| style='font-weight:bold'>Figure 5</span></b>).</span></p> |
| <table width="100%" border="0" cellspacing="0" cellpadding="0"> |
| <tr> |
| <td><img src="/images_www/magazine/bluemarine/images/image010.jpg" width="400" height="209"></td> |
| </tr> |
| <tr> |
| <td><p class=NB-Corpo211111><strong>Figure 5.</strong> The role of Node objects for inter-module communication.<br> |
| <br> |
| </p></td> |
| </tr> |
| </table> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>The explorer components do not depend on the Thumbnail |
| Viewer. Actually they are completely decoupled from it (we’re applying |
| Inversion of Control here). With this design I can add as many explorers as I |
| want, even in independent modules that can be installed as add-ons. I can also |
| easily add new viewers. For instance, I was able to include a Filmstrip Viewer |
| as a completely decoupled component that can be used by itself or together with |
| the original Thumbnail Viewer (see <b><span style='font-weight:bold'>Figures 6 </span></b>and<b><span |
| style='font-weight:bold'> 7</span></b>).</span></font></p> |
| <table width="100%" border="0" cellspacing="0" cellpadding="0"> |
| <tr> |
| <td><img src="/images_www/magazine/bluemarine/images/image012.jpg" width="340" height="320"></td> |
| </tr> |
| <tr> |
| <td><p class=NB-Corpo21111111><strong>Figure 6.</strong> The Thumbnail Viewer and the Film Strip Viewer must show the same nodes – with the same selection too.<br> |
| <br> |
| </p></td> |
| </tr> |
| </table> |
| <table width="100%" border="0" cellspacing="0" cellpadding="0"> |
| <tr> |
| <td><img src="/images_www/magazine/bluemarine/images/image014.jpg" width="400" height="145"></td> |
| </tr> |
| <tr> |
| <td><p class=NB-Corpo2111111><strong>Figure 7.</strong> Multiple, synchronized views are implemented by just listening to the same Node’s changes.<br> |
| <br> |
| </p></td> |
| </tr> |
| </table> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>The Lookup API has many other uses, as many types of |
| objects (including </span></font><span class=NB-NegritoTcnico2><b><font size=2 |
| color=black face="Verdana"><span lang=EN-US style='font-size:10.0pt'>Node</span></font></b></span><span |
| lang=EN-US>s themselves) have their own local </span><span |
| class=NB-NegritoTcnico2><b><font size=2 color=black face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt'>Lookup</span></font></b></span><span |
| lang=EN-US> instance. I’ve only shown the “tip of the iceberg” here.</span><br> |
| <br> |
| </p> |
| <p class=NB-Interttulo22><b><font size=1 color="#0081c7" face="Verdana"><span |
| lang=EN-US style='font-size:9.0pt'>The FileSystem API</span></font></b></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>Java offers just a bare-bones approach for file |
| management through the </span></font><span class=NB-NegritoTcnico2><b><font |
| size=2 color=black face="Verdana"><span lang=EN-US style='font-size: |
| 10.0pt'>java.io.File</span></font></b></span><span lang=EN-US> class, which |
| wraps a file name and provides attribute access, basic operations and directory |
| listing. This approach is really poor, since there’s no concept of a |
| filesystem; furthermore, </span><span class=NB-NegritoTcnico2><b><font size=2 |
| color=black face="Verdana"><span lang=EN-US style='font-size:10.0pt'>File</span></font></b></span><span |
| lang=EN-US> objects are bound to local, physical files/directories. What if you |
| need to represent a virtual or remote directory tree? I faced this problem a |
| few years ago, and in the end I solved it by extensively subclassing </span><span |
| class=NB-NegritoTcnico2><b><font size=2 color=black face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt'>File</span></font></b></span><span |
| lang=EN-US> – not a neat design, even though it worked.</span></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>NetBeans’ </span></font><span class=NB-NegritoTcnico2><b><font |
| size=2 color=black face="Verdana"><span lang=EN-US style='font-size: |
| 10.0pt'>FileSystem</span></font></b></span><span lang=EN-US> API fills this |
| gap. There’s a whole set of </span><span class=NB-NegritoTcnico2><b><font |
| size=2 color=black face="Verdana"><span lang=EN-US style='font-size: |
| 10.0pt'>FileSystem</span></font></b></span><span lang=EN-US> classes that can |
| be used to represent different types of filesystems: local, remote or even |
| virtual. (NetBeans’ inner configuration settings, including those of your |
| custom code, are stored in such a virtual file system.) The only caveat is that |
| you must use a NetBeans-specific instance of </span><span |
| class=NB-NegritoTcnico2><b><font size=2 color=black face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt'>FileObject</span></font></b></span><span |
| lang=EN-US> instead of </span><span class=NB-NegritoTcnico2><b><font size=2 |
| color=black face="Verdana"><span lang=EN-US style='font-size:10.0pt'>File</span></font></b></span><span |
| lang=EN-US>, but converting one into the other is easy:</span></p> |
| <p class="style2">FileObject fileObject = ...;</span></font><br> |
| File file = ...;</span></font><br> |
| file = FileUtil.toFile(fileObject);</span></font><br> |
| fileObject = FileUtil.toFileObject(file);</span></font> </p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>blueMarine has a strict requirement for managing files. |
| Each file must be associated with a unique id stored in a local database. The |
| id is later used to build relationships between each photo and other entities |
| such as thumbnails, metadata, galleries, editing settings, and so on. It’s a |
| rather common design for this kind of application, allowing you to later move |
| or rename photos without too many changes in the database. It also lets you |
| work with remote volumes such as external disks and DVDs. In other words, even |
| when you don’t have the file available in the system, you can look at its |
| thumbnails and metadata.</span></font></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>A good starting point for tweaking the filesystem |
| management is the </span></font><span class=NB-NegritoTcnico2><b><font size=2 |
| color=black face="Verdana"><span lang=EN-US style='font-size:10.0pt'>LocalFileSystem</span></font></b></span><span |
| lang=EN-US> class, which represents a tree of files with a single root (for |
| systems with multi-root hierarchies like Windows you just need to put a few </span><span |
| class=NB-NegritoTcnico2><b><font size=2 color=black face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt'>LocalFileSystem</span></font></b></span><span |
| lang=EN-US> objects together). </span></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>The </span></font><span class=NB-NegritoTcnico2><b><font |
| size=2 color=black face="Verdana"><span lang=EN-US style='font-size: |
| 10.0pt'>LocalFileSystem</span></font></b></span><span lang=EN-US> class |
| includes </span><span class=NB-NegritoTcnico2><b><font size=2 color=black |
| face="Verdana"><span lang=EN-US style='font-size:10.0pt'>AbstractFileSystem.Attr</span></font></b></span><span |
| lang=EN-US> and </span><span class=NB-NegritoTcnico2><b><font size=2 |
| color=black face="Verdana"><span lang=EN-US style='font-size:10.0pt'>AbstractFileSystem.List</span></font></b></span><span |
| lang=EN-US>. </span><span class=NB-NegritoTcnico2><b><font size=2 color=black |
| face="Verdana"><span lang=EN-US style='font-size:10.0pt'>Attr</span></font></b></span><span |
| lang=EN-US> lets you manipulate a set of attributes for each </span><span |
| class=NB-NegritoTcnico2><b><font size=2 color=black face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt'>FileObject</span></font></b></span><span |
| lang=EN-US>, and </span><span class=NB-NegritoTcnico2><b><font size=2 |
| color=black face="Verdana"><span lang=EN-US style='font-size:10.0pt'>List</span></font></b></span><span |
| lang=EN-US> lets you customize a directory listing. (Attributes are just simple |
| properties which are bound to a </span><span class=NB-NegritoTcnico2><b><font |
| size=2 color=black face="Verdana"><span lang=EN-US style='font-size: |
| 10.0pt'>FileObject</span></font></b></span><span lang=EN-US> and can be |
| manipulated with getters and setters.)</span></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt;letter-spacing:-.1pt'>I started by writing a simple |
| subclass of </span></font><span class=NB-NegritoTcnico2><b><font size=2 |
| color=black face="Verdana"><span lang=EN-US style='font-size:10.0pt; |
| letter-spacing:-.1pt'>LocalFileSystem</span></font></b></span><span lang=EN-US |
| style='letter-spacing:-.1pt'> that installs decorators of </span><span |
| class=NB-NegritoTcnico2><b><font size=2 color=black face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt;letter-spacing:-.1pt'>Attr</span></font></b></span><span |
| lang=EN-US style='letter-spacing:-.1pt'> and </span><span |
| class=NB-NegritoTcnico2><b><font size=2 color=black face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt;letter-spacing:-.1pt'>List</span></font></b></span><span |
| lang=EN-US style='letter-spacing:-.1pt'>, as shown in <b><span |
| style='font-weight:bold'>Listing 3</span></b>. The</span><span |
| class=NB-NegritoTcnico2><b><font size=2 color=black face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt;letter-spacing:-.1pt'> AttrDecorator</span></font></b></span><span |
| lang=EN-US style='letter-spacing:-.1pt'> class retrieves the unique id for each |
| file path (the </span><span class=NB-NegritoTcnico2><b><font size=2 color=black |
| face="Verdana"><span lang=EN-US style='font-size:10.0pt;letter-spacing: |
| -.1pt'>FileIndexer</span></font></b></span><span lang=EN-US style='letter-spacing: |
| -.1pt'> is just a sort of DAO for this data), and makes it available as a |
| special attribute of </span><span class=NB-NegritoTcnico2><b><font size=2 |
| color=black face="Verdana"><span lang=EN-US style='font-size:10.0pt; |
| letter-spacing:-.1pt'>FileObject</span></font></b></span><span lang=EN-US |
| style='letter-spacing:-.1pt'> (</span><span class=NB-NegritoTcnico2><b><font |
| size=2 color=black face="Verdana"><span lang=EN-US style='font-size: |
| 10.0pt;letter-spacing:-.1pt'>ID_ATTRIBUTE</span></font></b></span><span |
| lang=EN-US style='letter-spacing:-.1pt'>). The code is shown in <b><span |
| style='font-weight:bold'>Listing 4</span></b>. <br> |
| </span></p> |
| <table width="100%" border="1" cellpadding="0" cellspacing="0" bordercolor="#0081C7"> |
| <tr> |
| <td bgcolor="#0081C7"><p class="NB-Listagenstitulos"><strong>Listing 3.</strong> Plugging decorators into the LocalFileSystem class.</p></td> |
| </tr> |
| <tr> |
| <td><blockquote> |
| <pre class="style2">class LocalIndexedFileSystem extends LocalFileSystem { |
| public LocalIndexedFileSystem() { |
| attr = new AttrDecorator(attr, this); |
| list = new ListDecorator(list, this); |
| } |
| } </pre> |
| </blockquote></td> |
| </tr> |
| </table> |
| <br> |
| <br> |
| <table width="100%" border="1" cellpadding="0" cellspacing="0" bordercolor="#0081C7"> |
| <tr> |
| <td bgcolor="#0081C7"><p class="NB-Listagenstitulos"><strong>Listing 4.</strong> Retrieving registered objects.</p></td> |
| </tr> |
| <tr> |
| <td><blockquote> |
| <pre class="style2">class AttrDecorator implements AbstractFileSystem.Attr { |
| private static final FileIndexer fileIndexer = |
| FileIndexerLocator.findFileIndexer(); |
| private AbstractFileSystem.Attr peer; |
| private LocalIndexedFileSystem fileSystem; |
| |
| public AttrDecorator(AbstractFileSystem.Attr peer, |
| LocalIndexedFileSystem fileSystem) { |
| this.peer = peer; |
| this.fileSystem = fileSystem; |
| }</pre> |
| <pre class="style2"> public Object readAttribute (String path, String name) { |
| if (IndexedFileSystem.ID_ATTRIBUTE.equals(name)) { |
| String path2 = fileSystem.findCompletePath(path); |
| Serializable id = fileIndexer.findIdByPath(path2); </pre> |
| <pre class="style2"> if (id == null) { |
| fileIndexer.createIndexing(path2, false); |
| id = fileIndexer.findIdByPath(path2); |
| } |
| return id; |
| } |
| else { |
| return peer.readAttribute(path, name); |
| } |
| } |
| |
| ... |
| }</pre> |
| </blockquote></td> |
| </tr> |
| </table> |
| <br> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>While </span></font><span class=NB-NegritoTcnico2><b><font |
| size=2 color=black face="Verdana"><span lang=EN-US style='font-size: |
| 10.0pt'>AttrDecorator</span></font></b></span><span lang=EN-US> would be enough |
| to satisfy the functional specs, there’s still the problem of batch loading. |
| The </span><span class=NB-NegritoTcnico2><b><font size=2 color=black |
| face="Verdana"><span lang=EN-US style='font-size:10.0pt'>readAttribute()</span></font></b></span><span |
| lang=EN-US> method would be called quite randomly, thus preventing any |
| effective batch policy (</span><span class=NB-NegritoTcnico2><b><font size=2 |
| color=black face="Verdana"><span lang=EN-US style='font-size:10.0pt'>FileIndexer</span></font></b></span><span |
| lang=EN-US> is able to do batching by lazy loading, but to be effective it |
| needs to have a good number of entries to batch!). </span></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>Here </span></font><span class=NB-NegritoTcnico2><b><font |
| size=2 color=black face="Verdana"><span lang=EN-US style='font-size: |
| 10.0pt'>ListDecorator</span></font></b></span><span lang=EN-US> helps us, as it |
| intercepts children files after they are listed from a parent directory (see <b><span |
| style='font-weight:bold'>Listing 5</span></b>). Calling<b><span |
| style='font-weight:bold'> </span></b></span><span class=NB-NegritoTcnico2><b><font |
| size=2 color=black face="Verdana"><span lang=EN-US style='font-size: |
| 10.0pt'>createIndexing()</span></font></b></span><b><span lang=EN-US |
| style='font-weight:bold'> </span></b><span lang=EN-US>immediately on the set of |
| listed files allows the </span><span class=NB-NegritoTcnico2><b><font size=2 |
| color=black face="Verdana"><span lang=EN-US style='font-size:10.0pt'>FileIndexer</span></font></b></span><span |
| lang=EN-US> to batch the retrieval of their ids.</span></p> |
| <table width="100%" border="1" cellpadding="0" cellspacing="0" bordercolor="#0081C7"> |
| <tr> |
| <td bgcolor="#0081C7"><p class="NB-Listagenstitulos"><strong>Listing 5.</strong> Decorating directory scanning.</p></td> |
| </tr> |
| <tr> |
| <td><blockquote> |
| <p class="style2"><br> |
| class ListDecorator implements AbstractFileSystem.List {<br> |
| private static final FileIndexer fileIndexer =<br> |
| FileIndexerLocator.findFileIndexer();<br> |
| private AbstractFileSystem.List peer;<br> |
| private LocalIndexedFileSystem fileSystem;<br> |
| <br> |
| public ListDecorator (<br> |
| AbstractFileSystem.List peer, LocalIndexedFileSystem fileSystem) <br> |
| {<br> |
| this.peer = peer; <br> |
| this.fileSystem = fileSystem;<br> |
| }</p> |
| <p class="style2"> public String[] children (String path) {<br> |
| String[] result = peer.children(path);<br> |
| <br> |
| if (!fileSystem.disableChildrenIndexing) {<br> |
| String path2 = fileSystem.findCompletePath(path);<br> |
| if (result != null) {<br> |
| for (String child : result) {<br> |
| fileIndexer.createIndexing(path2 + child, true);<br> |
| }<br> |
| } <br> |
| }<br> |
| return result;<br> |
| }<br> |
| }</p> |
| </blockquote></td> |
| </tr> |
| </table> |
| <p class=NB-Interttulo22><b><font size=1 color="#0081c7" face="Verdana"><span |
| lang=EN-US style='font-size:9.0pt'>Actions and Menus</span></font></b></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>Actions and Menus (together with auxiliary components |
| such as toolbars) are the main facilities for interacting with the user. Swing |
| provides basic support for them, but you soon realize that this is not enough, |
| especially if you are designing a modular application. </span></font></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>Menus are organized hierarchically and grouped |
| according to intuitive criteria. So a pluggable module will need to place its |
| own menu items in the proper places (for instance, under a global “Edit” or |
| “View” item in the menu bar), and possibly respect some meaningful sequence |
| (e.g. “menu items of module C should appear between those of modules A and B”). |
| Also you might like to introduce menu dividers to group some menu items |
| together. </span></font></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>Swing actions can be enabled and disabled with a simple |
| attribute change; but the implementation of the decision whether to enable or |
| disable them is up to you. Often this is done by a special method that computes |
| the states of a set of actions and is invoked after any change made by the |
| user, as in:</span></font><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'> </span></font></p> |
| <pre class="style2">private void setEnablementStatus() {</span></font> |
| </span>myAction1.setEnabled(/* condition 1 */);</span></font> |
| </span>myAction2.setEnabled(/* condition 2 */);</span></font> |
| </span>...</span></font> |
| }</span></font></pre> |
| |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>This approach works, but it's neither modular nor easily maintainable. And one must consider that in most cases the boolean conditions (condition 1, 2, etc. in the previous code) are just a function of the set of objects currently selected by the user – e.g., you can run “Edit” or “Print” only if a photo is selected.</span></font></p> |
| |
| <!-- test --> |
| |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>Managing Menus and Actions with plain Swing in a clever |
| way doesn’t require rocket science, but you’ll get a headache if it needs to be |
| done from scratch for a sophisticated, modularized application. Fortunately, the |
| NetBeans Platform also helps you in this area.</span></font></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>First, the Platform provides richer classes than |
| Swing’s </span></font><span class=NB-NegritoTcnico2><b><font size=2 color=black |
| face="Verdana"><span lang=EN-US style='font-size:10.0pt'>Action</span></font></b></span><span |
| lang=EN-US>. Some of the most commonly used are:</span></p> |
| <ul> |
| <li><span class=NB-NegritoTcnico2><b><font |
| size=2 color=black face="Verdana"><span lang=EN-US style='font-size: |
| 10.0pt'>NodeAction</span></font></b></span><span lang=EN-US> – A generic action |
| that changes state when a new set of </span><span class=NB-NegritoTcnico2><b><font |
| size=2 color=black face="Verdana"><span lang=EN-US style='font-size: |
| 10.0pt'>Node</span></font></b></span><span lang=EN-US>s is selected. The |
| programmer must subclass it and override an </span><span |
| class=NB-NegritoTcnico2><b><font size=2 color=black face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt'>enable(Node[])</span></font></b></span><span |
| lang=EN-US> method, which evaluates the proper boolean expression for |
| activating the action.</span></li> |
| <li><span class=NB-NegritoTcnico2><b><font |
| size=2 color=black face="Verdana"><span lang=EN-US style='font-size: |
| 10.0pt'>CookieAction</span></font></b></span><span lang=EN-US> – This is an |
| action whose state depends on the currently selected </span><span |
| class=NB-NegritoTcnico2><b><font size=2 color=black face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt'>Node</span></font></b></span><span |
| lang=EN-US>, and on it being bound to a given object (usually a specific </span><span |
| class=NB-NegritoTcnico2><b><font size=2 color=black face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt'>DataObject</span></font></b></span><span |
| lang=EN-US>). It also deals with different selection modes such as “exactly |
| one”, “at least one”, etc. </span></li> |
| </ul> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'> </span></font><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>After having implemented your action using the proper |
| class, you declare it in your module’s <i><span style='font-style:italic'>layer.xml</span></i>, |
| which acts as a generic configuration file (it models a “virtual file system” |
| structured as the contained XML DOM). </span></font></p> |
| <p class=NB-Notadica2><font size=2 color="#0081c7" face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt'><strong>Note: </strong>Usually you don’t have to do this manually: |
| the NetBeans IDE offers a “New action” wizard that asks for the required |
| information and both generates skeleton Java code and updates the relevant part |
| of <i><span style='font-style:italic'>layer.xml.</span></i> In fact, most of |
| the XML in the following examples can be generated or manipulated through the |
| IDE.</span></font></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>This approach works for both actions that should appear |
| on contextual menus (see <b><span style='font-weight:bold'>Figure 8</span></b>) |
| and for actions that need to be attached to a “regular” menu.<i><span |
| style='font-style:italic'> </span></i>In <i><span style='font-style:italic'>layer.xml</span></i> you can also declare toolbars, where groups of buttons are logically bound to |
| actions, and define keyboard shortcuts.</span></font></p> |
| <table width="100%" border="0" cellspacing="0" cellpadding="0"> |
| <tr> |
| <td><img src="/images_www/magazine/bluemarine/images/image016.jpg" width="340" height="285"></td> |
| </tr> |
| <tr> |
| <td><p class=NB-Corpo21111112><strong>Figure 8.</strong> Each thumbnail is a rendered Node object bound to a PhotoDataObject and can pop up a menu with contextual actions. The grid arrangement and the look of thumbnails are implemented by means of a customized ListView. </p></td> |
| </tr> |
| </table> |
| <p class=NB-Corpo3><br> |
| <b><font size=1 color="#0081c7" face="Verdana"><span |
| lang=EN-US style='font-size:9.0pt'>The Windowing API</span></font></b></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>The NetBeans Platform provides a specific windowing |
| component named </span></font><span class=NB-NegritoTcnico2><b><font size=2 |
| color=black face="Verdana"><span lang=EN-US style='font-size:10.0pt'>TopComponent. </span></font></b></span><span lang=EN-US>This component models a rectangular |
| portion of the main window, which can be resized and docked in different areas |
| of the screen (these areas are called “modes”). For instance, the Explorer mode |
| is a vertical column at the left side; the Properties mode is a vertical column |
| at the right side; the Editor mode is the remaining space at the center (see <b><span |
| style='font-weight:bold'>Figure 9</span></b>). </span></p> |
| <table width="100%" border="0" cellspacing="0" cellpadding="0"> |
| <tr> |
| <td><img src="/images_www/magazine/bluemarine/images/image018.jpg" width="444" height="311"></td> |
| </tr> |
| <tr> |
| <td><p class=NB-Corpo211111121><strong>Figure 9.</strong> Modes in the main window of blueMarine – “strip” is a custom mode; each mode contains a TopComponent. </p></td> |
| </tr> |
| </table> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>Also, a </span></font><span class=NB-NegritoTcnico2><b><font |
| size=2 color=black face="Verdana"><span lang=EN-US style='font-size: |
| 10.0pt'>TopComponent</span></font></b></span><span lang=EN-US> can be activated |
| or deactivated, has its own mechanism for keeping persistent state (which is |
| automatically restored on restart), and can request attention by flashing its |
| tab.</span></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>Docking areas can be resized with the mouse, or |
| programmatically. You can assign </span></font><span class=NB-NegritoTcnico2><b><font |
| size=2 color=black face="Verdana"><span lang=EN-US style='font-size: |
| 10.0pt'>TopComponent</span></font></b></span><span lang=EN-US>s to different |
| areas by dragging them with the mouse or through code. You can define your own |
| docking areas as well. For instance, I needed a component called “Film Strip” |
| that should be placed at the bottom of the window. So I defined a docking area |
| called “strip” and bound the Film Strip to it (see <b><span style='font-weight: |
| bold'>Figure 9</span></b> again).</span></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>While this flexibility is great for some types of |
| applications, such as an IDE or a CAD system, so much control could be |
| distracting to some classes of users. For blueMarine I prefer not to have such |
| flexible docking: a fixed scheme is used, offering just a bit of control |
| through menu commands that let you swap the components in the Explorer and |
| Properties modes. </span></font></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>The tabs and the control code which allows docking with |
| the mouse has been removed in blueMarine by specifying a special </span></font><span |
| class=NB-NegritoTcnico2><b><font size=2 color=black face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt'>TabDisplayerUI</span></font></b></span><span |
| lang=EN-US> (the visual component for each mode). I implemented programmatic |
| control with the code in <b><span style='font-weight:bold'>Listing 6</span></b>.</span></p> |
| <table width="100%" border="1" cellpadding="0" cellspacing="0" bordercolor="#0081C7"> |
| <tr> |
| <td bgcolor="#0081C7"><p class="NB-Listagenstitulos"><strong>Listing 6.</strong> Programmatic component docking.</p></td> |
| </tr> |
| <tr> |
| <td><blockquote> |
| <pre class="style2">TopComponent topComponent = ...; |
| String newMode = “explorer”; |
| Mode targetMode = WindowManager.getDefault().findMode(newMode);</pre> |
| <pre class="style2">if (targetMode != null) { |
| component.close(); |
| targetMode.dockInto(component); |
| component.open(); |
| component.requestVisible(); |
| } </pre> |
| </blockquote></td> |
| </tr> |
| </table> |
| <p class=NB-Notadica2><font size=2 color="#0081c7" face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt'><strong>Note: </strong>Indeed it was not hard at all to implement |
| the </span></font><span class=NB-NegritoTcnico2><b><font size=1 color="#0081c7" |
| face="Verdana"><span lang=EN-US style='font-size:8.0pt;color:#0081C7'>TabDisplayerUI</span></font></b></span> <span |
| lang=EN-US>trick, but only because I discovered the solution on Geertjan |
| Wielenga’s blog; without that help it would have taken much longer. I found |
| that programmers can enjoy excellent support from the NetBeans community, both |
| in the mailing list and in the evangelists’ blogs – I recommend you to bookmark |
| these! </span></p> |
| <p class=NB-Interttulo22><b><font size=1 color="#0081c7" face="Verdana"><span |
| lang=EN-US style='font-size:9.0pt'>The Look & Feel</span></font></b></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>The predefined Java look and feels are getting better |
| with each JDK release, but sometimes you need a special LAF. For instance, |
| dealing with photography you need a clean GUI that doesn’t distract the user, |
| and a darkish theme (where all the used colors are rigorously shades of gray), |
| so as not to disturb a correct perception of colors.</span></font></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>Since JDK 1.4, the </span></font><span |
| class=NB-NegritoTcnico2><b><font size=2 color=black face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt'>UIManager</span></font></b></span><span |
| lang=EN-US> class allows you to plug different look and feels with minimal or |
| no impact on existing code. As the class is a part of the standard Swing API, |
| there are a lot of compatible LAFs that can be easily plugged into your app. </span></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>If you find a look and feel that you like, you can |
| install it into NetBeans (and of course into your NetBeans Platform |
| application) with a simple command-line switch:</span></font><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'> </span></font></p> |
| <p class="style2">--look-and-feel <name of the L&F |
| class></span></font></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>After some tests, I decided to keep the native look and |
| feel for every piece of the GUI except for the main window, where I just |
| changed the component colors (Mac OS X is a special case; see below). The |
| typical blueMarine look and feel is illustrated in<b><span style='font-weight: |
| bold'> Figure 10</span></b>.</span></font></p> |
| <table width="100%" border="0" cellspacing="0" cellpadding="0"> |
| <tr> |
| <td><img src="/images_www/magazine/bluemarine/images/image020.jpg" width="367" height="295"></td> |
| </tr> |
| <tr> |
| <td><p class=NB-Corpo2111111211><strong>Figure 10.</strong> Using a dark color scheme in the main window and a regular scheme in popups. </p></td> |
| </tr> |
| </table> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>As you know, changing the colors of a Swing component |
| is usually a matter of </span></font><span class=NB-NegritoTcnico2><b><font |
| size=2 color=black face="Verdana"><span lang=EN-US style='font-size: |
| 10.0pt'>c.setForeground()</span></font></b></span><span lang=EN-US> and </span><span |
| class=NB-NegritoTcnico2><b><font size=2 color=black face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt'>c.setBackground()</span></font></b></span><span |
| lang=EN-US>. Since the NetBeans Platform is Swing-based, things aren’t much |
| different. But there are a few exceptions. For instance, these standard methods |
| don’t work on </span><span class=NB-NegritoTcnico2><b><font size=2 color=black |
| face="Verdana"><span lang=EN-US style='font-size:10.0pt'>ListView</span></font></b></span><span |
| lang=EN-US> (one of the most used view components for </span><span |
| class=NB-NegritoTcnico2><b><font size=2 color=black face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt'>Node</span></font></b></span><span |
| lang=EN-US> objects). In blueMarine, this was fixed with the code in <b><span |
| style='font-weight:bold'>Listing 7</span></b>, which first retrieves the |
| inner </span><span class=NB-NegritoTcnico2><b><font size=2 color=black |
| face="Verdana"><span lang=EN-US style='font-size:10.0pt'>JList</span></font></b></span><span |
| lang=EN-US> and then changes its properties as needed. Similar code works with |
| tree-based components (which share the same problem).</span></p> |
| <table width="100%" border="1" cellpadding="0" cellspacing="0" bordercolor="#0081C7"> |
| <tr> |
| <td bgcolor="#0081C7"><p class="NB-Listagenstitulos"><strong>Listing 7.</strong> An enhanced ListView.</p></td> |
| </tr> |
| <tr> |
| <td><blockquote> |
| <pre class="style2"> |
| public class EnhancedListView extends ListView { |
| protected JList jList; |
| |
| @Override |
| protected JList createList() { |
| jList = super.createList(); |
| jList.setOpaque(isOpaque()); |
| jList.setBackground(getBackground()); |
| jList.setForeground(getForeground()); |
| return jList; |
| }</pre> |
| <pre class="style2">@Override |
| public void setBackground (Color color) { |
| super.setBackground(color); |
| if (jList != null) { |
| jList.setBackground(color); |
| } |
| }</pre> |
| <pre class="style2">@Override |
| public void setForeground (Color color){ |
| super.setForeground(color); |
| if (jList != null) { |
| jList.setForeground(color); |
| } |
| }</pre> |
| <pre><span class="style2">@Override |
| public void setOpaque (boolean opaque){ |
| super.setOpaque(opaque); |
| if (jList != null) { |
| jList.setOpaque(opaque); |
| } |
| } |
| }</span> |
| </pre> |
| </blockquote></td> |
| </tr> |
| </table> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>I found another problem with tree-based components: |
| even with the code shown before, tree cells were rendered in black and white. |
| Again, inspecting the sources, it was easy to find the cause: NetBeans’ trees |
| usually have a special cell renderer which does many things, such as supporting |
| HTML rendering (so you can use multiple text styles); the cell renderer also |
| chooses a color scheme that contrasts well between the foreground and the |
| background. This is a clever idea in most cases, but not when you want to |
| fine-tune your colors. The workaround was implemented by the few lines shown in <b><span style='font-weight:bold'>Listing 8</span></b>. Here’s how you |
| install the patched renderer:</span></font></p> |
| <p class="style2">PatchedNodeRenderer |
| nodeRenderer = new PatchedNodeRenderer(tree.getCellRenderer());<br> |
| tree.setCellRenderer(nodeRenderer);</span></font></p> |
| <table width="100%" border="1" cellpadding="0" cellspacing="0" bordercolor="#0081C7"> |
| <tr> |
| <td bgcolor="#0081C7"><p class="NB-Listagenstitulos"><strong>Listing 8.</strong> A patched cell renderer for controlling colors in JTree’s.</p></td> |
| </tr> |
| <tr> |
| <td><blockquote> |
| <pre class="style2">class PatchedNodeRenderer extends DefaultTreeCellRenderer { |
| private TreeCellRenderer peer; |
| public PatchedNodeRenderer (final TreeCellRenderer peer) { |
| this.peer = peer; |
| } |
| @Override |
| public Component getTreeCellRendererComponent (final JTree jTree, |
| final Object object, final boolean selected, final boolean expanded, |
| final boolean leaf, final int row, final boolean hasFocus) |
| { |
| final Component component = peer.getTreeCellRendererComponent( |
| jTree, object, selected, expanded, leaf, row, hasFocus); |
| component.setBackground( |
| selected ? getBackgroundSelectionColor() : getBackgroundNonSelectionColor()); |
| component.setForeground( |
| selected ? getTextSelectionColor() : getTextNonSelectionColor()); |
| return component; |
| } |
| }</pre> |
| </blockquote></td> |
| </tr> |
| </table> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>Regarding the look and feel, Mac OS X raised some |
| particular issues. Mac users, who are really picky about aesthetics, noticed |
| some time ago that even the Java implementation created by Apple does not |
| accurately reproduce the operating system look and feel. This prompted the |
| creation of a third-party product, named Quaqua, which fixes all the problems |
| and implements a pixel-accurate Aqua GUI. (Actually the problems go beyond pixel |
| accuracy: for instance the Java </span></font><span class=NB-NegritoTcnico2><b><font |
| size=2 color=black face="Verdana"><span lang=EN-US style='font-size: |
| 10.0pt'>JFileChooser</span></font></b></span><span lang=EN-US> under Apple’s |
| Mac OS LAF is terrible in comparison to the native one.) As Quaqua is a regular |
| look and feel handled by the </span><span class=NB-NegritoTcnico2><b><font |
| size=2 color=black face="Verdana"><span lang=EN-US style='font-size: |
| 10.0pt'>UIManager </span></font></b></span><span lang=EN-US>class, its |
| integration in blueMarine was not a problem, with the exception of a few Quaqua |
| issues that were quickly fixed by the project’s developer.</span><br> |
| <br> |
| <b><font size=1 color="#0081c7" face="Verdana"><span |
| lang=EN-US style='font-size:9.0pt'>Other extensions needed</span></font></b></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>A little more work was necessary with </span></font><span |
| class=NB-NegritoTcnico2><b><font size=2 color=black face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt'>ListView</span></font></b></span><span |
| lang=EN-US>, since the thumbnail-rendering components required a custom |
| renderer (to provide the “slide” look and for overlaying extra information). |
| Also needed was a grid layout with a predefined cell size. See <b><span |
| style='font-weight:bold'>Figure 9</span></b>.</span></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>The standard </span></font><span |
| class=NB-NegritoTcnico2><b><font size=2 color=black face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt'>JList</span></font></b></span><span |
| lang=EN-US> makes these things quite easy to achieve. It’s a matter of setting |
| a few properties:</span><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'> </span></font></p> |
| <p class="style2">jList.setCellRenderer(...);</span></font><br> |
| jList.setLayoutOrientation(JList.HORIZONTAL_WRAP);</span></font><br> |
| jList.setFixedCellWidth(150);</span></font><br> |
| jList.setFixedCellHeight(150);</span></font></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt'>But unfortunately NetBeans Platform developers left |
| these methods out of </span></font><span class=NB-NegritoTcnico2><b><font |
| size=2 color=black face="Verdana"><span lang=EN-US style='font-size: |
| 10.0pt'>ListView</span></font></b></span><span lang=EN-US> (much like the |
| control of colors). With a similar workaround to the one used for the colors |
| problem (i.e. accessing the inner </span><span class=NB-NegritoTcnico2><b><font |
| size=2 color=black face="Verdana"><span lang=EN-US style='font-size: |
| 10.0pt'>JList</span></font></b></span><span lang=EN-US>), it was easy for me to |
| add the missing methods to </span><span class=NB-NegritoTcnico2><b><font size=2 |
| color=black face="Verdana"><span lang=EN-US style='font-size:10.0pt'>EnhancedListView</span></font></b></span><span |
| lang=EN-US>, as you see in <b><span style='font-weight:bold'>Listing 9</span></b>.</span></p> |
| <table width="100%" border="1" cellpadding="0" cellspacing="0" bordercolor="#0081C7"> |
| <tr> |
| <td bgcolor="#0081C7"><p class="NB-Listagenstitulos"><strong>Listing 9.</strong> New methods in ListView.</p></td> |
| </tr> |
| <tr> |
| <td><blockquote> |
| <pre class="style2">public class EnhancedListView extends ListView { |
| ... |
| public void setCellRenderer (ListCellRenderer listCellRenderer) { |
| jList.setCellRenderer(listCellRenderer); |
| } |
| public void setFixedCellWidth (int size) { |
| jList.setFixedCellWidth(size); |
| } |
| public void setFixedCellHeight (int size) { |
| jList.setFixedCellHeight(size); |
| } |
| public void setLayoutOrientation (int layoutOrientation) { |
| jList.setLayoutOrientation(layoutOrientation); |
| } |
| } |
| </pre> |
| </blockquote></td> |
| </tr> |
| </table> |
| <table width="100%" border="1" cellpadding="0" cellspacing="0" bordercolor="#0081C7"> |
| <tr> |
| <td bgcolor="#0081C7"><p class="NB-Listagenstitulos"><strong>Listing 10.</strong> Retrieving the Node object from a custom cell renderer.</p></td> |
| </tr> |
| <tr> |
| <td><blockquote> |
| <pre class="style2">import org.openide.explorer.view.Visualizer;</pre> |
| <pre class="style2">public class ThumbnailRenderer extends JComponent implements ListCellRenderer { |
| final public Component getListCellRendererComponent( |
| JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { |
| this.hasFocus = cellHasFocus; |
| this.selected = isSelected; |
| this.index = index; |
| Node node = Visualizer.findNode(value); |
| thumbnail = (Thumbnail)node.getLookup().lookup(Thumbnail.class); |
| return this; |
| } |
| ...</pre> |
| </blockquote></td> |
| </tr> |
| </table> |
| <br> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt;letter-spacing:-.1pt'>As a final point, custom </span></font><span |
| class=NB-NegritoTcnico2><b><font size=2 color=black face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt;letter-spacing:-.1pt'>ListCellRenderer</span></font></b></span><span |
| lang=EN-US style='letter-spacing:-.1pt'>s must add an extra step through a |
| utility class, named </span><span class=NB-NegritoTcnico2><b><font size=2 |
| color=black face="Verdana"><span lang=EN-US style='font-size:10.0pt; |
| letter-spacing:-.1pt'>Visualizer</span></font></b></span><span lang=EN-US |
| style='letter-spacing:-.1pt'>, to retrieve the </span><span |
| class=NB-NegritoTcnico2><b><font size=2 color=black face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt;letter-spacing:-.1pt'>Node</span></font></b></span><span |
| lang=EN-US style='letter-spacing:-.1pt'> associated to the current object to |
| render, as shown in <b><span style='font-weight:bold'>Listing 10</span></b> (the usual </span><span class=NB-NegritoTcnico2><b><font size=2 color=black |
| face="Verdana"><span lang=EN-US style='font-size:10.0pt;letter-spacing: |
| -.1pt'>JList</span></font></b></span><span lang=EN-US style='letter-spacing: |
| -.1pt'> approach, that is a cast applied to the </span><span |
| class=NB-NegritoTcnico2><b><font size=2 color=black face="Verdana"><span |
| lang=EN-US style='font-size:10.0pt;letter-spacing:-.1pt'>value</span></font></b></span><span |
| lang=EN-US style='letter-spacing:-.1pt'> parameter, would not work). </span><br> |
| </p> |
| <p class=NB-Interttulo3><b><font size=4 color="#0075a2" face="Verdana"><span |
| lang=EN-US style='font-size:13.0pt;line-height:120%'>Conclusions</span></font></b></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt;letter-spacing:0pt'>W</span></font><span lang=EN-US |
| style='letter-spacing:-.1pt'>ell, what can I say... blueMarine has survived its |
| crisis, and its open-source “advertising” has already brought me a business |
| opportunity for an application related to photo management (which reuses some |
| of the back-end components of blueMarine – track my blogs if you want to know |
| more about it). And without NetBeans, I would have dropped blueMarine and |
| missed this opportunity. </span></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt;letter-spacing:0pt'>What about blueMarine itself? When |
| this article is published, the project should be very close to the first |
| Release Candidate of its second life. Redesigning around the NetBeans Platform |
| required some time, of course. It’s likely that you’ll need to deeply redesign |
| an existing application if you want to take full advantage of all NetBeans |
| Platform features (even though you could choose a lower-impact, more |
| incremental way of working than I did). But I’m quite pleased with the results, |
| and now I can add new features much faster |
| than before. </span></font></p> |
| <p class=NB-Corpo3><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt;letter-spacing:0pt'>To me, this means that Swing and the |
| NetBeans Platform are now mature technologies for the desktop. I’m no longer |
| forced to waste time reinventing the wheel. On the contrary: I can move very |
| rapidly from an idea for my application, to an</span></font><font color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt;letter-spacing:0pt'> </span></font><font size=1 color=black face="Verdana"><span lang=EN-US |
| style='font-size:9.0pt;letter-spacing:0pt'> effective implementation</span></font>.</p> |
| <table width="100%" border="1" cellpadding="0" cellspacing="0" bordercolor="#0081C7"> |
| <tr> |
| <td bgcolor="#0081C7"><p class="NB-Listagenstitulos"><strong>Links</strong></p></td> |
| </tr> |
| <tr> |
| <td><br> |
| <table width="100%" border="0" cellspacing="0" cellpadding="0"> |
| <tr> |
| <td width="40"> </td> |
| <td><a href="http://bluemarine.tidalwave.it"><span class="style3"><font color="#0075a2" face="Verdana">bluemarine.tidalwave.it</font></span></a></td> |
| </tr> |
| <tr> |
| <td> </td> |
| <td><font size=1 color=black face="Verdana"><span style="font-size:9.0pt;letter-spacing:0pt">The blueMarine Project</span></font></td> |
| </tr> |
| </table> |
| <br> |
| <table width="100%" border="0" cellspacing="0" cellpadding="0"> |
| <tr> |
| <td width="40"> </td> |
| <td><a href="http://aerith.dev.java.net"><span class="style3"><font color="#0075a2" face="Verdana">aerith.dev.java.net</font></span></a></td> |
| </tr> |
| <tr> |
| <td> </td> |
| <td><span class="style1"><font color=black face="Verdana">Aerith</font></span></td> |
| </tr> |
| </table> |
| <br> |
| <table width="100%" border="0" cellspacing="0" cellpadding="0"> |
| <tr> |
| <td width="40"> </td> |
| <td><a href="http://blogs.sun.com/geertjan"><span class="style3"><font color="#0075a2" face="Verdana">blogs.sun.com/geertjan</font></span></a></td> |
| </tr> |
| <tr> |
| <td> </td> |
| <td><span class="style1"><font color=black face="Verdana">Geertjan Wielenga’s blog </font></span></td> |
| </tr> |
| </table> |
| <br> |
| <table width="100%" border="0" cellspacing="0" cellpadding="0"> |
| <tr> |
| <td width="40"> </td> |
| <td><a href="http://www.curious-creature.org"><span class="style3"><font color="#0075a2" face="Verdana">www.curious-creature.org</font></span></a></td> |
| </tr> |
| <tr> |
| <td> </td> |
| <td><span class="style1"><font color=black face="Verdana">Romain Guy’s blog</font></span></td> |
| </tr> |
| </table> |
| <br> |
| <table width="100%" border="0" cellspacing="0" cellpadding="0"> |
| <tr> |
| <td width="40"> </td> |
| <td><a href="http://jrawio.dev.java.net"><span class="style3"><font color="#0075a2" face="Verdana">jrawio.dev.java.net</font></span></a></td> |
| </tr> |
| <tr> |
| <td> </td> |
| <td><span class="style1"><font color=black face="Verdana">The jrawio Image I/O plugin for RAW file formats </font></span></td> |
| </tr> |
| </table> |
| <br> |
| <table width="100%" border="0" cellspacing="0" cellpadding="0"> |
| <tr> |
| <td width="40"> </td> |
| <td><a href="http://swinglabs.org"><span class="style3"><font color="#0075a2" face="Verdana">swinglabs.org</font></span></a></td> |
| </tr> |
| <tr> |
| <td> </td> |
| <td><span class="style1"><font color=black face="Verdana">SwingLabs</font></span></td> |
| </tr> |
| </table> |
| <br> |
| <table width="100%" border="0" cellspacing="0" cellpadding="0"> |
| <tr> |
| <td width="40"> </td> |
| <td><a href="http://substance.dev.java.net"><span class="style3"><font color="#0075a2" face="Verdana">substance.dev.java.net</font></span></a></td> |
| </tr> |
| <tr> |
| <td> </td> |
| <td><span class="style1"><font color=black face="Verdana">The Substance look and feel </font></span></td> |
| </tr> |
| </table> |
| <br> |
| <table width="100%" border="0" cellspacing="0" cellpadding="0"> |
| <tr> |
| <td width="40"> </td> |
| <td><a href="http://jai.dev.java.net"><span class="style3"><font color="#0075a2" face="Verdana">jai.dev.java.net</font></span></a></td> |
| </tr> |
| <tr> |
| <td> </td> |
| <td><span class="style1"><font color=black face="Verdana">JAI – Java Advanced Imaging</font></span></td> |
| </tr> |
| </table> |
| <br> |
| <table width="100%" border="0" cellspacing="0" cellpadding="0"> |
| <tr> |
| <td width="40"> </td> |
| <td><a href="https://netbeans.org/competition/look-and-feel.html"><span class="style3"><font color="#0075a2" face="Verdana">netbeans.org/competition/look-and-feel.html</font></span></a></td> |
| </tr> |
| <tr> |
| <td> </td> |
| <td><span class="style1"><font color=black face="Verdana">Look-and-feel examples with the NetBeans IDE </font></span></td> |
| </tr> |
| </table> |
| <br> |
| <table width="100%" border="0" cellspacing="0" cellpadding="0"> |
| <tr> |
| <td width="40"> </td> |
| <td><a href="http://weblogs.java.net/blog/joshy"><span class="style3"><font color="#0075a2" face="Verdana">weblogs.java.net/blog/joshy</font></span></a></td> |
| </tr> |
| <tr> |
| <td> </td> |
| <td><span class="style1"><font color=black face="Verdana">Joshua Marinacci’s blog </font></span></td> |
| </tr> |
| </table> |
| <br> |
| <table width="100%" border="0" cellspacing="0" cellpadding="0"> |
| <tr> |
| <td width="40"> </td> |
| <td><a href="http://weblogs.java.net/blog/fabriziogiudici"><span class="style3"><font color="#0075a2" face="Verdana">weblogs.java.net/blog/fabriziogiudici<br> |
| </font></span></a><!-- <a href="http://www.tidalwave.it/blog"><span class="style3"><font color="#0075a2" face="Verdana">www.tidalwave.it/blog</font></span></a>--></td> |
| </tr> |
| <tr> |
| <td> </td> |
| <td><span class="style1"><font color=black face="Verdana">The author’s blogs </font></span></td> |
| </tr> |
| </table> |
| <br> |
| <table width="100%" border="0" cellspacing="0" cellpadding="0"> |
| <tr> |
| <td width="40"> </td> |
| <td><a href="http://quaqua.dev.java.net"><span class="style3"><font color="#0075a2" face="Verdana">quaqua.dev.java.net</font></span></a><!-- <a href="http://www.tidalwave.it/blog"></a>--></td> |
| </tr> |
| <tr> |
| <td> </td> |
| <td><span class="style1"><font color=black face="Verdana">The Quaqua look and feel </font></span></td> |
| </tr> |
| </table> |
| <br> |
| </tr> |
| </table> |
| <br> |
| <table width="100%" border="1" cellpadding="0" cellspacing="0" bordercolor="#0081C7"> |
| <tr> |
| <td><table width="100%" border="0" cellspacing="0" cellpadding="0"> |
| <tr> |
| <td width="93"><div align="center"><img src="/images_www/magazine/autores/Fabrizio_Giudici.jpg" alt="Autor" width="80" height="94"></div></td> |
| <td width="677"><p class=NB-Corpo1111><strong>Fabrizio Giudici</strong><br> |
| (<em>fabrizio.giudici@tidalwave.it</em>) has a Ph.D. in Computer Engineering from the University of Genoa (1998), and begun his career as a freelance technical writer and speaker. He started up a consultancy company with two friends and since 2005 is running his own company. Fabrizio has been architect, designer and developer in many industrial projects, including a Jini-based real-time telemetry system for Formula One racing cars. He’s a member of the NetBeans Dream Team, the IEEE and JUG Milano.<br> |
| </p></td> |
| </tr> |
| </table></td> |
| </tr> |
| </table></td> |
| </tr> |
| </table> |
| </body> |
| </html> |