| 87 | | setMainWindow(new MainWindow()); |
| 88 | | } |
| 89 | | |
| 90 | | private class MainWindow extends Window { |
| 91 | | |
| 92 | | MainWindow() { |
| 93 | | allFeatures = (Container.Ordered) features.getContainer(true); |
| 94 | | |
| 95 | | ExpandLayout main = new ExpandLayout(); |
| 96 | | setLayout(main); |
| 97 | | main.setSizeFull(); |
| 98 | | |
| | 92 | setMainWindow(new SamplerWindow()); |
| | 93 | } |
| | 94 | |
| | 95 | // Supports multiple browser windows |
| | 96 | public Window getWindow(String name) { |
| | 97 | Window w = super.getWindow(name); |
| | 98 | if (w == null) { |
| | 99 | w = new SamplerWindow(); |
| | 100 | w.setName(name); |
| | 101 | addWindow(w); |
| | 102 | // secondary windows will support normal reload if this is |
| | 103 | // enabled, but the url gets ugly: |
| | 104 | // w.open(new ExternalResource(w.getURL())); |
| | 105 | |
| | 106 | } |
| | 107 | return w; |
| | 108 | } |
| | 109 | |
| | 110 | /** |
| | 111 | * Gets absolute path for given Feature |
| | 112 | * |
| | 113 | * @param f |
| | 114 | * the Feature whose path to get, of null if not found |
| | 115 | * @return the path of the Feature |
| | 116 | */ |
| | 117 | String getPathFor(Feature f) { |
| | 118 | if (allFeatures.containsId(f)) { |
| | 119 | String path = f.getPathName(); |
| | 120 | f = (Feature) allFeatures.getParent(f); |
| | 121 | while (f != null) { |
| | 122 | path = f.getPathName() + "/" + path; |
| | 123 | } |
| | 124 | return path; |
| | 125 | } |
| | 126 | return null; |
| | 127 | } |
| | 128 | |
| | 129 | /** |
| | 130 | * The main window for Sampler, contains the full application UI. |
| | 131 | * |
| | 132 | */ |
| | 133 | private class SamplerWindow extends Window { |
| | 134 | private FeatureList currentList = new FeatureGrid(); |
| | 135 | private FeatureView featureView = new FeatureView(); |
| | 136 | private Property currentFeature = new ObjectProperty(null, |
| | 137 | Feature.class); |
| | 138 | |
| | 139 | private MainArea mainArea = new MainArea(); |
| | 140 | |
| | 141 | SamplerWindow() { |
| | 142 | // Main top/expanded-bottom layout |
| | 143 | ExpandLayout mainExpand = new ExpandLayout(); |
| | 144 | setLayout(mainExpand); |
| | 145 | mainExpand.setSizeFull(); |
| | 146 | |
| | 147 | // topbar (navigation) |
| 106 | | split = new SplitPanel(SplitPanel.ORIENTATION_HORIZONTAL); |
| | 155 | // Upper left logo |
| | 156 | Component logo = createLogo(); |
| | 157 | nav.addComponent(logo); |
| | 158 | nav.setComponentAlignment(logo, ExpandLayout.ALIGNMENT_LEFT, |
| | 159 | ExpandLayout.ALIGNMENT_VERTICAL_CENTER); |
| | 160 | nav.expand(logo); |
| | 161 | |
| | 162 | // Previous sample |
| | 163 | Button b = createPrevButton(); |
| | 164 | nav.addComponent(b); |
| | 165 | nav.setComponentAlignment(b, ExpandLayout.ALIGNMENT_LEFT, |
| | 166 | ExpandLayout.ALIGNMENT_VERTICAL_CENTER); |
| | 167 | // Next sample |
| | 168 | b = createNextButton(); |
| | 169 | nav.addComponent(b); |
| | 170 | nav.setComponentAlignment(b, ExpandLayout.ALIGNMENT_LEFT, |
| | 171 | ExpandLayout.ALIGNMENT_VERTICAL_CENTER); |
| | 172 | |
| | 173 | // Main left/right split; hidden menu tree |
| | 174 | SplitPanel split = new SplitPanel(SplitPanel.ORIENTATION_HORIZONTAL); |
| 109 | | main.addComponent(split); |
| 110 | | main.expand(split); |
| 111 | | |
| | 177 | mainExpand.addComponent(split); |
| | 178 | mainExpand.expand(split); |
| | 179 | |
| | 180 | // Menu tree, initially hidden |
| | 181 | Tree tree = createMenuTree(); |
| | 182 | split.addComponent(tree); |
| | 183 | |
| | 184 | // Main Area |
| | 185 | split.addComponent(mainArea); |
| | 186 | |
| | 187 | // List/grid/coverflow |
| | 188 | Component mode = createModeSwitch(); |
| | 189 | nav.addComponent(mode); |
| | 190 | nav.setComponentAlignment(mode, ExpandLayout.ALIGNMENT_RIGHT, |
| | 191 | ExpandLayout.ALIGNMENT_VERTICAL_CENTER); |
| | 192 | |
| | 193 | } |
| | 194 | |
| | 195 | /** |
| | 196 | * Displays a Feature(Set) |
| | 197 | * |
| | 198 | * @param f |
| | 199 | * the Feature(Set) to show |
| | 200 | */ |
| | 201 | public void setFeature(Feature f) { |
| | 202 | currentFeature.setValue(f); |
| | 203 | } |
| | 204 | |
| | 205 | /** |
| | 206 | * Displays a Feature(Set) matching the given path, or the main view if |
| | 207 | * no matching Feature(Set) is found. |
| | 208 | * |
| | 209 | * @param path |
| | 210 | * the path of the Feature(Set) to show |
| | 211 | */ |
| | 212 | public void setFeature(String path) { |
| | 213 | Feature f = features.getFeatureByPath(path); |
| | 214 | setFeature(f); |
| | 215 | } |
| | 216 | |
| | 217 | // Handle REST -style urls |
| | 218 | public DownloadStream handleURI(URL context, String relativeUri) { |
| | 219 | Feature f = features.getFeatureByPath(relativeUri); |
| | 220 | if (f != null) { |
| | 221 | setFeature(f); |
| | 222 | open(new ExternalResource(context)); |
| | 223 | } |
| | 224 | return super.handleURI(context, relativeUri); |
| | 225 | } |
| | 226 | |
| | 227 | /* |
| | 228 | * SamplerWindow helpers |
| | 229 | */ |
| | 230 | |
| | 231 | private Component createLogo() { |
| 121 | | nav.addComponent(logo); |
| 122 | | nav.setComponentAlignment(logo, ExpandLayout.ALIGNMENT_LEFT, |
| 123 | | ExpandLayout.ALIGNMENT_VERTICAL_CENTER); |
| 124 | | |
| 125 | | Button b = new Button("< Previous", new ClickListener() { |
| | 241 | return logo; |
| | 242 | } |
| | 243 | |
| | 244 | private Button createNextButton() { |
| | 245 | Button b = new Button("Next sample â", new ClickListener() { |
| | 246 | public void buttonClick(ClickEvent event) { |
| | 247 | Object curr = currentFeature.getValue(); |
| | 248 | Object next = allFeatures.nextItemId(curr); |
| | 249 | while (next != null && next instanceof FeatureSet) { |
| | 250 | next = allFeatures.nextItemId(next); |
| | 251 | } |
| | 252 | currentFeature.setValue(next); |
| | 253 | } |
| | 254 | }); |
| | 255 | b.setStyleName(Button.STYLE_LINK); |
| | 256 | return b; |
| | 257 | } |
| | 258 | |
| | 259 | private Button createPrevButton() { |
| | 260 | Button b = new Button("â Previous sample", new ClickListener() { |
| 133 | | |
| 134 | | } |
| 135 | | }); |
| 136 | | nav.addComponent(b); |
| 137 | | nav.setComponentAlignment(b, ExpandLayout.ALIGNMENT_LEFT, |
| 138 | | ExpandLayout.ALIGNMENT_VERTICAL_CENTER); |
| 139 | | |
| 140 | | b = new Button("Next >", new ClickListener() { |
| 141 | | public void buttonClick(ClickEvent event) { |
| 142 | | Object curr = currentFeature.getValue(); |
| 143 | | Object next = allFeatures.nextItemId(curr); |
| 144 | | while (next != null && next instanceof FeatureSet) { |
| 145 | | next = allFeatures.nextItemId(next); |
| | 268 | } |
| | 269 | }); |
| | 270 | b.setStyleName(Button.STYLE_LINK); |
| | 271 | return b; |
| | 272 | } |
| | 273 | |
| | 274 | private Component createModeSwitch() { |
| | 275 | ModeSwitch m = new ModeSwitch(); |
| | 276 | m.addMode(currentList, "", "View as Icons", new ThemeResource( |
| | 277 | "sampler/grid.gif")); |
| | 278 | m.addMode(new FeatureGrid(), "", "View as Icons", |
| | 279 | new ThemeResource("sampler/flow.gif")); |
| | 280 | m.addMode(new FeatureTable(), "", "View as List", |
| | 281 | new ThemeResource("sampler/list.gif")); |
| | 282 | m.addListener(new ModeSwitch.ModeSwitchListener() { |
| | 283 | public void componentEvent(Event event) { |
| | 284 | if (event instanceof ModeSwitchEvent) { |
| | 285 | updateFeatureList((FeatureList) ((ModeSwitchEvent) event) |
| | 286 | .getMode()); |
| 147 | | currentFeature.setValue(next); |
| 148 | | |
| 149 | | } |
| 150 | | }); |
| 151 | | nav.addComponent(b); |
| 152 | | nav.setComponentAlignment(b, ExpandLayout.ALIGNMENT_LEFT, |
| 153 | | ExpandLayout.ALIGNMENT_VERTICAL_CENTER); |
| 154 | | |
| 155 | | b = new Button(":: | \\â¡/ | â£"); |
| 156 | | nav.addComponent(b); |
| 157 | | nav.expand(b); |
| 158 | | nav.setComponentAlignment(b, ExpandLayout.ALIGNMENT_RIGHT, |
| 159 | | ExpandLayout.ALIGNMENT_VERTICAL_CENTER); |
| 160 | | |
| | 288 | } |
| | 289 | }); |
| | 290 | m.setMode(currentList); |
| | 291 | return m; |
| | 292 | } |
| | 293 | |
| | 294 | private Tree createMenuTree() { |
| 172 | | Feature val = (Feature) event.getProperty().getValue(); |
| 173 | | if (val == null) { |
| 174 | | currentList.setFeatureContainer(features |
| 175 | | .getContainer(true)); |
| 176 | | if (currentList.getParent() != split) { |
| 177 | | split.replaceComponent(featureView, currentList); |
| 178 | | } |
| 179 | | |
| 180 | | } else if (val instanceof FeatureSet) { |
| 181 | | currentList.setFeatureContainer(((FeatureSet) val) |
| 182 | | .getContainer(false)); |
| 183 | | if (currentList.getParent() != split) { |
| 184 | | split.replaceComponent(featureView, currentList); |
| 185 | | } |
| 186 | | } else { |
| 187 | | if (featureView.getParent() != split) { |
| 188 | | split.replaceComponent(currentList, featureView); |
| 189 | | } |
| 190 | | featureView.setFeature(val); |
| 191 | | } |
| 192 | | } |
| 193 | | }); |
| 194 | | |
| 195 | | FeatureTable tbl = new FeatureTable(); |
| 196 | | tbl.setFeatureContainer(allFeatures); |
| 197 | | currentList = tbl; |
| 198 | | |
| 199 | | split.addComponent(tbl); |
| 200 | | |
| 201 | | featureView = new FeatureView(); |
| 202 | | |
| 203 | | Feature f = features.getFeatureByPath("Components/c/DummyFeature"); |
| 204 | | tree.setValue(f); |
| 205 | | } |
| 206 | | } |
| 207 | | |
| | 305 | updateFeatureList(currentList); |
| | 306 | } |
| | 307 | }); |
| | 308 | return tree; |
| | 309 | } |
| | 310 | |
| | 311 | private void updateFeatureList(FeatureList list) { |
| | 312 | currentList = list; |
| | 313 | Feature val = (Feature) currentFeature.getValue(); |
| | 314 | if (val == null) { |
| | 315 | currentList.setFeatureContainer(allFeatures); |
| | 316 | mainArea.show(currentList); |
| | 317 | } else if (val instanceof FeatureSet) { |
| | 318 | currentList.setFeatureContainer(((FeatureSet) val) |
| | 319 | .getContainer(true)); |
| | 320 | mainArea.show(currentList); |
| | 321 | } else { |
| | 322 | mainArea.show(featureView); |
| | 323 | featureView.setFeature(val); |
| | 324 | } |
| | 325 | |
| | 326 | } |
| | 327 | |
| | 328 | } |
| | 329 | |
| | 330 | /** |
| | 331 | * Main area used to show Feature of FeatureList. In effect a one-component |
| | 332 | * container, to minimize repaints. |
| | 333 | */ |
| | 334 | private class MainArea extends CustomComponent { |
| | 335 | MainArea() { |
| | 336 | setSizeFull(); |
| | 337 | setCompositionRoot(new Label()); |
| | 338 | } |
| | 339 | |
| | 340 | public void show(Component c) { |
| | 341 | if (getCompositionRoot() != c) { |
| | 342 | setCompositionRoot(c); |
| | 343 | } |
| | 344 | } |
| | 345 | } |
| | 346 | |
| | 347 | /** |
| | 348 | * Components capable of listing Features should implement this. |
| | 349 | * |
| | 350 | */ |
| | 351 | interface FeatureList extends Component { |
| | 352 | /** |
| | 353 | * Shows the given Features |
| | 354 | * |
| | 355 | * @param c |
| | 356 | * Container with Features to show. |
| | 357 | */ |
| | 358 | public void setFeatureContainer(HierarchicalContainer c); |
| | 359 | } |
| | 360 | |
| | 361 | /** |
| | 362 | * Table -mode FeatureList. Displays the features in a Table. |
| | 363 | */ |
| | 416 | private class FeatureGrid extends GridLayout implements FeatureList { |
| | 417 | |
| | 418 | FeatureGrid() { |
| | 419 | super(5, 1); |
| | 420 | setWidth("100%"); |
| | 421 | } |
| | 422 | |
| | 423 | private void newRow() { |
| | 424 | while (getCursorX() > 0) { |
| | 425 | space(); |
| | 426 | } |
| | 427 | } |
| | 428 | |
| | 429 | @Override |
| | 430 | public void setFeatureContainer(HierarchicalContainer c) { |
| | 431 | removeAllComponents(); |
| | 432 | Collection features = c.getItemIds(); |
| | 433 | for (Iterator it = features.iterator(); it.hasNext();) { |
| | 434 | final Feature f = (Feature) it.next(); |
| | 435 | if (f instanceof FeatureSet) { |
| | 436 | newRow(); |
| | 437 | addComponent(new Label(f.getName())); |
| | 438 | if (c.isRoot(f)) { |
| | 439 | newRow(); |
| | 440 | } |
| | 441 | } else { |
| | 442 | Button b = new Button(); |
| | 443 | b.setWidth("130px"); |
| | 444 | b.setHeight("130px"); |
| | 445 | b.setSizeFull(); |
| | 446 | b.setStyleName(Button.STYLE_LINK); |
| | 447 | b.setIcon(new ClassResource(f.getClass(), f.getIconName(), |
| | 448 | SamplerApplication.this)); |
| | 449 | b.setDescription("<h3>" + f.getName() + "</h3>" |
| | 450 | + f.getDescription()); |
| | 451 | b.addListener(new Button.ClickListener() { |
| | 452 | public void buttonClick(ClickEvent event) { |
| | 453 | ((SamplerWindow) getWindow()).setFeature(f); |
| | 454 | } |
| | 455 | }); |
| | 456 | addComponent(b); |
| | 457 | } |
| | 458 | } |
| | 459 | } |
| | 460 | } |
| | 461 | |
| | 462 | /** |
| | 463 | * A set of features. |
| | 464 | */ |
| 262 | | String name; |
| 263 | | |
| 264 | | Feature[] content; |
| 265 | | |
| 266 | | HierarchicalContainer container = null; |
| 267 | | |
| 268 | | FeatureSet(String name, Feature[] content) { |
| | 467 | private String pathname; |
| | 468 | |
| | 469 | private String name; |
| | 470 | |
| | 471 | private String desc; |
| | 472 | |
| | 473 | private String icon = "FeatureSet.png"; |
| | 474 | |
| | 475 | private Feature[] content; |
| | 476 | |
| | 477 | private HierarchicalContainer container = null; |
| | 478 | |
| | 479 | private boolean containerRecursive = false; |
| | 480 | |
| | 481 | FeatureSet(String pathname, Feature[] content) { |
| | 482 | this(pathname, pathname, "", content); |
| | 483 | } |
| | 484 | |
| | 485 | FeatureSet(String pathname, String name, Feature[] content) { |
| | 486 | this(pathname, name, "", content); |
| | 487 | } |
| | 488 | |
| | 489 | FeatureSet(String pathname, String name, String desc, Feature[] content) { |
| | 490 | this.pathname = pathname; |