Clover coverage report - Code Coverage for tapestry-contrib release 4.0-alpha-3
Coverage timestamp: Mon May 16 2005 09:12:41 EDT
file stats: LOC: 483   Methods: 10
NCLOC: 187   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
Palette.java 0% 0% 0% 0%
coverage
 1   
 // Copyright 2004, 2005 The Apache Software Foundation
 2   
 //
 3   
 // Licensed under the Apache License, Version 2.0 (the "License");
 4   
 // you may not use this file except in compliance with the License.
 5   
 // You may obtain a copy of the License at
 6   
 //
 7   
 //     http://www.apache.org/licenses/LICENSE-2.0
 8   
 //
 9   
 // Unless required by applicable law or agreed to in writing, software
 10   
 // distributed under the License is distributed on an "AS IS" BASIS,
 11   
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12   
 // See the License for the specific language governing permissions and
 13   
 // limitations under the License.
 14   
 
 15   
 package org.apache.tapestry.contrib.palette;
 16   
 
 17   
 import java.util.ArrayList;
 18   
 import java.util.Collections;
 19   
 import java.util.HashMap;
 20   
 import java.util.Iterator;
 21   
 import java.util.List;
 22   
 import java.util.Map;
 23   
 
 24   
 import org.apache.tapestry.BaseComponent;
 25   
 import org.apache.tapestry.IAsset;
 26   
 import org.apache.tapestry.IForm;
 27   
 import org.apache.tapestry.IMarkupWriter;
 28   
 import org.apache.tapestry.IRequestCycle;
 29   
 import org.apache.tapestry.IScript;
 30   
 import org.apache.tapestry.PageRenderSupport;
 31   
 import org.apache.tapestry.Tapestry;
 32   
 import org.apache.tapestry.TapestryUtils;
 33   
 import org.apache.tapestry.components.Block;
 34   
 import org.apache.tapestry.form.FormEventType;
 35   
 import org.apache.tapestry.form.IFormComponent;
 36   
 import org.apache.tapestry.form.IPropertySelectionModel;
 37   
 import org.apache.tapestry.valid.IValidationDelegate;
 38   
 
 39   
 /**
 40   
  * A component used to make a number of selections from a list. The general look is a pair of
 41   
  * <select> elements. with a pair of buttons between them. The right element is a list of
 42   
  * values that can be selected. The buttons move values from the right column ("available") to the
 43   
  * left column ("selected").
 44   
  * <p>
 45   
  * This all takes a bit of JavaScript to accomplish (quite a bit), which means a {@link Body}
 46   
  * component must wrap the Palette. If JavaScript is not enabled in the client browser, then the
 47   
  * user will be unable to make (or change) any selections.
 48   
  * <p>
 49   
  * Cross-browser compatibility is not perfect. In some cases, the
 50   
  * {@link org.apache.tapestry.contrib.form.MultiplePropertySelection}component may be a better
 51   
  * choice.
 52   
  * <p>
 53   
  * <table border=1>
 54   
  * <tr>
 55   
  * <td>Parameter</td>
 56   
  * <td>Type</td>
 57   
  * <td>Direction</td>
 58   
  * <td>Required</td>
 59   
  * <td>Default</td>
 60   
  * <td>Description</td>
 61   
  * </tr>
 62   
  * <tr>
 63   
  * <td>selected</td>
 64   
  * <td>{@link List}</td>
 65   
  * <td>in</td>
 66   
  * <td>yes</td>
 67   
  * <td>&nbsp;</td>
 68   
  * <td>A List of selected values. Possible selections are defined by the model; this should be a
 69   
  * subset of the possible values. This may be null when the component is renderred. When the
 70   
  * containing form is submitted, this parameter is updated with a new List of selected objects.
 71   
  * <p>
 72   
  * The order may be set by the user, as well, depending on the sortMode parameter.</td>
 73   
  * </tr>
 74   
  * <tr>
 75   
  * <td>model</td>
 76   
  * <td>{@link IPropertySelectionModel}</td>
 77   
  * <td>in</td>
 78   
  * <td>yes</td>
 79   
  * <td>&nbsp;</td>
 80   
  * <td>Works, as with a {@link org.apache.tapestry.form.PropertySelection}component, to define the
 81   
  * possible values.</td>
 82   
  * </tr>
 83   
  * <tr>
 84   
  * <td>sort</td>
 85   
  * <td>{@link SortMode}</td>
 86   
  * <td>in</td>
 87   
  * <td>no</td>
 88   
  * <td>{@link SortMode#NONE}</td>
 89   
  * <td>Controls automatic sorting of the options.</td>
 90   
  * </tr>
 91   
  * <tr>
 92   
  * <td>rows</td>
 93   
  * <td>int</td>
 94   
  * <td>in</td>
 95   
  * <td>no</td>
 96   
  * <td>10</td>
 97   
  * <td>The number of rows that should be visible in the Pallete's &lt;select&gt; elements.</td>
 98   
  * </tr>
 99   
  * <tr>
 100   
  * <td>tableClass</td>
 101   
  * <td>{@link String}</td>
 102   
  * <td>in</td>
 103   
  * <td>no</td>
 104   
  * <td>tapestry-palette</td>
 105   
  * <td>The CSS class for the table which surrounds the other elements of the Palette.</td>
 106   
  * </tr>
 107   
  * <tr>
 108   
  * <td>selectedTitleBlock</td>
 109   
  * <td>{@link Block}</td>
 110   
  * <td>in</td>
 111   
  * <td>no</td>
 112   
  * <td>"Selected"</td>
 113   
  * <td>If specified, allows a {@link Block}to be placed within the &lt;th&gt; reserved for the
 114   
  * title above the selected items &lt;select&gt; (on the right). This allows for images or other
 115   
  * components to be placed there. By default, the simple word <code>Selected</code> is used.</td>
 116   
  * </tr>
 117   
  * <tr>
 118   
  * <td>availableTitleBlock</td>
 119   
  * <td>{@link Block}</td>
 120   
  * <td>in</td>
 121   
  * <td>no</td>
 122   
  * <td>"Available"</td>
 123   
  * <td>As with selectedTitleBlock, but for the left column, of items which are available to be
 124   
  * selected. The default is the word <code>Available</code>.</td>
 125   
  * </tr>
 126   
  * <tr>
 127   
  * <td>selectImage <br>
 128   
  * selectDisabledImage <br>
 129   
  * deselectImage <br>
 130   
  * deselectDisabledImage <br>
 131   
  * upImage <br>
 132   
  * upDisabledImage <br>
 133   
  * downImage <br>
 134   
  * downDisabledImage</td>
 135   
  * <td>{@link IAsset}</td>
 136   
  * <td>in</td>
 137   
  * <td>no</td>
 138   
  * <td>&nbsp;</td>
 139   
  * <td>If any of these are specified then they override the default images provided with the
 140   
  * component. This allows the look and feel to be customized relatively easily.
 141   
  * <p>
 142   
  * The most common reason to replace the images is to deal with backgrounds. The default images are
 143   
  * anti-aliased against a white background. If a colored or patterned background is used, the
 144   
  * default images will have an ugly white fringe. Until all browsers have full support for PNG
 145   
  * (which has a true alpha channel), it is necessary to customize the images to match the
 146   
  * background.</td>
 147   
  * </tr>
 148   
  * </table>
 149   
  * <p>
 150   
  * A Palette requires some CSS entries to render correctly ... especially the middle column, which
 151   
  * contains the two or four buttons for moving selections between the two columns. The width and
 152   
  * alignment of this column must be set using CSS. Additionally, CSS is commonly used to give the
 153   
  * Palette columns a fixed width, and to dress up the titles. Here is an example of some CSS you can
 154   
  * use to format the palette component:
 155   
  * 
 156   
  * <pre>
 157   
  *                 TABLE.tapestry-palette TH
 158   
  *                 {
 159   
  *                   font-size: 9pt;
 160   
  *                   font-weight: bold;
 161   
  *                   color: white;
 162   
  *                   background-color: #330066;
 163   
  *                   text-align: center;
 164   
  *                 }
 165   
  *                
 166   
  *                 TD.available-cell SELECT
 167   
  *                 {
 168   
  *                   font-weight: normal;
 169   
  *                   background-color: #FFFFFF;
 170   
  *                   width: 200px;
 171   
  *                 }
 172   
  *                 
 173   
  *                 TD.selected-cell SELECT
 174   
  *                 {
 175   
  *                   font-weight: normal;
 176   
  *                   background-color: #FFFFFF;
 177   
  *                   width: 200px;
 178   
  *                 }
 179   
  *                 
 180   
  *                 TABLE.tapestry-palette TD.controls
 181   
  *                 {
 182   
  *                   text-align: center;
 183   
  *                   vertical-align: middle;
 184   
  *                   width: 60px;
 185   
  *                 }
 186   
  * </pre>
 187   
  * 
 188   
  * @author Howard Lewis Ship
 189   
  */
 190   
 
 191   
 public abstract class Palette extends BaseComponent implements IFormComponent
 192   
 {
 193   
     private static final int MAP_SIZE = 7;
 194   
 
 195   
     /**
 196   
      * A set of symbols produced by the Palette script. This is used to provide proper names for
 197   
      * some of the HTML elements (&lt;select&gt; and &lt;button&gt; elements, etc.).
 198   
      */
 199   
 
 200   
     private Map _symbols;
 201   
 
 202   
     /** @since 3.0 * */
 203   
     public abstract void setAvailableColumn(PaletteColumn column);
 204   
 
 205   
     /** @since 3.0 * */
 206   
     public abstract void setSelectedColumn(PaletteColumn column);
 207   
 
 208   
     public abstract String getName();
 209   
 
 210   
     public abstract void setName(String name);
 211   
 
 212   
     public abstract IForm getForm();
 213   
 
 214   
     public abstract void setForm(IForm form);
 215   
 
 216  0
     protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
 217   
     {
 218  0
         IForm form = TapestryUtils.getForm(cycle, this);
 219   
 
 220  0
         if (form.wasPrerendered(writer, this))
 221  0
             return;
 222   
 
 223  0
         setForm(form);
 224   
 
 225  0
         IValidationDelegate delegate = form.getDelegate();
 226   
 
 227  0
         delegate.setFormComponent(this);
 228   
 
 229  0
         setName(form.getElementId(this));
 230   
 
 231  0
         if (form.isRewinding())
 232  0
             handleSubmission(cycle);
 233   
 
 234   
         // Don't do any additional work if rewinding
 235   
         // (some other action or form on the page).
 236   
 
 237  0
         if (!cycle.isRewinding())
 238   
         {
 239   
             // Lots of work to produce JavaScript and HTML for this sucker.
 240   
 
 241  0
             _symbols = new HashMap(MAP_SIZE);
 242   
 
 243  0
             runScript(cycle);
 244   
 
 245   
             // Output symbol 'formSubmitFunctionName' is the name
 246   
             // of a JavaScript function to execute when the form
 247   
             // is submitted. This is also key to the operation
 248   
             // of the PropertySelection.
 249   
 
 250  0
             form.addEventHandler(FormEventType.SUBMIT, (String) _symbols
 251   
                     .get("formSubmitFunctionName"));
 252   
 
 253  0
             constructColumns();
 254   
         }
 255   
 
 256  0
         super.renderComponent(writer, cycle);
 257   
     }
 258   
 
 259  0
     protected void cleanupAfterRender(IRequestCycle cycle)
 260   
     {
 261  0
         _symbols = null;
 262   
 
 263  0
         setAvailableColumn(null);
 264  0
         setSelectedColumn(null);
 265   
 
 266  0
         super.cleanupAfterRender(cycle);
 267   
     }
 268   
 
 269   
     /**
 270   
      * Executes the associated script, which generates all the JavaScript to support this Palette.
 271   
      */
 272  0
     private void runScript(IRequestCycle cycle)
 273   
     {
 274  0
         PageRenderSupport pageRenderSupport = TapestryUtils.getPageRenderSupport(cycle, this);
 275   
 
 276  0
         setImage(pageRenderSupport, cycle, "selectImage", getSelectImage());
 277  0
         setImage(pageRenderSupport, cycle, "selectDisabledImage", getSelectDisabledImage());
 278  0
         setImage(pageRenderSupport, cycle, "deselectImage", getDeselectImage());
 279  0
         setImage(pageRenderSupport, cycle, "deselectDisabledImage", getDeselectDisabledImage());
 280   
 
 281  0
         if (isSortUser())
 282   
         {
 283  0
             setImage(pageRenderSupport, cycle, "upImage", getUpImage());
 284  0
             setImage(pageRenderSupport, cycle, "upDisabledImage", getUpDisabledImage());
 285  0
             setImage(pageRenderSupport, cycle, "downImage", getDownImage());
 286  0
             setImage(pageRenderSupport, cycle, "downDisabledImage", getDownDisabledImage());
 287   
         }
 288   
 
 289  0
         _symbols.put("palette", this);
 290   
 
 291  0
         getScript().execute(cycle, pageRenderSupport, _symbols);
 292   
     }
 293   
 
 294   
     /**
 295   
      * Extracts its asset URL, sets it up for preloading, and assigns the preload reference as a
 296   
      * script symbol.
 297   
      */
 298  0
     private void setImage(PageRenderSupport pageRenderSupport, IRequestCycle cycle,
 299   
             String symbolName, IAsset asset)
 300   
     {
 301  0
         String URL = asset.buildURL(cycle);
 302  0
         String reference = pageRenderSupport.getPreloadedImageReference(URL);
 303   
 
 304  0
         _symbols.put(symbolName, reference);
 305   
     }
 306   
 
 307  0
     public Map getSymbols()
 308   
     {
 309  0
         return _symbols;
 310   
     }
 311   
 
 312   
     /**
 313   
      * Constructs a pair of {@link PaletteColumn}s: the available and selected options.
 314   
      */
 315  0
     private void constructColumns()
 316   
     {
 317   
         // Build a Set around the list of selected items.
 318   
 
 319  0
         List selected = getSelected();
 320   
 
 321  0
         if (selected == null)
 322  0
             selected = Collections.EMPTY_LIST;
 323   
 
 324  0
         SortMode sortMode = getSort();
 325   
 
 326  0
         boolean sortUser = sortMode == SortMode.USER;
 327   
 
 328  0
         List selectedOptions = null;
 329   
 
 330  0
         if (sortUser)
 331   
         {
 332  0
             int count = selected.size();
 333  0
             selectedOptions = new ArrayList(count);
 334   
 
 335  0
             for (int i = 0; i < count; i++)
 336  0
                 selectedOptions.add(null);
 337   
         }
 338   
 
 339  0
         PaletteColumn availableColumn = new PaletteColumn((String) _symbols.get("availableName"),
 340   
                 getRows());
 341  0
         PaletteColumn selectedColumn = new PaletteColumn(getName(), getRows());
 342   
 
 343   
         // Each value specified in the model will go into either the selected or available
 344   
         // lists.
 345   
 
 346  0
         IPropertySelectionModel model = getModel();
 347   
 
 348  0
         int count = model.getOptionCount();
 349   
 
 350  0
         for (int i = 0; i < count; i++)
 351   
         {
 352  0
             Object optionValue = model.getOption(i);
 353   
 
 354  0
             PaletteOption o = new PaletteOption(model.getValue(i), model.getLabel(i));
 355   
 
 356  0
             int index = selected.indexOf(optionValue);
 357  0
             boolean isSelected = index >= 0;
 358   
 
 359  0
             if (sortUser && isSelected)
 360   
             {
 361  0
                 selectedOptions.set(index, o);
 362  0
                 continue;
 363   
             }
 364   
 
 365  0
             PaletteColumn c = isSelected ? selectedColumn : availableColumn;
 366   
 
 367  0
             c.addOption(o);
 368   
         }
 369   
 
 370  0
         if (sortUser)
 371   
         {
 372  0
             Iterator i = selectedOptions.iterator();
 373  0
             while (i.hasNext())
 374   
             {
 375  0
                 PaletteOption o = (PaletteOption) i.next();
 376  0
                 selectedColumn.addOption(o);
 377   
             }
 378   
         }
 379   
 
 380  0
         if (sortMode == SortMode.VALUE)
 381   
         {
 382  0
             availableColumn.sortByValue();
 383  0
             selectedColumn.sortByValue();
 384   
         }
 385  0
         else if (sortMode == SortMode.LABEL)
 386   
         {
 387  0
             availableColumn.sortByLabel();
 388  0
             selectedColumn.sortByLabel();
 389   
         }
 390   
 
 391  0
         setAvailableColumn(availableColumn);
 392  0
         setSelectedColumn(selectedColumn);
 393   
     }
 394   
 
 395  0
     private void handleSubmission(IRequestCycle cycle)
 396   
     {
 397  0
         String[] values = cycle.getParameters(getName());
 398   
 
 399  0
         int count = Tapestry.size(values);
 400   
 
 401  0
         if (count == 0)
 402  0
             return;
 403   
 
 404  0
         List selected = new ArrayList(count);
 405  0
         IPropertySelectionModel model = getModel();
 406   
 
 407  0
         for (int i = 0; i < count; i++)
 408   
         {
 409  0
             String value = values[i];
 410  0
             Object option = model.translateValue(value);
 411   
 
 412  0
             selected.add(option);
 413   
         }
 414   
 
 415  0
         setSelected(selected);
 416   
     }
 417   
 
 418  0
     public boolean isSortUser()
 419   
     {
 420  0
         return getSort() == SortMode.USER;
 421   
     }
 422   
 
 423   
     /**
 424   
      * Returns null, but may make sense to implement a displayName parameter.
 425   
      */
 426  0
     public String getDisplayName()
 427   
     {
 428  0
         return null;
 429   
     }
 430   
 
 431   
     public abstract Block getAvailableTitleBlock();
 432   
 
 433   
     public abstract IAsset getDeselectDisabledImage();
 434   
 
 435   
     public abstract IAsset getDeselectImage();
 436   
 
 437   
     public abstract IAsset getDownDisabledImage();
 438   
 
 439   
     public abstract IAsset getDownImage();
 440   
 
 441   
     public abstract IAsset getSelectDisabledImage();
 442   
 
 443   
     public abstract IPropertySelectionModel getModel();
 444   
 
 445   
     public abstract int getRows();
 446   
 
 447   
     public abstract Block getSelectedTitleBlock();
 448   
 
 449   
     public abstract IAsset getSelectImage();
 450   
 
 451   
     public abstract SortMode getSort();
 452   
 
 453   
     public abstract IAsset getUpDisabledImage();
 454   
 
 455   
     public abstract IAsset getUpImage();
 456   
 
 457   
     /**
 458   
      * Returns false. Palette components are never disabled.
 459   
      * 
 460   
      * @since 2.2
 461   
      */
 462   
 
 463  0
     public boolean isDisabled()
 464   
     {
 465  0
         return false;
 466   
     }
 467   
 
 468   
     /** @since 2.2 * */
 469   
 
 470   
     public abstract List getSelected();
 471   
 
 472   
     /** @since 2.2 * */
 473   
 
 474   
     public abstract void setSelected(List selected);
 475   
 
 476   
     /**
 477   
      * Injected.
 478   
      * 
 479   
      * @since 4.0
 480   
      */
 481   
 
 482   
     public abstract IScript getScript();
 483   
 }