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