001/*
002 * ModeShape (http://www.modeshape.org)
003 *
004 * Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
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 */
016package org.modeshape.web.client.peditor;
017
018import com.google.gwt.user.client.rpc.AsyncCallback;
019import com.smartgwt.client.types.Alignment;
020import com.smartgwt.client.types.MultipleAppearance;
021import com.smartgwt.client.types.VerticalAlignment;
022import com.smartgwt.client.util.SC;
023import com.smartgwt.client.widgets.Button;
024import com.smartgwt.client.widgets.Label;
025import com.smartgwt.client.widgets.events.ClickHandler;
026import com.smartgwt.client.widgets.form.DynamicForm;
027import com.smartgwt.client.widgets.form.fields.SelectItem;
028import com.smartgwt.client.widgets.form.fields.events.ClickEvent;
029import com.smartgwt.client.widgets.layout.VLayout;
030import java.util.ArrayList;
031import org.modeshape.web.client.contents.Contents;
032import org.modeshape.web.shared.Align;
033import org.modeshape.web.shared.Columns;
034import org.modeshape.web.shared.JcrNode;
035
036/**
037 * Default value editor which is using text representation of the value.
038 * 
039 * @author kulikov
040 */
041public class MixinValueEditor extends BaseEditor implements ValueEditor<String> {
042    //form title
043    private final static String TITLE = "Modify property value";
044    
045    //form dimensions
046    private final static int WIDTH = 430;
047    private final static int HEIGHT = 350;
048    
049    //form fields
050    private final SelectItem mixTypes = new SelectItem("");
051    private final SelectItem selectedTypes = new SelectItem("");
052    
053    //'controller' - provides access to business logic
054    private final Contents contents;
055    
056    //node/property references
057    private JcrNode node;
058    private String name;
059    
060    private String[] allTypes;
061    private String[] nodeTypes;
062    private String[] originalNodeTypes;
063    
064    /**
065     * Creates this property editor.
066     * 
067     * @param contents Contents view form.
068     */
069    public MixinValueEditor(Contents contents) {
070        super(TITLE);
071        this.contents = contents;
072
073        setWidth(WIDTH);
074        setHeight(HEIGHT);                
075        
076        Columns h1 = new Columns(Align.CENTER, Align.CENTER);
077        h1.setHeight(15);
078        
079        Label l1 = new Label();
080        l1.setWidth(150);
081        l1.setContents("Mixin Types");
082
083        Label l2 = new Label();
084        l2.setWidth(100);
085        l2.setContents("");
086        
087        Label l3 = new Label();
088        l3.setWidth(150);
089        l3.setContents("Node's types");
090        
091        h1.addMember(l1);
092        h1.addMember(l2);
093        h1.addMember(l3);
094        
095        addMember(h1);
096        
097        Columns layout = new Columns(Align.CENTER, Align.CENTER);
098        layout.setWidth100();
099
100        mixTypes.setMultiple(true);
101        mixTypes.setMultipleAppearance(MultipleAppearance.GRID);
102        mixTypes.setWidth(150);
103        mixTypes.setHeight(200);
104        
105        selectedTypes.setMultiple(true);
106        selectedTypes.setMultipleAppearance(MultipleAppearance.GRID);
107        selectedTypes.setWidth(150);
108        selectedTypes.setHeight(200);
109        
110        DynamicForm f1 = new DynamicForm();
111        f1.setItems(mixTypes);
112        f1.setWidth(150);
113        f1.setHeight(200);
114        
115        DynamicForm f2 = new DynamicForm();
116        f2.setItems(selectedTypes);
117        f2.setWidth(150);
118        f2.setHeight(200);
119        
120        VLayout buttons = new VLayout();
121        buttons.setLayoutAlign(Alignment.CENTER);
122        buttons.setDefaultLayoutAlign(Alignment.CENTER);
123        buttons.setAlign(Alignment.CENTER);        
124        buttons.setLayoutAlign(VerticalAlignment.CENTER);        
125        buttons.setWidth(50);
126        
127        layout.addMember(f1);
128        layout.addMember(buttons);
129        layout.addMember(f2);
130        
131        Button b1 = new Button(">>");
132        b1.setWidth(30);
133        b1.addClickHandler(new ClickHandler() {
134            @Override
135            public void onClick(com.smartgwt.client.widgets.events.ClickEvent event) {
136                allTypes = remove(allTypes, mixTypes.getValueAsString());
137                nodeTypes = add(nodeTypes, mixTypes.getValueAsString());
138                updateLists();
139            }
140        });
141        
142        Button b2 = new Button("<<");
143        b2.setWidth(30);
144        b2.addClickHandler(new ClickHandler() {
145            @Override
146            public void onClick(com.smartgwt.client.widgets.events.ClickEvent event) {
147                nodeTypes = remove(nodeTypes, selectedTypes.getValueAsString());
148                allTypes = add(allTypes, selectedTypes.getValueAsString());
149                updateLists();
150            }
151        });
152        
153        buttons.addMember(b1);
154        buttons.addMember(b2);
155        
156        addMember(layout);
157        
158        Columns h3 = new Columns(Align.RIGHT, Align.CENTER);
159        h3.setHeight(50);
160        
161        Button okButton = new Button("OK");
162        okButton.addClickHandler(new ClickHandler() {
163            @Override
164            public void onClick(com.smartgwt.client.widgets.events.ClickEvent event) {
165                onConfirm(null);
166                hide();
167            }
168        });
169        
170        Button cancelButton = new Button("Cancel");
171        cancelButton.addClickHandler(new ClickHandler() {
172            @Override
173            public void onClick(com.smartgwt.client.widgets.events.ClickEvent event) {
174                hide();
175            }
176        });
177        
178        h3.addMember(okButton);
179        h3.addMember(cancelButton);
180        
181        addMember(h3);
182        
183    }
184    
185    @Override
186    public void showModal() {
187        contents.jcrService().getMixinTypes(contents.repository(), contents.workspace(),
188                false, new AsyncCallback<String[]>() {
189            @Override
190            public void onFailure(Throwable caught) {
191                SC.say(caught.getMessage());
192            }
193
194            @Override
195            public void onSuccess(String[] result) {
196                allTypes = result;
197                updateLists();
198                MixinValueEditor.super.showModal();
199            }
200        });
201        
202    }
203    
204    private void updateLists() {
205        mixTypes.setValueMap(diff(allTypes, nodeTypes));
206        selectedTypes.setValueMap(diff(nodeTypes, allTypes));
207    }
208    
209    private String[] parseValues(String value) {
210        if (value.equalsIgnoreCase("N/A")) {
211            return new String[]{};
212        }
213        return value.split(",");
214    }
215    
216    @Override
217    public void setValue(JcrNode node, String name, String value) {
218        this.node = node;
219        this.name = name;
220        
221        nodeTypes = parseValues(value);
222        originalNodeTypes = parseValues(value);
223        
224        showModal();
225    }
226
227    private String[] remove(String[] values, String value) {
228        String[] res = new String[values.length - 1];
229        int j = 0;
230        for (int i = 0; i < values.length; i++) {
231            if (!values[i].equalsIgnoreCase(value)) {
232                res[j++] = values[i];
233            }
234        }
235        return res;
236    }
237    
238    private String[] add(String[] values, String value) {
239        String[] res = new String[values.length + 1];
240        for (int i = 0; i < values.length; i++) {
241            res[i] = values[i];
242        }
243        res[values.length] = value;
244        return res;
245    }
246
247    @SuppressWarnings("unchecked")
248    private String[] diff(String[] a, String[] b) {
249        ArrayList<String> list = new ArrayList();
250        for (int i = 0; i < a.length; i++) {
251            boolean found = false;
252            for (int j = 0; j < b.length; j++) {
253                if (a[i].equalsIgnoreCase(b[j])) {
254                    found = true;
255                    break;
256                }
257            }
258            if (!found) list.add(a[i]);
259        }
260        String[] map = new String[list.size()];
261        list.toArray(map);
262        return map;
263    }
264    
265    @Override
266    public void onConfirm(ClickEvent event) {
267        //new types
268        for (int i = 0; i < nodeTypes.length; i++) {
269            boolean isNew = true;
270            
271            for (int j = 0; j < originalNodeTypes.length; j++) {
272                if (nodeTypes[i].equalsIgnoreCase(originalNodeTypes[j])) {
273                    isNew = false;
274                    break;
275                }
276            }
277
278            if (isNew)  contents.addMixin(nodeTypes[i]);
279        }
280        
281        //removed types
282        for (int i = 0; i < originalNodeTypes.length; i++) {
283            boolean isRemoved = false;
284            
285            for (int j = 0; j < nodeTypes.length; j++) {
286                if (originalNodeTypes[i].equalsIgnoreCase(nodeTypes[j])) {
287                    isRemoved = false;
288                    break;
289                }
290            }
291
292            if (isRemoved)  contents.removeMixin(nodeTypes[i]);
293        }
294    }
295 
296}