Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 350359
Collapse All | Expand All

(-)a/org.eclipse.skalli.model.ext.misc/META-INF/MANIFEST.MF (-1 / +2 lines)
Lines 35-41 Service-Component: OSGI-INF/ExtensionServiceReview.xml, Link Here
35
 OSGI-INF/ExtensionServiceLinkGroups.xml,
35
 OSGI-INF/ExtensionServiceLinkGroups.xml,
36
 OSGI-INF/MailingListMappingConfigSection.xml,
36
 OSGI-INF/MailingListMappingConfigSection.xml,
37
 OSGI-INF/ScmLocationMappingConfigSection.xml,
37
 OSGI-INF/ScmLocationMappingConfigSection.xml,
38
 OSGI-INF/ScrumPeopleProvider.xml
38
 OSGI-INF/ScrumPeopleProvider.xml,
39
 OSGI-INF/ExtensionServiceRelatedProjects.xml
39
Export-Package: org.eclipse.skalli.model.ext.devinf,
40
Export-Package: org.eclipse.skalli.model.ext.devinf,
40
 org.eclipse.skalli.model.ext.info,
41
 org.eclipse.skalli.model.ext.info,
41
 org.eclipse.skalli.model.ext.linkgroups,
42
 org.eclipse.skalli.model.ext.linkgroups,
(-)a/org.eclipse.skalli.model.ext.misc/OSGI-INF/ExtensionServiceRelatedProjects.xml (+18 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?><!--
2
    Copyright (c) 2010, 2011 SAP AG and others.
3
    All rights reserved. This program and the accompanying materials
4
    are made available under the terms of the Eclipse Public License v1.0
5
    which accompanies this distribution, and is available at
6
    http://www.eclipse.org/legal/epl-v10.html
7
   
8
    Contributors:
9
        SAP AG - initial API and implementation
10
 -->
11
12
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="org.eclipse.skalli.model.ext.related">
13
   <implementation class="org.eclipse.skalli.model.ext.misc.internal.ExtensionServiceRelatedProjects"/>
14
   <service>
15
      <provide interface="org.eclipse.skalli.model.ext.ExtensionService"/>
16
   </service>
17
</scr:component>
18
(-)a/org.eclipse.skalli.model.ext.misc/src/main/java/org/eclipse/skalli/model/ext/misc/RelatedProjectsExt.java (+49 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010, 2011 SAP AG and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     SAP AG - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.skalli.model.ext.misc;
12
13
import org.eclipse.skalli.common.util.UUIDList;
14
import org.eclipse.skalli.model.ext.ExtensionEntityBase;
15
import org.eclipse.skalli.model.ext.PropertyName;
16
17
public class RelatedProjectsExt extends ExtensionEntityBase {
18
    public static final String MODEL_VERSION = "1.0"; //$NON-NLS-1$
19
    public static final String NAMESPACE = "http://www.eclipse.org/skalli/2010/Model/Extension-Related"; //$NON-NLS-1$
20
21
    @PropertyName(position = 0)
22
    public static final String PROPERTY_CALCULATED = "calculated";
23
24
    @PropertyName(position = 1)
25
    public static final String PROPERTY_RELATED_PROJECT = "relatedProjects"; //$NON-NLS-1$
26
27
    private UUIDList relatedProjects;
28
    private boolean calculated;
29
30
    public boolean getCalculated() {
31
        return calculated;
32
    }
33
34
    public void setCalculated(boolean calculated) {
35
        this.calculated = calculated;
36
    }
37
38
    public UUIDList getRelatedProjects() {
39
        if (relatedProjects == null) {
40
            relatedProjects = new UUIDList();
41
        }
42
        return relatedProjects;
43
    }
44
45
    public void setRelatedProjects(UUIDList relatedProjects) {
46
        this.relatedProjects = new UUIDList(relatedProjects);
47
    }
48
49
}
(-)a/org.eclipse.skalli.model.ext.misc/src/main/java/org/eclipse/skalli/model/ext/misc/internal/ExtensionServiceRelatedProjects.java (+77 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010, 2011 SAP AG and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     SAP AG - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.skalli.model.ext.misc.internal;
12
13
import java.util.Map;
14
15
import org.eclipse.skalli.common.util.CollectionUtils;
16
import org.eclipse.skalli.model.ext.ExtensionService;
17
import org.eclipse.skalli.model.ext.ExtensionServiceBase;
18
import org.eclipse.skalli.model.ext.misc.RelatedProjectsExt;
19
20
public class ExtensionServiceRelatedProjects extends ExtensionServiceBase<RelatedProjectsExt>
21
        implements ExtensionService<RelatedProjectsExt> {
22
23
    private static final String DESCRIPTION = "Information about projects that might be related to this projects or could also be of interest.";
24
25
    private static final String CAPTION = "Related Projects";
26
27
    private static final Map<String, String> CAPTIONS = CollectionUtils
28
            .asMap(new String[][] {
29
                    { RelatedProjectsExt.PROPERTY_RELATED_PROJECT, "Related Project" },
30
                    { RelatedProjectsExt.PROPERTY_CALCULATED,
31
                            "Calculate Related Projects (based on similarities to this project)" } });
32
33
    @Override
34
    public Class<RelatedProjectsExt> getExtensionClass() {
35
        return RelatedProjectsExt.class;
36
    }
37
38
    @Override
39
    public String getModelVersion() {
40
        return RelatedProjectsExt.MODEL_VERSION;
41
    }
42
43
    @Override
44
    public String getShortName() {
45
        return "relatedProjects";
46
    }
47
48
    @Override
49
    public String getCaption() {
50
        return CAPTION;
51
    }
52
53
    @Override
54
    public String getCaption(String propertyName) {
55
        String caption = CAPTIONS.get(propertyName);
56
        if (caption == null) {
57
            caption = super.getCaption(propertyName);
58
        }
59
        return caption;
60
    }
61
62
    @Override
63
    public String getDescription() {
64
        return DESCRIPTION;
65
    }
66
67
    @Override
68
    public String getNamespace() {
69
        return RelatedProjectsExt.NAMESPACE;
70
    }
71
72
    @Override
73
    public String getXsdFileName() {
74
        return null;
75
    }
76
77
}
(-)a/org.eclipse.skalli.view.ext.impl/META-INF/MANIFEST.MF (+1 lines)
Lines 41-46 Service-Component: OSGI-INF/ExtensionServiceProjectBasicsEditForm.xml, Link Here
41
 OSGI-INF/ExtensionServiceMavenProjectExtEditForm.xml,
41
 OSGI-INF/ExtensionServiceMavenProjectExtEditForm.xml,
42
 OSGI-INF/ExtensionServiceReviewProjectExtEditForm.xml,
42
 OSGI-INF/ExtensionServiceReviewProjectExtEditForm.xml,
43
 OSGI-INF/ExtensionServiceScrumProjectExtEditForm.xml,
43
 OSGI-INF/ExtensionServiceScrumProjectExtEditForm.xml,
44
 OSGI-INF/ExtensionServiceRelatedProjectsExtEditForm.xml,
44
 OSGI-INF/ExtensionServiceProjectAboutBox.xml,
45
 OSGI-INF/ExtensionServiceProjectAboutBox.xml,
45
 OSGI-INF/ExtensionServiceProjectDevInfBox.xml,
46
 OSGI-INF/ExtensionServiceProjectDevInfBox.xml,
46
 OSGI-INF/ExtensionServiceProjectIssuesBox.xml,
47
 OSGI-INF/ExtensionServiceProjectIssuesBox.xml,
(-)a/org.eclipse.skalli.view.ext.impl/OSGI-INF/ExtensionServiceRelatedProjectsExtEditForm.xml (+19 lines)
Added Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<!--
3
    Copyright (c) 2010, 2011 SAP AG and others.
4
    All rights reserved. This program and the accompanying materials
5
    are made available under the terms of the Eclipse Public License v1.0
6
    which accompanies this distribution, and is available at
7
    http://www.eclipse.org/legal/epl-v10.html
8
   
9
    Contributors:
10
        SAP AG - initial API and implementation
11
 -->
12
13
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="org.eclipse.skalli.view.ext.impl.internal.forms.related">
14
   <implementation class="org.eclipse.skalli.view.ext.impl.internal.forms.RelatedProjectsExtEditForm"/>
15
   <service>
16
      <provide interface="org.eclipse.skalli.view.ext.ExtensionFormService"/>
17
   </service>
18
</scr:component>
19
(-)a/org.eclipse.skalli.view.ext.impl/src/main/java/org/eclipse/skalli/view/ext/impl/internal/forms/RelatedProjectsExtEditForm.java (+98 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2010, 2011 SAP AG and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     SAP AG - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.skalli.view.ext.impl.internal.forms;
12
13
import org.eclipse.skalli.common.util.UUIDList;
14
import org.eclipse.skalli.model.core.Project;
15
import org.eclipse.skalli.model.ext.misc.RelatedProjectsExt;
16
import org.eclipse.skalli.view.component.MultiComboBox;
17
import org.eclipse.skalli.view.ext.AbstractExtensionFormService;
18
import org.eclipse.skalli.view.ext.DefaultProjectFieldFactory;
19
import org.eclipse.skalli.view.ext.ProjectEditContext;
20
21
import com.vaadin.data.Item;
22
import com.vaadin.data.Property.ValueChangeListener;
23
import com.vaadin.data.util.BeanItem;
24
import com.vaadin.ui.CheckBox;
25
import com.vaadin.ui.Field;
26
import com.vaadin.ui.FormFieldFactory;
27
28
public class RelatedProjectsExtEditForm extends AbstractExtensionFormService<RelatedProjectsExt> {
29
30
    @Override
31
    public String getIconPath() {
32
        return "res/icons/relProjects.png"; //$NON-NLS-1$
33
    }
34
35
    @Override
36
    public float getRank() {
37
        return 1.5f;
38
    }
39
40
    @Override
41
    protected FormFieldFactory getFieldFactory(Project project, ProjectEditContext context) {
42
        return new FieldFactory(project, context);
43
    }
44
45
    @Override
46
    protected Item getItemDataSource(Project project) {
47
        return new BeanItem<RelatedProjectsExt>(getExtension(project));
48
    }
49
50
    private class FieldFactory extends DefaultProjectFieldFactory<RelatedProjectsExt> {
51
52
        private static final long serialVersionUID = 939519704283769367L;
53
        private RelatedProjectsExt extension;
54
        private Field comboBox;
55
56
        public FieldFactory(Project project, ProjectEditContext context) {
57
            super(project, RelatedProjectsExt.class, context);
58
            this.extension = getExtension(project);
59
        }
60
61
        @Override
62
        protected Field createField(Object propertyId, String caption) {
63
64
            if (RelatedProjectsExt.PROPERTY_CALCULATED.equals(propertyId)) {
65
                final CheckBox field = new CheckBox(caption);
66
                field.setImmediate(true);
67
                field.addListener(new ValueChangeListener() {
68
69
                    private static final long serialVersionUID = 3996507266934851419L;
70
71
                    @Override
72
                    public void valueChange(com.vaadin.data.Property.ValueChangeEvent event) {
73
                        if (comboBox != null) {
74
                            comboBox.setEnabled(!field.booleanValue());
75
                        }
76
                    }
77
                });
78
                return field;
79
            } else if (RelatedProjectsExt.PROPERTY_RELATED_PROJECT.equals(propertyId)) {
80
                UUIDList ids = extension.getRelatedProjects();
81
                comboBox = new MultiComboBox(caption, ids);
82
                comboBox.setEnabled(!extension.getCalculated());
83
                return comboBox;
84
            }
85
            return null;
86
        }
87
    }
88
89
    @Override
90
    public Class<RelatedProjectsExt> getExtensionClass() {
91
        return RelatedProjectsExt.class;
92
    }
93
94
    @Override
95
    public RelatedProjectsExt newExtensionInstance() {
96
        return new RelatedProjectsExt();
97
    }
98
}
(-)a/org.eclipse.skalli.view.ext.impl/src/main/java/org/eclipse/skalli/view/ext/impl/internal/infobox/RelatedProjectsInfoBox.java (-8 / +44 lines)
Lines 10-28 Link Here
10
 *******************************************************************************/
10
 *******************************************************************************/
11
package org.eclipse.skalli.view.ext.impl.internal.infobox;
11
package org.eclipse.skalli.view.ext.impl.internal.infobox;
12
12
13
import java.util.UUID;
14
15
import org.eclipse.skalli.api.java.ProjectService;
13
import org.eclipse.skalli.api.java.SearchHit;
16
import org.eclipse.skalli.api.java.SearchHit;
14
import org.eclipse.skalli.api.java.SearchResult;
17
import org.eclipse.skalli.api.java.SearchResult;
15
import org.eclipse.skalli.api.java.SearchService;
18
import org.eclipse.skalli.api.java.SearchService;
16
import org.eclipse.skalli.common.Services;
19
import org.eclipse.skalli.common.Services;
20
import org.eclipse.skalli.common.util.UUIDList;
17
import org.eclipse.skalli.model.core.Project;
21
import org.eclipse.skalli.model.core.Project;
22
import org.eclipse.skalli.model.ext.misc.RelatedProjectsExt;
18
import org.eclipse.skalli.view.ext.AbstractInfoBox;
23
import org.eclipse.skalli.view.ext.AbstractInfoBox;
19
import org.eclipse.skalli.view.ext.ExtensionUtil;
24
import org.eclipse.skalli.view.ext.ExtensionUtil;
20
import org.eclipse.skalli.view.ext.ProjectInfoBox;
25
import org.eclipse.skalli.view.ext.ProjectInfoBox;
26
21
import com.vaadin.terminal.ExternalResource;
27
import com.vaadin.terminal.ExternalResource;
22
import com.vaadin.ui.Component;
28
import com.vaadin.ui.Component;
23
import com.vaadin.ui.CssLayout;
29
import com.vaadin.ui.CssLayout;
30
import com.vaadin.ui.Label;
24
import com.vaadin.ui.Layout;
31
import com.vaadin.ui.Layout;
25
import com.vaadin.ui.Link;
26
32
27
public class RelatedProjectsInfoBox extends AbstractInfoBox implements ProjectInfoBox {
33
public class RelatedProjectsInfoBox extends AbstractInfoBox implements ProjectInfoBox {
28
34
Lines 41-58 public class RelatedProjectsInfoBox extends AbstractInfoBox implements ProjectIn Link Here
41
        Layout layout = new CssLayout();
47
        Layout layout = new CssLayout();
42
        layout.setSizeFull();
48
        layout.setSizeFull();
43
49
50
        RelatedProjectsExt ext = project.getExtension(RelatedProjectsExt.class);
51
        if (ext != null) {
52
            Label label = new Label("The following projects might also be of interest to you:",
53
                    Label.CONTENT_XHTML);
54
            layout.addComponent(label);
55
            boolean calculated = ext.getCalculated();
56
            if (calculated) {
57
                addCalculatedContent(project, layout);
58
            } else {
59
                UUIDList ids = ext.getRelatedProjects();
60
                ProjectService projectService = Services.getRequiredService(ProjectService.class);
61
                for (UUID uuid : ids) {
62
                    Project relatedProject = projectService.getByUUID(uuid);
63
                    ExternalResource externalResource = new ExternalResource("/projects/" + relatedProject.getProjectId());
64
                    String content = HSPACE + "<a href=" + externalResource.getURL() + ">" + relatedProject.getName()
65
                            + "</a>";
66
                    Label l = new Label(content, Label.CONTENT_XHTML);
67
                    layout.addComponent(l);
68
                }
69
            }
70
        }
71
        return layout;
72
    }
73
74
    protected void addCalculatedContent(Project project, Layout layout) {
44
        SearchService searchService = Services.getService(SearchService.class);
75
        SearchService searchService = Services.getService(SearchService.class);
45
        if (searchService != null) {
76
        if (searchService != null) {
46
            SearchResult<Project> relatedProjects = searchService.getRelatedProjects(project, 5);
77
            SearchResult<Project> relatedProjects = searchService.getRelatedProjects(project, 5);
47
            for (SearchHit<Project> hit : relatedProjects.getResult()) {
78
            for (SearchHit<Project> hit : relatedProjects.getResult()) {
48
                Link link = new Link();
79
                ExternalResource externalResource = new ExternalResource("/projects/" + hit.getEntity().getProjectId());
49
                link.setCaption(hit.getEntity().getName());
80
                String content = HSPACE + "<a href=" + externalResource.getURL() + ">" + hit.getEntity().getName()
50
                link.setResource(new ExternalResource("/projects/" + hit.getEntity().getProjectId())); //$NON-NLS-1$
81
                        + "*</a>";
51
                layout.addComponent(link);
82
                Label label = new Label(content, Label.CONTENT_XHTML);
83
                layout.addComponent(label);
52
            }
84
            }
53
        }
85
            Label label = new Label(HSPACE + "*calculated based on similarities between the projects",
86
                    Label.CONTENT_XHTML);
87
            label.setStyleName("light");//$NON-NLS-1$
88
            layout.addComponent(label);
54
89
55
        return layout;
90
        }
56
    }
91
    }
57
92
58
    @Override
93
    @Override
Lines 67-73 public class RelatedProjectsInfoBox extends AbstractInfoBox implements ProjectIn Link Here
67
102
68
    @Override
103
    @Override
69
    public boolean isVisible(Project project, String loggedInUserId) {
104
    public boolean isVisible(Project project, String loggedInUserId) {
70
        if (project.isDeleted()) {
105
        RelatedProjectsExt ext = project.getExtension(RelatedProjectsExt.class);
106
        if (ext == null || ext.getRelatedProjects().isEmpty()) {
71
            return false;
107
            return false;
72
        } else {
108
        } else {
73
            return true;
109
            return true;
(-)a/org.eclipse.skalli.view.ext/src/main/java/org/eclipse/skalli/view/ext/AbstractInfoBox.java (+1 lines)
Lines 15-19 public abstract class AbstractInfoBox { Link Here
15
    protected static final String STYLE_LABEL = "infolabel";
15
    protected static final String STYLE_LABEL = "infolabel";
16
    protected static final String STYLE_LINK = "infolink";
16
    protected static final String STYLE_LINK = "infolink";
17
    protected static final String STYLE_TEAMLABEL = "teamlabel";
17
    protected static final String STYLE_TEAMLABEL = "teamlabel";
18
    protected static final String HSPACE = "&nbsp;&nbsp;&nbsp;&nbsp;"; //$NON-NLS-1$
18
19
19
}
20
}
(-)a/org.eclipse.skalli.view/VAADIN/themes/simple/styles.css (+1 lines)
Lines 7-12 Link Here
7
 @import url(styles_tray.css);
7
 @import url(styles_tray.css);
8
 @import url(styles_peoplesearch.css);
8
 @import url(styles_peoplesearch.css);
9
 @import url(styles_multitext.css);
9
 @import url(styles_multitext.css);
10
 @import url(styles_multicombobox.css);
10
 
11
 
11
.v-app {
12
.v-app {
12
      background: #fff;
13
      background: #fff;
(-)a/org.eclipse.skalli.view/VAADIN/themes/simple/styles_multicombobox.css (+16 lines)
Added Link Here
1
.multicombobox-layout {
2
    
3
}
4
5
.multicombobox-line {
6
    margin-bottom: 5px;
7
}
8
9
.multicombobox-btn {
10
    margin-left: 5px;
11
    margin-top: 5px;
12
}
13
14
.multicombobox-btn .v-button-caption {
15
    font-size: x-small;
16
}
(-)a/org.eclipse.skalli.view/src/main/java/org/eclipse/skalli/view/component/MultiComboBox.java (-1 / +275 lines)
Added Link Here
0
- 
1
/*******************************************************************************
2
 * Copyright (c) 2010, 2011 SAP AG and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 *
8
 * Contributors:
9
 *     SAP AG - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.skalli.view.component;
12
13
import java.util.ArrayList;
14
import java.util.Collection;
15
import java.util.Iterator;
16
import java.util.List;
17
import java.util.UUID;
18
19
import org.apache.commons.lang.StringUtils;
20
import org.eclipse.skalli.api.java.ProjectService;
21
import org.eclipse.skalli.common.Services;
22
import org.eclipse.skalli.common.util.UUIDList;
23
import org.eclipse.skalli.model.core.Project;
24
import org.eclipse.skalli.model.ext.PropertyName;
25
26
import com.vaadin.data.Item;
27
import com.vaadin.data.Validator.InvalidValueException;
28
import com.vaadin.data.util.IndexedContainer;
29
import com.vaadin.ui.AbstractSelect;
30
import com.vaadin.ui.AbstractSelect.Filtering;
31
import com.vaadin.ui.Button;
32
import com.vaadin.ui.Button.ClickEvent;
33
import com.vaadin.ui.ComboBox;
34
import com.vaadin.ui.CustomField;
35
import com.vaadin.ui.HorizontalLayout;
36
import com.vaadin.ui.Select;
37
import com.vaadin.ui.VerticalLayout;
38
39
public class MultiComboBox extends CustomField {
40
41
    private static final long serialVersionUID = -2946220818606365985L;
42
43
    private static final String STYLE_LAYOUT = "multicombobox-layout";
44
    private static final String STYLE_LINE_LAYOUT = "multicombobox-line";
45
    private static final String STYLE_BUTTON = "multicombobox-btn";
46
47
    private UUIDList values;
48
    private VerticalLayout layout;
49
    private List<ComboBoxElement> comboBoxEntries;
50
    private String description;
51
    private boolean readOnly;
52
    private int columns;
53
54
    private static class ComboBoxElement {
55
        public ComboBoxElement(ComboBox comboBox) {
56
            this.comboBox = comboBox;
57
            comboBox.setItemCaptionPropertyId(ProjectDataSource.PROPERTY_DISPLAYNAME);
58
            comboBox.setItemCaptionMode(AbstractSelect.ITEM_CAPTION_MODE_PROPERTY);
59
            comboBox.setFilteringMode(Filtering.FILTERINGMODE_CONTAINS);
60
            comboBox.setImmediate(true);
61
            comboBox.setNewItemsAllowed(false);
62
            comboBox.setNullSelectionAllowed(true);
63
        }
64
65
        ComboBox comboBox;
66
        Button removeButton;
67
    }
68
69
    public MultiComboBox(String caption, UUIDList values) {
70
        if (values == null) {
71
            throw new IllegalArgumentException("argument 'values' must not be null");
72
        }
73
        setCaption(caption);
74
        this.values = values;
75
        init(values);
76
        layout = new VerticalLayout();
77
        layout.setStyleName(STYLE_LAYOUT);
78
        renderComboBoxes();
79
        setCompositionRoot(layout);
80
    }
81
82
    private void renderComboBoxes() {
83
        boolean hasMultipleEntries = comboBoxEntries.size() > 1;
84
        int last = comboBoxEntries.size() - 1;
85
        for (int i = 0; i <= last; ++i) {
86
            ComboBoxElement comboBoxEntry = comboBoxEntries.get(i);
87
            HorizontalLayout horLayout = new HorizontalLayout();
88
            horLayout.setStyleName(STYLE_LINE_LAYOUT);
89
            ComboBox comboBox = comboBoxEntry.comboBox;
90
            if (comboBox.getValue() == null) {
91
                comboBox.setEnabled(!readOnly);
92
            } else {
93
                comboBox.setReadOnly(readOnly);
94
            }
95
            horLayout.addComponent(comboBox);
96
97
            if (hasMultipleEntries) {
98
                Button b = createRemoveButton();
99
                comboBoxEntry.removeButton = b;
100
                horLayout.addComponent(b);
101
            }
102
            if (i == last) {
103
                horLayout.addComponent(createAddButton());
104
            }
105
106
            layout.addComponent(horLayout);
107
        }
108
    }
109
110
    private void init(UUIDList values) {
111
        comboBoxEntries = new ArrayList<ComboBoxElement>();
112
        if (values != null && !values.isEmpty()) {
113
            for (UUID value : values) {
114
                ComboBox comboBox = createComboBox(value);
115
                comboBoxEntries.add(new ComboBoxElement(comboBox));
116
            }
117
        } else {
118
            ComboBox comboBox = createComboBox(null);
119
            comboBoxEntries.add(new ComboBoxElement(comboBox));
120
        }
121
    }
122
123
    private ComboBox createComboBox(UUID uuid) {
124
        ComboBox comboBox = new ComboBox(null, new ProjectDataSource());
125
        if (description != null) {
126
            comboBox.setDescription(description);
127
        }
128
        if (uuid != null) {
129
            ProjectService projectService = Services.getRequiredService(ProjectService.class);
130
            Project project = projectService.getByUUID(uuid);
131
            comboBox.select(project);
132
        }
133
        return comboBox;
134
    }
135
136
    public void setColumns(int columns) {
137
        this.columns = columns;
138
        for (ComboBoxElement entry : comboBoxEntries) {
139
            entry.comboBox.setWidth(columns, Select.UNITS_EM);
140
        }
141
    }
142
143
    private Button createAddButton() {
144
        Button b = new Button("Add");
145
        b.setStyleName(Button.STYLE_LINK);
146
        b.addStyleName(STYLE_BUTTON);
147
        b.setDescription("Add another entry");
148
        b.setEnabled(!readOnly);
149
        b.addListener(new Button.ClickListener() {
150
            @Override
151
            public void buttonClick(ClickEvent event) {
152
                ComboBox cb = createComboBox(null);
153
                cb.setWidth(columns, Select.UNITS_EM);
154
                comboBoxEntries.add(new ComboBoxElement(cb));
155
                layout.removeAllComponents();
156
                renderComboBoxes();
157
            }
158
        });
159
        return b;
160
    }
161
162
    private Button createRemoveButton() {
163
        Button b = new Button("Remove");
164
        b.setStyleName(Button.STYLE_LINK);
165
        b.addStyleName(STYLE_BUTTON);
166
        b.setDescription("Remove this entry");
167
        b.addListener(new Button.ClickListener() {
168
            @Override
169
            public void buttonClick(ClickEvent event) {
170
                Button b = event.getButton();
171
                Iterator<ComboBoxElement> it = comboBoxEntries.iterator();
172
                while (it.hasNext()) {
173
                    ComboBoxElement element = it.next();
174
                    if (element.removeButton == b) {
175
                        it.remove();
176
                        break;
177
                    }
178
                }
179
                layout.removeAllComponents();
180
                renderComboBoxes();
181
            }
182
        });
183
        return b;
184
    }
185
186
    @Override
187
    public void setDescription(String description) {
188
        this.description = description;
189
        for (ComboBoxElement element : comboBoxEntries) {
190
            element.comboBox.setDescription(description);
191
        }
192
    }
193
194
    @Override
195
    public Object getValue() {
196
        UUIDList uuid = new UUIDList(comboBoxEntries.size());
197
        copyValues(uuid);
198
        return uuid;
199
    }
200
201
    @Override
202
    public void commit() throws SourceException, InvalidValueException {
203
        values.clear();
204
        copyValues(values);
205
    }
206
207
    private void copyValues(UUIDList values) {
208
        for (ComboBoxElement entry : comboBoxEntries) {
209
            Project project = (Project) entry.comboBox.getValue();
210
            if (project == null) {
211
                return;
212
            }
213
            UUID value = project.getUuid();
214
            if (StringUtils.isNotBlank(value.toString())) {
215
                values.add(value);
216
            }
217
        }
218
    }
219
220
    @Override
221
    public Class<?> getType() {
222
        return Collection.class;
223
    }
224
225
    private static class ProjectDataSource extends IndexedContainer {
226
227
        private static final long serialVersionUID = 8192530422436522676L;
228
229
        @PropertyName(position = 0)
230
        public static final Object PROPERTY_DISPLAYNAME = "displayName";
231
232
        public ProjectDataSource() {
233
            super();
234
            addContainerProperty(Project.PROPERTY_NAME, String.class, null);
235
            addContainerProperty(Project.PROPERTY_PROJECTID, String.class, null);
236
            addContainerProperty(PROPERTY_DISPLAYNAME, String.class, null);
237
238
            ProjectService projectService = Services.getRequiredService(ProjectService.class);
239
            List<Project> projects = projectService.getAll();
240
            for (Project project : projects) {
241
                addItem(project);
242
            }
243
            sort(new Object[] { Project.PROPERTY_NAME, Project.PROPERTY_PROJECTID }, new boolean[] { true, true });
244
        }
245
246
        private Item addItem(Project project) {
247
            // item key = project instance
248
            Item item = getItem(project);
249
            if (item == null) {
250
                item = super.addItem(project); // IndexedContainer#addItem return null, if entry already exists!!!
251
            }
252
            if (item != null) {
253
                String projectId = project.getProjectId();
254
                String name = project.getName();
255
                item.getItemProperty(Project.PROPERTY_NAME).setValue(name);
256
                item.getItemProperty(Project.PROPERTY_PROJECTID).setValue(projectId);
257
                item.getItemProperty(PROPERTY_DISPLAYNAME).setValue(name + " <" + projectId + ">");
258
            }
259
            return item;
260
        }
261
    }
262
263
    @Override
264
    public void setReadOnly(boolean readOnly) {
265
        this.readOnly = readOnly;
266
        layout.removeAllComponents();
267
        renderComboBoxes();
268
    }
269
270
    @Override
271
    public boolean isReadOnly() {
272
        return readOnly;
273
    }
274
275
}

Return to bug 350359