001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.ui.sitemap;
029
030import org.opencms.file.CmsObject;
031import org.opencms.file.CmsResource;
032import org.opencms.file.CmsResourceFilter;
033import org.opencms.gwt.CmsIconUtil;
034import org.opencms.gwt.shared.CmsGwtConstants;
035import org.opencms.i18n.CmsLocaleGroup;
036import org.opencms.i18n.CmsLocaleGroupService;
037import org.opencms.main.CmsException;
038import org.opencms.main.CmsLog;
039import org.opencms.main.OpenCms;
040import org.opencms.site.CmsSite;
041import org.opencms.ui.A_CmsUI;
042import org.opencms.ui.CmsVaadinUtils;
043import org.opencms.ui.FontOpenCms;
044import org.opencms.ui.Messages;
045import org.opencms.ui.components.CmsErrorDialog;
046import org.opencms.ui.components.OpenCmsTheme;
047import org.opencms.util.CmsUUID;
048import org.opencms.workplace.explorer.CmsResourceUtil;
049
050import java.util.Collection;
051import java.util.List;
052import java.util.Locale;
053
054import org.apache.commons.logging.Log;
055
056import com.google.common.collect.Lists;
057import com.vaadin.server.Resource;
058import com.vaadin.ui.CssLayout;
059import com.vaadin.ui.JavaScript;
060import com.vaadin.ui.Notification;
061import com.vaadin.v7.data.Property.ValueChangeEvent;
062import com.vaadin.v7.data.Property.ValueChangeListener;
063import com.vaadin.v7.ui.ComboBox;
064import com.vaadin.v7.ui.VerticalLayout;
065
066/**
067 * View used to compare sitemaps across locales.<p>
068 */
069public class CmsLocaleComparePanel extends VerticalLayout implements I_CmsLocaleCompareContext {
070
071    /** Icon for the main locale option in select boxes. */
072    public static final Resource MAIN_LOCALE_ICON = FontOpenCms.CIRCLE_INFO;
073
074    /** The logger instance for this class. */
075    private static final Log LOG = CmsLog.getLog(CmsLocaleComparePanel.class);
076
077    /** The serial version id. */
078    private static final long serialVersionUID = 1L;
079
080    /** The parent layout of the tree. */
081    protected CssLayout m_treeContainer = new CssLayout();
082
083    /** The selected comparison locale. */
084    private Locale m_comparisonLocale;
085
086    /** The comparison locale selector. */
087    private ComboBox m_comparisonLocaleSelector;
088
089    /** The current root of the tree. */
090    private CmsResource m_currentRoot;
091
092    /** Flag which is set while the user switches one of the locales. */
093    private boolean m_handlingLocaleChange;
094
095    /** The root locale (locale of the root resource). */
096    private Locale m_rootLocale;
097
098    /** The root locale selector. */
099    private ComboBox m_rootLocaleSelector;
100
101    /**
102     * Creates a new instance.<p>
103     *
104     * @param id the id of a sitemap entry
105     */
106    public CmsLocaleComparePanel(String id) {
107
108        super();
109        Locale locale = OpenCms.getWorkplaceManager().getWorkplaceLocale(A_CmsUI.getCmsObject());
110        A_CmsUI.get().setLocale(locale);
111        try {
112            initialize(new CmsUUID(id), null);
113        } catch (CmsException e) {
114            LOG.error(e.getLocalizedMessage(), e);
115            CmsErrorDialog.showErrorDialog(e);
116        }
117    }
118
119    /**
120     * @see org.opencms.ui.sitemap.I_CmsLocaleCompareContext#getComparisonLocale()
121     */
122    public Locale getComparisonLocale() {
123
124        return m_comparisonLocale;
125
126    }
127
128    /**
129     * Gets the locales selectable as comparison locales.<p>
130     *
131     * @return the possible comparison locales
132     */
133    public List<Locale> getComparisonLocales() {
134
135        CmsObject cms = A_CmsUI.getCmsObject();
136        cms.getLocaleGroupService();
137        List<Locale> result = CmsLocaleGroupService.getPossibleLocales(cms, m_currentRoot);
138        return result;
139    }
140
141    /**
142     * @see org.opencms.ui.sitemap.I_CmsLocaleCompareContext#getLocaleGroup()
143     */
144    public CmsLocaleGroup getLocaleGroup() {
145
146        try {
147            CmsObject cms = A_CmsUI.getCmsObject();
148            CmsLocaleGroupService service = cms.getLocaleGroupService();
149            return service.readLocaleGroup(m_currentRoot);
150        } catch (Exception e) {
151            LOG.error(e.getLocalizedMessage(), e);
152            return null;
153        }
154
155    }
156
157    /**
158     * @see org.opencms.ui.sitemap.I_CmsLocaleCompareContext#getRoot()
159     */
160    public CmsResource getRoot() {
161
162        return m_currentRoot;
163    }
164
165    /**
166     * @see org.opencms.ui.sitemap.I_CmsLocaleCompareContext#getRootLocale()
167     */
168    public Locale getRootLocale() {
169
170        return m_rootLocale;
171    }
172
173    /**
174     * Initializes the locale comparison view.<p>
175     *
176     * @param id the structure id of the currrent sitemap root entry
177     * @param initialComparisonLocale if not null, the initially selected ccomparison locale
178     *
179     * @throws CmsException if something goes wrong
180     */
181    public void initialize(CmsUUID id, Locale initialComparisonLocale) throws CmsException {
182
183        removeAllComponents();
184        CmsObject cms = A_CmsUI.getCmsObject();
185        CmsResource res = cms.readResource(id);
186        m_currentRoot = res;
187        CmsSite site = OpenCms.getSiteManager().getSiteForRootPath(res.getRootPath());
188
189        Locale rootLocale = OpenCms.getLocaleManager().getDefaultLocale(cms, res);
190        m_rootLocale = rootLocale;
191        Locale mainLocale = site.getMainTranslationLocale(null);
192        List<Locale> secondaryLocales = site.getSecondaryTranslationLocales();
193
194        List<Locale> possibleLocaleSelections = getMainLocaleSelectOptions(cms, res, mainLocale, secondaryLocales);
195        m_rootLocaleSelector = new ComboBox();
196        m_rootLocaleSelector.addStyleName("o-sitemap-localeselect");
197        m_rootLocaleSelector.setNullSelectionAllowed(false);
198        for (Locale selectableLocale : possibleLocaleSelections) {
199            m_rootLocaleSelector.addItem(selectableLocale);
200            m_rootLocaleSelector.setItemIcon(selectableLocale, FontOpenCms.SPACE);
201            m_rootLocaleSelector.setItemCaption(
202                selectableLocale,
203                selectableLocale.getDisplayName(A_CmsUI.get().getLocale()));
204        }
205        m_rootLocaleSelector.setItemIcon(mainLocale, MAIN_LOCALE_ICON);
206        m_rootLocaleSelector.setValue(m_rootLocale);
207        m_rootLocaleSelector.addValueChangeListener(new ValueChangeListener() {
208
209            private static final long serialVersionUID = 1L;
210
211            @SuppressWarnings("synthetic-access")
212            public void valueChange(ValueChangeEvent event) {
213
214                if (!m_handlingLocaleChange) {
215                    m_handlingLocaleChange = true;
216                    try {
217                        Locale newLocale = (Locale)(event.getProperty().getValue());
218                        switchToLocale(newLocale);
219                    } catch (Exception e) {
220                        LOG.error(e.getLocalizedMessage(), e);
221                        CmsErrorDialog.showErrorDialog(e);
222                    } finally {
223                        m_handlingLocaleChange = false;
224                    }
225                }
226            }
227        });
228
229        m_comparisonLocaleSelector = new ComboBox();
230        m_comparisonLocaleSelector.addStyleName("o-sitemap-localeselect");
231        m_comparisonLocaleSelector.setNullSelectionAllowed(false);
232
233        List<Locale> comparisonLocales = getComparisonLocales();
234        Locale selectedComparisonLocale = null;
235        for (Locale comparisonLocale : comparisonLocales) {
236            m_comparisonLocaleSelector.addItem(comparisonLocale);
237            m_comparisonLocaleSelector.setItemIcon(comparisonLocale, FontOpenCms.SPACE);
238            m_comparisonLocaleSelector.setItemCaption(
239                comparisonLocale,
240                comparisonLocale.getDisplayName(A_CmsUI.get().getLocale()));
241            if ((selectedComparisonLocale == null) && !comparisonLocale.equals(m_rootLocale)) {
242                selectedComparisonLocale = comparisonLocale;
243            }
244            if ((initialComparisonLocale != null)
245                && comparisonLocale.equals(initialComparisonLocale)
246                && !comparisonLocale.equals(m_rootLocale)) {
247                // if an initial comparison locale is given, it should have priority over the first comparison locale
248                selectedComparisonLocale = comparisonLocale;
249            }
250
251        }
252        m_comparisonLocale = selectedComparisonLocale;
253        m_comparisonLocaleSelector.setValue(selectedComparisonLocale);
254        m_comparisonLocaleSelector.setItemIcon(mainLocale, MAIN_LOCALE_ICON);
255
256        m_comparisonLocaleSelector.addValueChangeListener(new ValueChangeListener() {
257
258            private static final long serialVersionUID = 1L;
259
260            @SuppressWarnings("synthetic-access")
261            public void valueChange(ValueChangeEvent event) {
262
263                if (!m_handlingLocaleChange) {
264                    m_handlingLocaleChange = true;
265                    try {
266                        Locale locale = (Locale)(event.getProperty().getValue());
267                        if (m_rootLocale.equals(locale)) {
268                            Locale oldComparisonLocale = m_comparisonLocale;
269                            if (getLocaleGroup().getResourcesByLocale().keySet().contains(oldComparisonLocale)) {
270                                m_comparisonLocale = locale;
271                                switchToLocale(oldComparisonLocale);
272                                updateLocaleWidgets();
273                            } else {
274                                Notification.show(
275                                    CmsVaadinUtils.getMessageText(
276                                        Messages.GUI_LOCALECOMPARE_CANNOT_SWITCH_COMPARISON_LOCALE_0));
277                                m_comparisonLocaleSelector.setValue(oldComparisonLocale);
278                            }
279                        } else {
280                            m_comparisonLocale = locale;
281                            updateLocaleWidgets();
282                            initTree(m_currentRoot);
283                        }
284
285                    } catch (Exception e) {
286                        LOG.error(e.getLocalizedMessage(), e);
287                        CmsErrorDialog.showErrorDialog(e);
288                    } finally {
289                        m_handlingLocaleChange = false;
290                    }
291                }
292            }
293        });
294
295        CssLayout localeSelectors = new CssLayout();
296        localeSelectors.addStyleName(OpenCmsTheme.SITEMAP_LOCALE_BAR);
297
298        m_rootLocaleSelector.setCaption(CmsVaadinUtils.getMessageText(Messages.GUI_LOCALECOMPARE_MAIN_LOCALE_0));
299        m_comparisonLocaleSelector.setCaption(
300            CmsVaadinUtils.getMessageText(Messages.GUI_LOCALECOMPARE_COMPARISON_LOCALE_0));
301
302        localeSelectors.setWidth("100%");
303        localeSelectors.addComponent(m_rootLocaleSelector);
304        localeSelectors.addComponent(m_comparisonLocaleSelector);
305        // localeSelectors.setComponentAlignment(wrapper2, Alignment.MIDDLE_RIGHT);
306
307        setSpacing(true);
308        addComponent(localeSelectors);
309        addComponent(m_treeContainer);
310        m_treeContainer.setWidth("100%");
311        initTree(res);
312    }
313
314    /**
315     * @see org.opencms.ui.sitemap.I_CmsLocaleCompareContext#refreshAll()
316     */
317    public void refreshAll() {
318
319        try {
320            initialize(m_currentRoot.getStructureId(), m_comparisonLocale);
321        } catch (CmsException e) {
322            LOG.error(e.getLocalizedMessage(), e);
323            CmsErrorDialog.showErrorDialog(e);
324        }
325    }
326
327    /**
328     * Switches the root locale to the given value.<p>
329     *
330     * @param locale the new root locale
331     * @throws CmsException if something goes wrong
332     */
333    public void switchToLocale(Locale locale) throws CmsException {
334
335        CmsObject cms = A_CmsUI.getCmsObject();
336        CmsLocaleGroupService groupService = cms.getLocaleGroupService();
337        CmsLocaleGroup localeGroup = groupService.readDefaultFileLocaleGroup(m_currentRoot);
338        Collection<CmsResource> resources = localeGroup.getResourcesForLocale(locale);
339        if (resources.isEmpty()) {
340            LOG.error(
341                "Can not switch to locale "
342                    + locale
343                    + ": no page found in locale group of "
344                    + m_currentRoot.getRootPath());
345        }
346        CmsResource localeVariant = resources.iterator().next();
347        if (!localeVariant.isFolder()) {
348            CmsResource parentFolder = cms.readParentFolder(localeVariant.getStructureId());
349            if (m_comparisonLocale.equals(locale)) {
350                m_comparisonLocale = m_rootLocale;
351                m_rootLocale = locale;
352            } else {
353                m_rootLocale = locale;
354            }
355            updateLocaleWidgets();
356            initTree(parentFolder);
357        } else {
358            LOG.error("locale variant should not be a folder: " + localeVariant.getRootPath());
359        }
360    }
361
362    /**
363     * Initializes the tree with the given resource as a root.<p>
364     *
365     * @param rootRes the new tree root resource
366     * @throws CmsException if something goes wrong
367     */
368    protected void initTree(CmsResource rootRes) throws CmsException {
369
370        m_currentRoot = rootRes;
371        m_treeContainer.removeAllComponents();
372        showHeader();
373        CmsSitemapTreeController controller = new CmsSitemapTreeController(
374            A_CmsUI.getCmsObject(),
375            rootRes,
376            this,
377            m_treeContainer);
378
379        // no need to escape a structure id
380        JavaScript.eval(CmsGwtConstants.VAR_LOCALE_ROOT + "='" + rootRes.getStructureId() + "'");
381
382        CmsSitemapUI ui = (CmsSitemapUI)(A_CmsUI.get());
383        ui.getSitemapExtension().setSitemapTreeController(controller);
384        CmsSitemapTreeNode root1 = controller.createRootNode();
385        controller.initEventHandlers(root1);
386        m_treeContainer.addComponent(root1);
387        controller.onClickOpen(root1);
388    }
389
390    /**
391     * Shows the current loale values in their corresponding widgets.
392     */
393    protected void updateLocaleWidgets() {
394
395        m_rootLocaleSelector.setValue(m_rootLocale);
396        m_comparisonLocaleSelector.setValue(m_comparisonLocale);
397    }
398
399    /**
400     * Gets the possible locale values selectable as main locale.<p>
401     *
402     * @param cms the CMS context
403     * @param res the resource
404     * @param mainLocale the main locale
405     * @param secondaryLocales the secondary locales
406     *
407     * @return the possible locale selections
408     */
409    private List<Locale> getMainLocaleSelectOptions(
410        CmsObject cms,
411        CmsResource res,
412        Locale mainLocale,
413        List<Locale> secondaryLocales) {
414
415        try {
416            CmsLocaleGroup localeGroup = cms.getLocaleGroupService().readDefaultFileLocaleGroup(res);
417            List<Locale> result = Lists.newArrayList();
418            if (localeGroup.hasLocale(mainLocale)) {
419                result.add(mainLocale);
420            }
421            for (Locale locale : secondaryLocales) {
422                if (localeGroup.hasLocale(locale)) {
423                    result.add(locale);
424                }
425            }
426            return result;
427        } catch (CmsException e) {
428            LOG.error(e.getLocalizedMessage(), e);
429            return Lists.newArrayList();
430        }
431    }
432
433    /**
434     * Shows the header for the currently selected sitemap root.<p>
435     *
436     * @throws CmsException if something goes wrong
437     */
438    private void showHeader() throws CmsException {
439
440        CmsSitemapUI ui = (CmsSitemapUI)A_CmsUI.get();
441        String title = null;
442        String description = null;
443        String path = null;
444        String locale = m_rootLocale.toString();
445        CmsObject cms = A_CmsUI.getCmsObject();
446        CmsResource targetRes = getRoot();
447        if (targetRes.isFolder()) {
448            targetRes = cms.readDefaultFile(targetRes, CmsResourceFilter.IGNORE_EXPIRATION);
449            if (targetRes == null) {
450                targetRes = getRoot();
451            }
452        }
453        CmsResourceUtil resUtil = new CmsResourceUtil(cms, getRoot());
454        title = resUtil.getTitle();
455        description = resUtil.getGalleryDescription(A_CmsUI.get().getLocale());
456        path = OpenCms.getLinkManager().getServerLink(
457            cms,
458            cms.getRequestContext().removeSiteRoot(targetRes.getRootPath()));
459        String iconClasses = CmsIconUtil.getIconClasses(
460            CmsIconUtil.getDisplayType(cms, getRoot()),
461            getRoot().getName(),
462            false);
463        ui.getSitemapExtension().showInfoHeader(title, description, path, locale, iconClasses);
464    }
465}