001    /**
002     * Copyright 2005-2013 The Kuali Foundation
003     *
004     * Licensed under the Educational Community License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.opensource.org/licenses/ecl2.php
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.kuali.rice.krad.demo.uif.components;
017    
018    import org.apache.commons.io.FileUtils;
019    import org.apache.commons.io.LineIterator;
020    import org.kuali.rice.core.api.util.AbstractKeyValue;
021    import org.kuali.rice.core.api.util.ConcreteKeyValue;
022    import org.kuali.rice.core.api.util.KeyValue;
023    import org.kuali.rice.krad.datadictionary.parse.BeanTag;
024    import org.kuali.rice.krad.datadictionary.parse.BeanTagAttribute;
025    import org.kuali.rice.krad.datadictionary.parse.BeanTags;
026    import org.kuali.rice.krad.messages.MessageService;
027    import org.kuali.rice.krad.service.KRADServiceLocatorWeb;
028    import org.kuali.rice.krad.uif.component.Component;
029    import org.kuali.rice.krad.uif.container.Group;
030    import org.kuali.rice.krad.uif.container.TabGroup;
031    import org.kuali.rice.krad.uif.control.MultiValueControl;
032    import org.kuali.rice.krad.uif.element.Header;
033    import org.kuali.rice.krad.uif.element.Message;
034    import org.kuali.rice.krad.uif.field.InputField;
035    import org.kuali.rice.krad.uif.util.ComponentFactory;
036    import org.kuali.rice.krad.uif.view.FormView;
037    import org.kuali.rice.krad.uif.view.View;
038    import org.springframework.util.StringUtils;
039    
040    import javax.swing.text.StyleContext;
041    import java.io.File;
042    import java.lang.reflect.Method;
043    import java.net.URL;
044    import java.util.ArrayList;
045    import java.util.Arrays;
046    import java.util.Collections;
047    import java.util.Comparator;
048    import java.util.HashMap;
049    import java.util.List;
050    import java.util.Map;
051    import java.util.regex.Matcher;
052    import java.util.regex.Pattern;
053    
054    /**
055     * View for the ComponentLibrary demo examples of Uif Components
056     *
057     * @author Kuali Rice Team (rice.collab@kuali.org)
058     */
059    public class ComponentLibraryView extends FormView {
060        private static final long serialVersionUID = 3981186175467661843L;
061    
062        private String rootJavadocAddress;
063        private String rootDocBookAddress;
064        private String docBookAnchor;
065        private String componentName;
066        private String javaFullClassPath;
067        private String xmlFilePath;
068        private String description;
069        private String usage;
070        private String largeExampleFieldId;
071    
072        public static enum ExampleSize {
073            SMALL, LARGE, XLARGE, WINDOW;
074        }
075    
076        private ExampleSize exampleSize;
077    
078        private Group detailsGroup;
079    
080        private ComponentExhibit exhibit;
081        private List<Group> demoGroups;
082    
083        /**
084         * Initializes the TabGroup that contains description and usage.  Processes ths source code marked with the
085         * ex: comment tags and adds them to the ComponentExhibit for this view.
086         *
087         * @see Component#performInitialization(org.kuali.rice.krad.uif.view.View, Object)
088         */
089        @Override
090        public void performInitialization(View view, Object model) {
091            super.performInitialization(view, model);
092    
093            MessageService messageService = KRADServiceLocatorWeb.getMessageService();
094    
095            //set page name
096            this.getPage().setHeaderText(this.getComponentName());
097    
098            TabGroup tabGroup = ComponentFactory.getTabGroup();
099            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(demoGroup.getId(), 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    
767        /**
768         * @see org.kuali.rice.krad.uif.component.ComponentBase#copy()
769         */
770        @Override
771        protected <T> void copyProperties(T component) {
772            super.copyProperties(component);
773    
774            ComponentLibraryView libraryViewCopy = (ComponentLibraryView) component;
775    
776            libraryViewCopy.setRootJavadocAddress(this.rootJavadocAddress);
777            libraryViewCopy.setRootDocBookAddress(this.rootDocBookAddress);
778            libraryViewCopy.setDocBookAnchor(this.docBookAnchor);
779            libraryViewCopy.setComponentName(this.componentName);
780            libraryViewCopy.setJavaFullClassPath(this.javaFullClassPath);
781            libraryViewCopy.setXmlFilePath(this.xmlFilePath);
782            libraryViewCopy.setDescription(this.description);
783            libraryViewCopy.setUsage(this.usage);
784            libraryViewCopy.setLargeExampleFieldId(this.largeExampleFieldId);
785            libraryViewCopy.setExampleSize(this.exampleSize);
786    
787            if (this.detailsGroup != null) {
788                libraryViewCopy.setDetailsGroup((Group) this.detailsGroup.copy());
789            }
790    
791            if (this.exhibit != null) {
792                libraryViewCopy.setExhibit((ComponentExhibit) this.exhibit.copy());
793            }
794    
795            if (this.demoGroups != null) {
796                List<Group> demoGroupsCopy = new ArrayList<Group>();
797    
798                for (Group demoGroup : this.demoGroups) {
799                    demoGroupsCopy.add((Group) demoGroup.copy());
800                }
801                libraryViewCopy.setDemoGroups(demoGroupsCopy);
802            }
803        }
804    }