Make multi terms more robust when an existing term has changed.
[gpl/argeo-suite.git] / core / org.argeo.entity.ui / src / org / argeo / entity / ui / forms / MultiTermsPart.java
1 package org.argeo.entity.ui.forms;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 import javax.jcr.Item;
7
8 import org.apache.commons.logging.Log;
9 import org.apache.commons.logging.LogFactory;
10 import org.argeo.cms.ui.forms.FormStyle;
11 import org.argeo.cms.ui.util.CmsUiUtils;
12 import org.argeo.cms.ui.viewers.EditablePart;
13 import org.argeo.cms.ui.widgets.ContextOverlay;
14 import org.argeo.eclipse.ui.MouseDoubleClick;
15 import org.argeo.eclipse.ui.MouseDown;
16 import org.argeo.eclipse.ui.Selected;
17 import org.argeo.entity.Term;
18 import org.argeo.entity.TermsManager;
19 import org.argeo.jcr.Jcr;
20 import org.eclipse.swt.SWT;
21 import org.eclipse.swt.events.FocusEvent;
22 import org.eclipse.swt.events.FocusListener;
23 import org.eclipse.swt.layout.GridLayout;
24 import org.eclipse.swt.layout.RowLayout;
25 import org.eclipse.swt.widgets.Composite;
26 import org.eclipse.swt.widgets.Control;
27 import org.eclipse.swt.widgets.Label;
28 import org.eclipse.swt.widgets.Text;
29 import org.eclipse.swt.widgets.ToolBar;
30 import org.eclipse.swt.widgets.ToolItem;
31
32 /** {@link EditablePart} for multiple terms. */
33 public class MultiTermsPart extends AbstractTermsPart {
34         private static final long serialVersionUID = -4961135649177920808L;
35         private final static Log log = LogFactory.getLog(MultiTermsPart.class);
36
37         public MultiTermsPart(Composite parent, int style, Item item, TermsManager termsManager, String typology) {
38                 super(parent, style, item, termsManager, typology);
39         }
40
41         @Override
42         protected Control createControl(Composite box, String style) {
43                 Composite placeholder = new Composite(box, SWT.NONE);
44                 RowLayout rl = new RowLayout(SWT.HORIZONTAL);
45                 rl.wrap = true;
46                 placeholder.setLayout(rl);
47                 List<Term> currentValue = getValue();
48                 if (currentValue != null && !currentValue.isEmpty())
49                         for (Term value : currentValue) {
50                                 Composite block = new Composite(placeholder, SWT.NONE);
51                                 block.setLayout(CmsUiUtils.noSpaceGridLayout(3));
52                                 Label lbl = new Label(block, SWT.SINGLE);
53                                 String display = getTermLabel(value);
54                                 lbl.setText(display);
55                                 CmsUiUtils.style(lbl, style == null ? FormStyle.propertyText.style() : style);
56                                 if (editable)
57                                         lbl.addMouseListener((MouseDoubleClick) (e) -> {
58                                                 startEditing();
59                                         });
60                                 if (isEditing()) {
61                                         ToolBar toolBar = new ToolBar(block, SWT.HORIZONTAL);
62                                         ToolItem deleteItem = new ToolItem(toolBar, SWT.FLAT);
63                                         styleDelete(deleteItem);
64                                         deleteItem.addSelectionListener((Selected) (e) -> {
65                                                 // we retrieve them again here because they may have changed
66                                                 List<Term> curr = getValue();
67                                                 List<Term> newValue = new ArrayList<>();
68                                                 for (Term v : curr) {
69                                                         if (!v.equals(value))
70                                                                 newValue.add(v);
71                                                 }
72                                                 setValue(newValue);
73                                                 block.dispose();
74                                                 layout(true, true);
75                                         });
76
77                                 }
78                         }
79                 else {// empty
80                         if (editable && !isEditing()) {
81                                 ToolBar toolBar = new ToolBar(placeholder, SWT.HORIZONTAL);
82                                 ToolItem addItem = new ToolItem(toolBar, SWT.FLAT);
83                                 styleAdd(addItem);
84                                 addItem.addSelectionListener((Selected) (e) -> {
85                                         startEditing();
86                                 });
87                         }
88                 }
89
90                 if (isEditing()) {
91                         Composite block = new Composite(placeholder, SWT.NONE);
92                         block.setLayout(CmsUiUtils.noSpaceGridLayout(3));
93
94                         createHighlight(block);
95
96                         Text txt = new Text(block, SWT.SINGLE | SWT.BORDER);
97                         txt.setLayoutData(CmsUiUtils.fillWidth());
98 //                      txt.setMessage("[new]");
99
100                         CmsUiUtils.style(txt, style == null ? FormStyle.propertyText.style() : style);
101
102                         ToolBar toolBar = new ToolBar(block, SWT.HORIZONTAL);
103                         ToolItem cancelItem = new ToolItem(toolBar, SWT.FLAT);
104                         styleCancel(cancelItem);
105                         cancelItem.addSelectionListener((Selected) (e) -> {
106                                 stopEditing();
107                         });
108
109                         ContextOverlay contextOverlay = new ContextOverlay(txt, SWT.NONE) {
110                                 private static final long serialVersionUID = -7980078594405384874L;
111
112                                 @Override
113                                 protected void onHide() {
114                                         stopEditing();
115                                 }
116                         };
117                         contextOverlay.setLayout(new GridLayout());
118                         // filter
119                         txt.addModifyListener((e) -> {
120                                 String filter = txt.getText().toLowerCase();
121                                 if ("".equals(filter.trim()))
122                                         filter = null;
123                                 refresh(contextOverlay, filter, txt);
124                         });
125                         txt.addFocusListener(new FocusListener() {
126                                 private static final long serialVersionUID = -6024501573409619949L;
127
128                                 @Override
129                                 public void focusLost(FocusEvent event) {
130 //                                      if (!contextOverlay.isDisposed() && contextOverlay.isShellVisible())
131 //                                              getDisplay().asyncExec(() -> stopEditing());
132                                 }
133
134                                 @Override
135                                 public void focusGained(FocusEvent event) {
136                                         // txt.setText("");
137                                         if (!contextOverlay.isDisposed() && !contextOverlay.isShellVisible())
138                                                 refresh(contextOverlay, null, txt);
139                                 }
140                         });
141                         layout(new Control[] { txt });
142                         // getDisplay().asyncExec(() -> txt.setFocus());
143                 }
144                 return placeholder;
145         }
146
147         @Override
148         protected void refresh(ContextOverlay contextArea, String filter, Text txt) {
149                 CmsUiUtils.clear(contextArea);
150                 List<? extends Term> terms = termsManager.listAllTerms(typology.getId());
151                 List<Term> currentValue = getValue();
152                 terms: for (Term term : terms) {
153                         if (currentValue != null && currentValue.contains(term))
154                                 continue terms;
155                         String display = getTermLabel(term);
156                         if (filter != null && !display.toLowerCase().contains(filter))
157                                 continue terms;
158                         Label termL = new Label(contextArea, SWT.WRAP);
159                         termL.setText(display);
160                         processTermListLabel(term, termL);
161                         if (isTermSelectable(term))
162                                 termL.addMouseListener((MouseDown) (e) -> {
163                                         List<Term> newValue = new ArrayList<>();
164                                         List<Term> curr = getValue();
165                                         if (currentValue != null)
166                                                 newValue.addAll(curr);
167                                         newValue.add(term);
168                                         setValue(newValue);
169                                         contextArea.hide();
170                                         stopEditing();
171                                 });
172                 }
173                 contextArea.show();
174         }
175
176         protected List<Term> getValue() {
177                 String property = typology.getId();
178                 List<String> curr = Jcr.getMultiple(getNode(), property);
179                 List<Term> res = new ArrayList<>();
180                 if (curr != null)
181                         terms: for (String str : curr) {
182                                 Term term = termsManager.getTerm(str);
183                                 if (term == null) {
184                                         log.warn("Ignoring term " + str + " as it was not found.");
185                                         continue terms;
186                                 }
187                                 res.add(term);
188                         }
189                 return res;
190         }
191
192         protected void setValue(List<Term> value) {
193                 String property = typology.getId();
194                 List<String> ids = new ArrayList<>();
195                 for (Term term : value) {
196                         ids.add(term.getId());
197                 }
198                 Jcr.set(getNode(), property, ids);
199                 Jcr.save(getNode());
200         }
201
202 }