001/*
002 * (C) Copyright 2006-2008 Nuxeo SA (http://nuxeo.com/) and others.
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 *
016 * Contributors:
017 *     Alexandre Russel
018 *
019 * $Id$
020 */
021
022package org.nuxeo.ecm.platform.annotations.gwt.client.view;
023
024import java.util.HashMap;
025import java.util.HashSet;
026import java.util.List;
027import java.util.Map;
028import java.util.Set;
029
030import org.nuxeo.ecm.platform.annotations.gwt.client.annotea.RDFConstant;
031import org.nuxeo.ecm.platform.annotations.gwt.client.configuration.AnnotationDefinition;
032import org.nuxeo.ecm.platform.annotations.gwt.client.configuration.AnnotationFilter;
033import org.nuxeo.ecm.platform.annotations.gwt.client.configuration.WebConfiguration;
034import org.nuxeo.ecm.platform.annotations.gwt.client.configuration.filter.InMenuFilter;
035import org.nuxeo.ecm.platform.annotations.gwt.client.controler.AnnotationController;
036import org.nuxeo.ecm.platform.annotations.gwt.client.model.Annotation;
037import org.nuxeo.ecm.platform.annotations.gwt.client.model.AnnotationChangeListener;
038import org.nuxeo.ecm.platform.annotations.gwt.client.model.AnnotationModel;
039import org.nuxeo.ecm.platform.annotations.gwt.client.util.AnnotationUtils;
040import org.nuxeo.ecm.platform.annotations.gwt.client.view.i18n.TranslationConstants;
041import org.nuxeo.ecm.platform.annotations.gwt.client.view.i18n.TranslationMessages;
042
043import com.google.gwt.core.client.GWT;
044import com.google.gwt.user.client.Window;
045import com.google.gwt.user.client.ui.ChangeListener;
046import com.google.gwt.user.client.ui.ClickListener;
047import com.google.gwt.user.client.ui.Frame;
048import com.google.gwt.user.client.ui.Grid;
049import com.google.gwt.user.client.ui.HTML;
050import com.google.gwt.user.client.ui.HorizontalPanel;
051import com.google.gwt.user.client.ui.Image;
052import com.google.gwt.user.client.ui.Label;
053import com.google.gwt.user.client.ui.ListBox;
054import com.google.gwt.user.client.ui.PushButton;
055import com.google.gwt.user.client.ui.VerticalPanel;
056import com.google.gwt.user.client.ui.Widget;
057
058/**
059 * @author Alexandre Russel
060 */
061public class AnnotationManagerPanel extends VerticalPanel implements AnnotationChangeListener {
062
063    private static final String CLASS_NAME = "annotationManagerPanel";
064
065    private final WebConfiguration webConfiguration;
066
067    private AnnotationController controller;
068
069    private AnnotationModel model;
070
071    private VerticalPanel shownAnnotation = new VerticalPanel();
072
073    private Map<String, Integer> selectedParams = new HashMap<String, Integer>();
074
075    private HorizontalPanel selectedRow;
076
077    public AnnotationManagerPanel(AnnotationController controller, WebConfiguration webConfiguration) {
078        this.controller = controller;
079        this.webConfiguration = webConfiguration;
080
081        setStyleName(CLASS_NAME);
082    }
083
084    public void onChange(AnnotationModel model, ChangeEvent ce) {
085        this.model = model;
086        if (ce == ChangeEvent.annotationList) {
087            update();
088        }
089    }
090
091    private void update() {
092        clear();
093        addAnnotationsActionList();
094        addFiltersToolbar();
095        addAnnotationsList();
096    }
097
098    private void addFiltersToolbar() {
099        HorizontalPanel toolBar = new HorizontalPanel();
100        List<AnnotationFilter> filters = webConfiguration.getFilters();
101        for (final AnnotationFilter filter : filters) {
102            PushButton button = new PushButton(new Image(filter.getIcon()), new ClickListener() {
103                public void onClick(Widget sender) {
104                    model.setFilter(filter);
105                }
106            });
107            button.setTitle(filter.getName());
108            toolBar.add(button);
109        }
110
111        Label spacer = new Label(" ");
112        toolBar.add(spacer);
113        toolBar.setCellWidth(spacer, "100%");
114
115        List<AnnotationDefinition> inMenuAnnos = webConfiguration.getAnnotationDefinitions(new InMenuFilter());
116        TranslationMessages translationMessages = GWT.create(TranslationMessages.class);
117        for (AnnotationDefinition annotationDef : inMenuAnnos) {
118            final String annName = annotationDef.getName();
119            PushButton button = new PushButton(new Image(annotationDef.getListIcon()), new ClickListener() {
120                public void onClick(Widget sender) {
121                    new AnnotationListPopup(annName, model.filterAnnotations(new AnnotationFilter("", "", annName,
122                            null, null)), webConfiguration).show();
123                }
124            });
125            button.setTitle(translationMessages.viewAnnotations(annotationDef.getName()));
126            toolBar.add(button);
127        }
128        for (AnnotationDefinition annotationDef : inMenuAnnos) {
129            final String annName = annotationDef.getName();
130            final String annType = annotationDef.getType();
131            PushButton button = new PushButton(new Image(annotationDef.getCreateIcon()), new ClickListener() {
132                public void onClick(Widget sender) {
133                    controller.createNewAnnotation("#xpointer(null-range)");
134                    NewAnnotationPopup popup = new NewAnnotationPopup(null, controller, false, annType, annName);
135                    popup.show();
136
137                }
138            });
139            button.setTitle(translationMessages.addAnnotation(annotationDef.getName()));
140            toolBar.add(button);
141        }
142        add(toolBar);
143
144        final AnnotationFilter currentFilter = model.getFilter();
145        if (currentFilter != null && !currentFilter.getParameters().isEmpty()) {
146            List<String> parameters = currentFilter.getParameters();
147            Map<String, String> labels = webConfiguration.getFieldLabels();
148            Grid filterGrid = new Grid(parameters.size(), 2);
149            filterGrid.setStyleName("filterGrid");
150            filterGrid.getColumnFormatter().setWidth(1, "100%");
151            for (int i = 0; i < parameters.size(); i++) {
152                final String parameter = parameters.get(i);
153
154                filterGrid.setWidget(i, 0, new Label(
155                        (labels.containsKey(parameter) ? labels.get(parameter) : parameter) + ": "));
156                final ListBox filterListBox = new ListBox();
157                filterListBox.setStyleName("filterListBox");
158                filterListBox.addItem("All");
159                Set<String> values = new HashSet<String>();
160                for (Annotation annotation : model.getUnfilteredAnnotations()) {
161                    if (parameter.equals(RDFConstant.R_TYPE)) {
162                        values.add(annotation.getShortType());
163                    } else if (parameter.equals(RDFConstant.D_CREATOR)) {
164                        values.add(annotation.getAuthor());
165                    } else {
166                        String value = annotation.getFields().get(parameter);
167                        if (value != null) {
168                            values.add(value);
169                        }
170                    }
171                }
172                for (String value : values) {
173                    filterListBox.addItem(value);
174                }
175                if (selectedParams.containsKey(parameter)) {
176                    filterListBox.setSelectedIndex(selectedParams.get(parameter).intValue());
177                }
178                if (parameter.equals(RDFConstant.R_TYPE)) {
179                    filterListBox.addChangeListener(new ChangeListener() {
180                        public void onChange(Widget arg0) {
181                            int selectedIndex = filterListBox.getSelectedIndex();
182                            if (selectedIndex == 0) {
183                                currentFilter.setType(null);
184                            } else {
185                                currentFilter.setType(filterListBox.getItemText(selectedIndex));
186                            }
187                            selectedParams.put(parameter, Integer.valueOf(selectedIndex));
188                            model.setFilter(currentFilter);
189                        }
190                    });
191                } else if (parameter.equals(RDFConstant.D_CREATOR)) {
192                    filterListBox.addChangeListener(new ChangeListener() {
193                        public void onChange(Widget arg0) {
194                            int selectedIndex = filterListBox.getSelectedIndex();
195                            if (selectedIndex == 0) {
196                                currentFilter.setAuthor(null);
197                            } else {
198                                currentFilter.setAuthor(filterListBox.getItemText(selectedIndex));
199                            }
200                            selectedParams.put(parameter, Integer.valueOf(selectedIndex));
201                            model.setFilter(currentFilter);
202                        }
203                    });
204                } else {
205                    filterListBox.addChangeListener(new ChangeListener() {
206                        public void onChange(Widget arg0) {
207                            int selectedIndex = filterListBox.getSelectedIndex();
208                            if (selectedIndex == 0) {
209                                currentFilter.removeField(parameter);
210                            } else {
211                                currentFilter.setField(parameter, filterListBox.getItemText(selectedIndex));
212                            }
213                            selectedParams.put(parameter, Integer.valueOf(selectedIndex));
214                            model.setFilter(currentFilter);
215                        }
216                    });
217                }
218                filterGrid.setWidget(i, 1, filterListBox);
219            }
220            add(filterGrid);
221        }
222    }
223
224    private void addAnnotationsActionList() {
225        add(new AnnotationActionsBanner(controller));
226    }
227
228    private void addAnnotationsList() {
229        HorizontalPanel hpSelected = null;
230        int selectedAnnotationIndex = -1;
231
232        VerticalPanel vp = new VerticalPanel();
233        vp.setStylePrimaryName("annotation-list");
234        final List<Annotation> annotations = model.getAnnotations();
235        for (int y = 0; y < annotations.size(); y++) {
236            final int row = y;
237            Annotation annotation = annotations.get(y);
238            final HorizontalPanel hp = new HorizontalPanel();
239            hp.setWidth("100%");
240            AnnotationDefinition def = webConfiguration.getAnnotationDefinition(annotation.getShortType());
241
242            Image icon = new Image(def.getIcon());
243            icon.addClickListener(new ClickListener() {
244                public void onClick(Widget sender) {
245                    updateSelectedAnnotation(row);
246                    selectAnnotation(hp, row);
247                }
248            });
249            hp.add(icon);
250
251            Label date = new Label(annotation.getFormattedDate());
252            date.addClickListener(new ClickListener() {
253                public void onClick(Widget sender) {
254                    updateSelectedAnnotation(row);
255                    selectAnnotation(hp, row);
256                }
257            });
258            hp.add(date);
259
260            // add the displayed fields
261            Set<String> displayedFields = webConfiguration.getDisplayedFields();
262            for (String displayedField : displayedFields) {
263                String value = annotation.getFields().get(displayedField);
264                Label l = new Label(value != null ? value : " ");
265                l.addClickListener(new ClickListener() {
266                    public void onClick(Widget sender) {
267                        updateSelectedAnnotation(row);
268                        selectAnnotation(hp, row);
269                    }
270                });
271                hp.add(l);
272            }
273            vp.add(hp);
274
275            if (getSelectedAnnotationIndex() == row) {
276                hpSelected = hp;
277                selectedAnnotationIndex = row;
278            }
279        }
280        add(vp);
281
282        if (hpSelected != null && selectedAnnotationIndex > -1) {
283            selectAnnotation(hpSelected, selectedAnnotationIndex);
284        }
285    }
286
287    private native void updateSelectedAnnotation(int index) /*-{
288                                                            if (typeof top['updateSelectedAnnotation'] != "undefined") {
289                                                            top['updateSelectedAnnotation'](index);
290                                                            }
291                                                            }-*/;
292
293    private void selectAnnotation(HorizontalPanel hp, int index) {
294        setSelectedannotationIndex(index);
295        updateShownAnnotation(index);
296        updateSelectedRow(hp, index);
297    }
298
299    private native void setSelectedannotationIndex(int index) /*-{
300                                                              top['selectedAnnotationIndex'] = index;
301                                                              }-*/;
302
303    private native int getSelectedAnnotationIndex() /*-{
304                                                    if (top && typeof top['selectedAnnotationIndex'] != "undefined") {
305                                                    return top['selectedAnnotationIndex'];
306                                                    } else {
307                                                    return -1;
308                                                    }
309                                                    }-*/;
310
311    private void updateShownAnnotation(int y) {
312        remove(shownAnnotation);
313        shownAnnotation = new VerticalPanel();
314        shownAnnotation.addStyleName("shown-annotation");
315        Annotation ann = model.getAnnotations().get(y);
316        add(shownAnnotation);
317        HorizontalPanel horizontalPanel = new HorizontalPanel();
318        AnnotationDefinition def = webConfiguration.getAnnotationDefinition(ann.getShortType());
319        Image image = new Image(def.getIcon());
320        horizontalPanel.add(image);
321        horizontalPanel.add(new Label(ann.getFormattedDate()));
322
323        // add the displayed fields
324        Set<String> displayedFields = webConfiguration.getDisplayedFields();
325        for (String displayedField : displayedFields) {
326            String value = ann.getFields().get(displayedField);
327            horizontalPanel.add(new Label("•"));
328            Label valueLabel = new Label(value != null ? value : " ");
329            horizontalPanel.add(valueLabel);
330        }
331        Label spacer = new Label(" ");
332        horizontalPanel.add(spacer);
333        horizontalPanel.setCellWidth(spacer, "100%");
334
335        shownAnnotation.add(horizontalPanel);
336        if (ann.isBodyUrl()) {
337            Frame frame = new Frame();
338            frame.setUrl(ann.getBody());
339            shownAnnotation.add(frame);
340        } else {
341            HTML label = new HTML(AnnotationUtils.replaceCarriageReturns(ann.getBody()));
342            label.setStyleName("annotation-body");
343            shownAnnotation.add(label);
344        }
345    }
346
347    protected void updateSelectedRow(HorizontalPanel hp, final int index) {
348        if (selectedRow != null) {
349            selectedRow.removeStyleName("selectedAnnotationInList");
350            selectedRow.remove(selectedRow.getWidgetCount() - 1);
351        }
352        hp.setStyleName("selectedAnnotationInList");
353
354        Image deleteImage = new Image("icons/delete.png");
355        deleteImage.addClickListener(new ClickListener() {
356            public void onClick(Widget sender) {
357                TranslationConstants translationConstants = GWT.create(TranslationConstants.class);
358                if (Window.confirm(translationConstants.menuConfirmDelete())) {
359                    controller.deleteAnnotation(index);
360                    setSelectedannotationIndex(-1);
361                }
362            }
363        });
364        hp.add(deleteImage);
365
366        selectedRow = hp;
367    }
368
369}