View Javadoc

1   /**
2    * Copyright 2005-2013 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.rice.krad.demo.uif.components;
17  
18  import org.apache.commons.io.FileUtils;
19  import org.apache.commons.io.LineIterator;
20  import org.kuali.rice.core.api.util.AbstractKeyValue;
21  import org.kuali.rice.core.api.util.ConcreteKeyValue;
22  import org.kuali.rice.core.api.util.KeyValue;
23  import org.kuali.rice.krad.datadictionary.parse.BeanTag;
24  import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
25  import org.kuali.rice.krad.datadictionary.parse.BeanTags;
26  import org.kuali.rice.krad.messages.MessageService;
27  import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
28  import org.kuali.rice.krad.uif.component.Component;
29  import org.kuali.rice.krad.uif.container.Group;
30  import org.kuali.rice.krad.uif.container.TabGroup;
31  import org.kuali.rice.krad.uif.control.MultiValueControl;
32  import org.kuali.rice.krad.uif.element.Header;
33  import org.kuali.rice.krad.uif.element.Message;
34  import org.kuali.rice.krad.uif.field.InputField;
35  import org.kuali.rice.krad.uif.util.ComponentFactory;
36  import org.kuali.rice.krad.uif.view.FormView;
37  import org.kuali.rice.krad.uif.view.View;
38  import org.springframework.util.StringUtils;
39  
40  import javax.swing.text.StyleContext;
41  import java.io.File;
42  import java.lang.reflect.Method;
43  import java.net.URL;
44  import java.util.ArrayList;
45  import java.util.Arrays;
46  import java.util.Collections;
47  import java.util.Comparator;
48  import java.util.HashMap;
49  import java.util.List;
50  import java.util.Map;
51  import java.util.regex.Matcher;
52  import java.util.regex.Pattern;
53  
54  /**
55   * View for the ComponentLibrary demo examples of Uif Components
56   *
57   * @author Kuali Rice Team (rice.collab@kuali.org)
58   */
59  public class ComponentLibraryView extends FormView {
60      private static final long serialVersionUID = 3981186175467661843L;
61  
62      private String rootJavadocAddress;
63      private String rootDocBookAddress;
64      private String docBookAnchor;
65      private String componentName;
66      private String javaFullClassPath;
67      private String xmlFilePath;
68      private String description;
69      private String usage;
70      private String largeExampleFieldId;
71  
72      public static enum ExampleSize {
73          SMALL, LARGE, XLARGE, WINDOW;
74      }
75  
76      private ExampleSize exampleSize;
77  
78      private Group detailsGroup;
79  
80      private ComponentExhibit exhibit;
81      private List<Group> demoGroups;
82  
83      /**
84       * Initializes the TabGroup that contains description and usage.  Processes ths source code marked with the
85       * ex: comment tags and adds them to the ComponentExhibit for this view.
86       *
87       * @see Component#performInitialization(org.kuali.rice.krad.uif.view.View, Object)
88       */
89      @Override
90      public void performInitialization(View view, Object model) {
91          super.performInitialization(view, model);
92  
93          MessageService messageService = KRADServiceLocatorWeb.getMessageService();
94  
95          //set page name
96          this.getPage().setHeaderText(this.getComponentName());
97  
98          TabGroup tabGroup = ComponentFactory.getTabGroup();
99          List<Component> tabItems = new ArrayList<Component>();
100 
101         //Description processing
102         Group descriptionGroup = ComponentFactory.getVerticalBoxGroup();
103 
104         //Description header
105         Header descriptionHeader = (Header) ComponentFactory.getNewComponentInstance("Uif-SubSectionHeader");
106         descriptionHeader.setHeaderLevel("H3");
107         descriptionHeader.setHeaderText(messageService.getMessageText("KR-SAP", null, "componentLibrary.description"));
108         descriptionHeader.setRender(false);
109         descriptionGroup.setHeader(descriptionHeader);
110 
111         //Description message
112         List<Component> descriptionItems = new ArrayList<Component>();
113         Message descriptionMessage = ComponentFactory.getMessage();
114         descriptionMessage.setMessageText(description);
115         descriptionItems.add(descriptionMessage);
116         descriptionGroup.setItems(descriptionItems);
117 
118         tabItems.add(descriptionGroup);
119 
120         //Usage processing
121         Group usageGroup = ComponentFactory.getVerticalBoxGroup();
122 
123         //Usage header
124         Header usageHeader = (Header) ComponentFactory.getNewComponentInstance("Uif-SubSectionHeader");
125         usageHeader.setHeaderLevel("H3");
126         usageHeader.setHeaderText(messageService.getMessageText("KR-SAP", null, "componentLibrary.usage"));
127         usageHeader.setRender(false);
128         usageGroup.setHeader(usageHeader);
129 
130         //Usage message
131         List<Component> usageItems = new ArrayList<Component>();
132         Message usageMessage = ComponentFactory.getMessage();
133         usageMessage.setMessageText(usage);
134         usageItems.add(usageMessage);
135         usageGroup.setItems(usageItems);
136 
137         tabItems.add(usageGroup);
138 
139         //Documentation processing
140         if (javaFullClassPath != null) {
141             processDocumentationTab(tabItems);
142         }
143 
144         //set tabGroup items
145         tabGroup.setItems(tabItems);
146 
147         tabGroup.addStyleClass("demo-componentDetailsTabs");
148 
149         //Add tabGroup to detailsGroup
150         List<Component> detailsItems = new ArrayList<Component>();
151         detailsItems.addAll(detailsGroup.getItems());
152         detailsItems.add(tabGroup);
153         detailsGroup.setItems(detailsItems);
154         view.assignComponentIds(detailsGroup);
155 
156         //exhibit setup
157         List<String> sourceCode = new ArrayList<String>();
158 
159         //process source
160         processXmlSource(sourceCode);
161 
162         //setup exhibit
163         exhibit.setDemoSourceCode(sourceCode);
164         exhibit.setDemoGroups(this.getDemoGroups());
165 
166         if (this.getExampleSize() != null &&
167                 (this.getExampleSize().equals(ExampleSize.LARGE) || this.getExampleSize().equals(ExampleSize.XLARGE))) {
168             exhibit.getTabGroup().addStyleClass("demo-noTabs");
169             Group headerRightGroup = view.getPage().getHeader().getRightGroup();
170             for (Component item : headerRightGroup.getItems()) {
171                 if (item instanceof InputField && ((InputField) item).getControl() instanceof MultiValueControl && item
172                         .getId().equals(this.getLargeExampleFieldId())) {
173                     //List<ConcreteKeyValue> keyValues = new ArrayList<ConcreteKeyValue>();
174                     List<KeyValue> values = new ArrayList<KeyValue>();
175                     int i = 0;
176                     for (Group demoGroup : demoGroups) {
177                         values.add(new ConcreteKeyValue(String.valueOf(i), demoGroup.getHeader().getHeaderText()));
178                         i++;
179                     }
180 
181                     //values.addAll(keyValues);
182                     ((MultiValueControl) ((InputField) item).getControl()).setOptions(values);
183                     item.setRender(true);
184                 }
185             }
186         }
187 
188         if(this.getExampleSize() != null && this.getExampleSize().equals(ExampleSize.XLARGE)){
189             this.addStyleClass("demo-xLargeLibraryView");
190         }
191 
192         //Add detailsGroup and exhibit to page
193         List<Component> pageItems = new ArrayList<Component>();
194         pageItems.addAll(this.getPage().getItems());
195         pageItems.add(exhibit);
196         pageItems.add(detailsGroup);
197         this.getPage().setItems(pageItems);
198     }
199 
200     /**
201      * Builds out the documentation tab content by auto-generating the content for properties and documentation and
202      * adds it to the tabItems list
203      *
204      * @param tabItems list of tab items for component details
205      */
206     private void processDocumentationTab(List<Component> tabItems) {
207         MessageService messageService = KRADServiceLocatorWeb.getMessageService();
208 
209         try {
210             Class<?> componentClass = Class.forName(javaFullClassPath);
211             Method methodsArray[] = componentClass.getMethods();
212 
213             //get top level documentation for this class
214             String classMessage = messageService.getMessageText("KR-SAP", null, javaFullClassPath);
215 
216             if (classMessage == null) {
217                 classMessage = "NO DOCUMENTATION AVAILABLE/FOUND... we are working on it!";
218             }
219 
220             //scrub class message of @link and @code
221             classMessage = classMessage.replaceAll("\\{[@#]link (.*?)\\}", "<i>$1</i>");
222             classMessage = classMessage.replaceAll("\\{[@#]code (.*?)\\}", "<i>$1</i>");
223 
224             //Generate schema and bean Id reference table
225             String schemaTable =
226                     "<table class='demo-schemaIdDocTable'><tr><th>Schema Name</th>" + "<th>Uif Bean Id</th></tr>";
227             if (componentClass.isAnnotationPresent(BeanTag.class)) {
228                 BeanTag beanTag = componentClass.getAnnotation(BeanTag.class);
229                 schemaTable = schemaTable +
230                         "<tr><td>" + beanTag.name() + "</td><td>" + beanTag.parent() + "</td></tr>";
231                 schemaTable = schemaTable + "</table>";
232             } else if (componentClass.isAnnotationPresent(BeanTags.class)) {
233                 BeanTags beanTags = componentClass.getAnnotation(BeanTags.class);
234                 BeanTag[] beanTagArray = beanTags.value();
235                 for (BeanTag beanTag : beanTagArray) {
236                     schemaTable = schemaTable +
237                             "<tr><td>" + beanTag.name() + "</td><td>" + beanTag.parent() + "</td></tr>";
238                 }
239                 schemaTable = schemaTable + "</table>";
240             } else {
241                 schemaTable = "";
242             }
243 
244             String javadocTitle = messageService.getMessageText("KR-SAP", null, "componentLibrary.javaDoc");
245             String kradGuideTitle = messageService.getMessageText("KR-SAP", null, "componentLibrary.kradGuide");
246             String devDocumentationTitle = messageService.getMessageText("KR-SAP", null,
247                     "componentLibrary.devDocumentation");
248             String beanDefsTitle = messageService.getMessageText("KR-SAP", null, "componentLibrary.beanDefs");
249 
250             //build documentation links from javadoc address and docbook address/anchor
251             String docLinkDiv = "<div class='demo-docLinks'> "
252                     + "<label>Additional Resources:</label><a class='demo-documentationLink'"
253                     + " href='"
254                     + getRootJavadocAddress()
255                     + javaFullClassPath.replace('.', '/')
256                     + ".html' target='_blank'>"
257                     + javadocTitle
258                     + "</a>"
259                     + "<a class='demo-documentationLink'"
260                     + " href='"
261                     + getRootDocBookAddress()
262                     + getDocBookAnchor()
263                     + "' target='_blank'>"
264                     + kradGuideTitle
265                     + "</a>"
266                     + "</div>";
267 
268             //initialize the documentation content
269             String documentationMessageContent =
270                     "<H3>" + this.getComponentName() + " " + devDocumentationTitle + "</H3>" +
271                             docLinkDiv + classMessage + "<H3>" + beanDefsTitle + "</H3>" + schemaTable;
272 
273             List<String> propertyDescriptions = new ArrayList<String>();
274             Map<String, List<String>> inheritedProperties = new HashMap<String, List<String>>();
275 
276             List<Method> methods = Arrays.asList(methodsArray);
277 
278             //alphabetize the methods by name
279             Collections.sort(methods, new Comparator<Method>() {
280                 @Override
281                 public int compare(Method method1, Method method2) {
282                     String name1 = getPropName(method1);
283                     String name2 = getPropName(method2);
284                     return name1.compareTo(
285                             name2);  //To change body of implemented methods use File | Settings | File Templates.
286                 }
287             });
288 
289             //Process all methods on this class
290             for (Method method : methods) {
291                 BeanTagAttribute attribute = method.getAnnotation(BeanTagAttribute.class);
292                 if (attribute != null) {
293                     //property variables
294                     String name = getPropName(method);
295                     String methodClass = method.getDeclaringClass().getName();
296                     String returnType = method.getReturnType().getName();
297                     returnType = returnType.replaceAll("<.*?>", "");
298                     String returnTypeShort = returnType.substring(returnType.lastIndexOf(".") + 1);
299 
300                     //get property documentation message
301                     String key = methodClass + "|" + name + "|" + returnTypeShort;
302                     String propertyMessage = messageService.getMessageText("KR-SAP", null, key);
303 
304                     if (propertyMessage == null) {
305                         propertyMessage = "NO DOCUMENTATION AVAILABLE... we are working on it!";
306                     }
307 
308                     //scrub property message of @link and @code
309                     propertyMessage = propertyMessage.replaceAll("\\{[@#]link (.*?)\\}", "<i>$1</i>");
310                     propertyMessage = propertyMessage.replaceAll("\\{[@#]code (.*?)\\}", "<i>$1</i>");
311 
312                     //wrap in link if a kuali type
313                     if (returnType.startsWith("org.kuali")) {
314                         returnTypeShort = "<a href='"
315                                 + getRootJavadocAddress()
316                                 + returnType.replace('.', '/')
317                                 + ".html' target='_blank'>"
318                                 + returnTypeShort
319                                 + "</a>";
320                     }
321 
322                     //html propertyMessage content
323                     propertyMessage = "<div class='demo-propertyItem'>"
324                             + "<h4 class='demo-propertyName'>"
325                             + name
326                             + "</h4>"
327                             + "<div class='demo-propertyType'>"
328                             + returnTypeShort
329                             + "</div>"
330                             + "<div class='demo-propertyDesc'>"
331                             + propertyMessage
332                             + "</div></div>";
333 
334                     if (!methodClass.equals(javaFullClassPath)) {
335                         //if this method comes from a parent and not this class, put it in the inheritedPropertiesMap
336                         List<String> classProperties = inheritedProperties.get(methodClass);
337                         if (classProperties == null) {
338                             classProperties = new ArrayList<String>();
339                         }
340                         classProperties.add(propertyMessage);
341                         inheritedProperties.put(methodClass, classProperties);
342                     } else {
343                         propertyDescriptions.add(propertyMessage);
344                     }
345                 }
346             }
347 
348             documentationMessageContent =
349                     documentationMessageContent + "<H3>Properties</H3><div class='demo-propertiesContent'>";
350             for (String desc : propertyDescriptions) {
351                 documentationMessageContent = documentationMessageContent + desc;
352             }
353             documentationMessageContent = documentationMessageContent + "</div>";
354 
355             Group documentationGroup = ComponentFactory.getVerticalBoxGroup();
356 
357             //properties header
358             Header documentationHeader = (Header) ComponentFactory.getNewComponentInstance("Uif-SubSectionHeader");
359             documentationHeader.setHeaderLevel("H3");
360             documentationHeader.setHeaderText(messageService.getMessageText("KR-SAP", null,
361                     "componentLibrary.documentation"));
362             documentationHeader.setRender(false);
363             documentationGroup.setHeader(documentationHeader);
364 
365             List<Component> propertiesItems = new ArrayList<Component>();
366             Message propertiesMessage = ComponentFactory.getMessage();
367             propertiesMessage.setParseComponents(false);
368             propertiesMessage.setMessageText(documentationMessageContent);
369             propertiesItems.add(propertiesMessage);
370 
371             //create the inherited properties disclosures
372             if (!inheritedProperties.isEmpty()) {
373 
374                 //todo sort alphabetically here?
375                 for (String className : inheritedProperties.keySet()) {
376                     String messageContent = "";
377                     List<String> inheritedPropertyDescriptions = inheritedProperties.get(className);
378 
379                     for (String desc : inheritedPropertyDescriptions) {
380                         messageContent = messageContent + desc;
381                     }
382 
383                     Group iPropertiesGroup = ComponentFactory.getVerticalBoxGroup();
384 
385                     //inherited properties header
386                     Header iPropHeader = (Header) ComponentFactory.getNewComponentInstance("Uif-SubSectionHeader");
387                     iPropHeader.setHeaderLevel("H3");
388                     iPropHeader.setHeaderText(messageService.getMessageText("KR-SAP", null,
389                             "componentLibrary.inheritedFrom") + " " + className);
390                     //iPropHeader.setRender(false);
391                     iPropertiesGroup.setHeader(iPropHeader);
392                     iPropertiesGroup.getDisclosure().setRender(true);
393                     iPropertiesGroup.getDisclosure().setDefaultOpen(false);
394 
395                     List<Component> iPropertiesItems = new ArrayList<Component>();
396                     Message iPropertiesMessage = ComponentFactory.getMessage();
397                     iPropertiesMessage.setParseComponents(false);
398                     iPropertiesMessage.setMessageText(messageContent);
399                     iPropertiesItems.add(iPropertiesMessage);
400                     iPropertiesGroup.setItems(iPropertiesItems);
401 
402                     propertiesItems.add(iPropertiesGroup);
403                 }
404             }
405 
406             documentationGroup.setItems(propertiesItems);
407 
408             tabItems.add(documentationGroup);
409         } catch (Exception e) {
410             throw new RuntimeException("Error loading class: " + javaFullClassPath, e);
411         }
412     }
413 
414     /**
415      * Gets the property name from the method by stripping get/is and making the first letter lowercase
416      *
417      * @param method the Method object
418      * @return the property name for the Method passed in
419      */
420     private String getPropName(Method method) {
421         String name = method.getName();
422 
423         if (name.startsWith("get")) {
424             name = name.replaceFirst("get", "");
425         } else {
426             name = name.replaceFirst("is", "");
427         }
428 
429         name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
430 
431         return name;
432     }
433 
434     /**
435      * Process xml source code to be consumed by the exhibit component
436      *
437      * @param sourceCode list of sourceCode to be filled in, in order the group exhibit examples appear
438      */
439     private void processXmlSource(List<String> sourceCode) {
440         Map<String, String> idSourceMap = new HashMap<String, String>();
441         if (xmlFilePath != null) {
442             try {
443                 //Get the source file
444                 URL fileUrl = ComponentLibraryView.class.getClassLoader().getResource(xmlFilePath);
445                 File file = new File(fileUrl.toURI());
446                 Pattern examplePattern = Pattern.compile("ex:(.*?)(\\s|(-->))");
447 
448                 boolean readingSource = false;
449                 String currentSource = "";
450                 String currentId = "";
451 
452                 LineIterator lineIt = FileUtils.lineIterator(file);
453                 while (lineIt.hasNext()) {
454                     String line = lineIt.next();
455                     if (line.contains("ex:") && !readingSource) {
456                         //found a ex: tag and are not already reading source
457                         readingSource = true;
458 
459                         Matcher matcher = examplePattern.matcher(line);
460                         if (matcher.find()) {
461                             currentId = matcher.group(1);
462                         }
463 
464                         currentSource = idSourceMap.get(currentId) != null ? idSourceMap.get(currentId) : "";
465 
466                         if (!currentSource.isEmpty()) {
467                             currentSource = currentSource + "\n";
468                         }
469                     } else if (line.contains("ex:") && readingSource) {
470                         //stop reading source on second ex tag
471                         readingSource = false;
472                         idSourceMap.put(currentId, currentSource);
473                     } else if (readingSource) {
474                         //when reading source just continue to add it
475                         currentSource = currentSource + line + "\n";
476                     }
477 
478                 }
479             } catch (Exception e) {
480                 throw new RuntimeException(
481                         "file not found or error while reading: " + xmlFilePath + " for source reading", e);
482             }
483         }
484 
485         for (Group demoGroup : demoGroups) {
486             //add source to the source list by order that demo groups appear
487             String groupId = demoGroup.getId();
488             String source = idSourceMap.get(groupId);
489             if (source != null) {
490                 //translate the source to something that can be displayed
491                 sourceCode.add(translateSource(source));
492             }
493         }
494     }
495 
496     /**
497      * Translates the source by removing chracters that the dom will misinterpret as html and to ensure
498      * source spacing is correct
499      *
500      * @param source the original source
501      * @return that translated source used in the SyntaxHighlighter of the exhibit
502      */
503     private String translateSource(String source) {
504         //convert characters to ascii equivalent
505         source = source.replace("<", "&lt;");
506         source = source.replace(">", "&gt;");
507         source = source.replaceAll("[ \\t]", "&#32;");
508 
509         Pattern linePattern = Pattern.compile("((&#32;)*).*?(\\n)+");
510         Matcher matcher = linePattern.matcher(source);
511         int toRemove = -1;
512 
513         //find the line with the least amount of spaces
514         while (matcher.find()) {
515             String spaces = matcher.group(1);
516 
517             int count = StringUtils.countOccurrencesOf(spaces, "&#32;");
518             if (toRemove == -1 || count < toRemove) {
519                 toRemove = count;
520             }
521         }
522 
523         matcher.reset();
524         String newSource = "";
525 
526         //remove the min number of spaces from each line to get them to align left properly in the viewer
527         while (matcher.find()) {
528             String line = matcher.group();
529             newSource = newSource + line.replaceFirst("(&#32;){" + toRemove + "}", "");
530         }
531 
532         //remove very last newline
533         newSource = newSource.replaceAll("\\n$", "");
534         //replace remaining newlines with ascii equivalent
535         newSource = newSource.replace("\n", "&#010;");
536 
537         return newSource;
538     }
539 
540     /**
541      * ComponentLibraryView constructor
542      */
543     public ComponentLibraryView() {
544         demoGroups = new ArrayList<Group>();
545     }
546 
547     /**
548      * The name of the component (to be used by this page's header)
549      *
550      * @return componentName the name of the component being demoed
551      */
552     public String getComponentName() {
553         return componentName;
554     }
555 
556     /**
557      * Sets the componentName
558      *
559      * @param componentName
560      */
561     public void setComponentName(String componentName) {
562         this.componentName = componentName;
563     }
564 
565     /**
566      * Set the java path to the class being used by this component
567      * TODO not yet used
568      *
569      * @return the java path to the class
570      */
571     public String getJavaFullClassPath() {
572         return javaFullClassPath;
573     }
574 
575     /**
576      * Get the java full class path
577      *
578      * @param javaFullClassPath
579      */
580     public void setJavaFullClassPath(String javaFullClassPath) {
581         this.javaFullClassPath = javaFullClassPath;
582     }
583 
584     /**
585      * The xml file path that contains the source being used for this demo, must start with / (relative path)
586      *
587      * @return the xml file path
588      */
589     public String getXmlFilePath() {
590         return xmlFilePath;
591     }
592 
593     /**
594      * Set the xml file path
595      *
596      * @param xmlFilePath
597      */
598     public void setXmlFilePath(String xmlFilePath) {
599         this.xmlFilePath = xmlFilePath;
600     }
601 
602     /**
603      * The description of the component being demoed by this view
604      *
605      * @return the description
606      */
607     public String getDescription() {
608         return description;
609     }
610 
611     /**
612      * Sets the description
613      *
614      * @param description
615      */
616     public void setDescription(String description) {
617         this.description = description;
618     }
619 
620     /**
621      * Gets the usage description and examples of how to use this component
622      *
623      * @return the usage text
624      */
625     public String getUsage() {
626         return usage;
627     }
628 
629     /**
630      * Set the usage text
631      *
632      * @param usage
633      */
634     public void setUsage(String usage) {
635         this.usage = usage;
636     }
637 
638     /**
639      * The details group that will contain the description, usage, and properties tabGroup
640      *
641      * @return the details group
642      */
643     public Group getDetailsGroup() {
644         return detailsGroup;
645     }
646 
647     /**
648      * Set the details group
649      *
650      * @param detailsGroup
651      */
652     public void setDetailsGroup(Group detailsGroup) {
653         this.detailsGroup = detailsGroup;
654     }
655 
656     /**
657      * Gets the exhibit that will display the example, source code, and tabs to switch between examples
658      *
659      * @return the ComponentExhibit for this component demo view
660      */
661     public ComponentExhibit getExhibit() {
662         return exhibit;
663     }
664 
665     /**
666      * Set the ComponentExhibit for this demo
667      *
668      * @param exhibit
669      */
670     public void setExhibit(ComponentExhibit exhibit) {
671         this.exhibit = exhibit;
672     }
673 
674     /**
675      * List of groups that will demostrate the functionality fo the component being demonstrated, these groups are
676      * copied directly into componentExhibit - this is an ease of use property
677      *
678      * @return the demoGroups
679      */
680     public List<Group> getDemoGroups() {
681         return demoGroups;
682     }
683 
684     /**
685      * Set the demoGroups used for demonstrating features of the component
686      *
687      * @param demoGroups
688      */
689     public void setDemoGroups(List<Group> demoGroups) {
690         this.demoGroups = demoGroups;
691     }
692 
693     /**
694      * The root address to the javadoc for Rice
695      *
696      * @return the javadoc root address
697      */
698     public String getRootJavadocAddress() {
699         return rootJavadocAddress;
700     }
701 
702     /**
703      * Set the root address to the javadoc for Rice
704      *
705      * @param rootJavadocAddress
706      */
707     public void setRootJavadocAddress(String rootJavadocAddress) {
708         this.rootJavadocAddress = rootJavadocAddress;
709     }
710 
711     /**
712      * Get the root address to the docbook for KRAD
713      *
714      * @return KRAD's docbook address (url)
715      */
716     public String getRootDocBookAddress() {
717         return rootDocBookAddress;
718     }
719 
720     /**
721      * Set the docbook root address
722      *
723      * @param rootDocBookAddress
724      */
725     public void setRootDocBookAddress(String rootDocBookAddress) {
726         this.rootDocBookAddress = rootDocBookAddress;
727     }
728 
729     /**
730      * The anchor in the docbook this component is described at (do not include #)
731      *
732      * @return the anchor name
733      */
734     public String getDocBookAnchor() {
735         if (docBookAnchor == null) {
736             return "";
737         } else {
738             return "#" + docBookAnchor;
739         }
740     }
741 
742     /**
743      * Set the docBookAnchor name for the component described by this view
744      *
745      * @param docBookAnchor
746      */
747     public void setDocBookAnchor(String docBookAnchor) {
748         this.docBookAnchor = docBookAnchor;
749     }
750 
751     public ExampleSize getExampleSize() {
752         return exampleSize;
753     }
754 
755     public void setExampleSize(ExampleSize exampleSize) {
756         this.exampleSize = exampleSize;
757     }
758 
759     public String getLargeExampleFieldId() {
760         return largeExampleFieldId;
761     }
762 
763     public void setLargeExampleFieldId(String largeExampleFieldId) {
764         this.largeExampleFieldId = largeExampleFieldId;
765     }
766 }