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.shared.CmsGwtConstants;
034import org.opencms.gwt.shared.CmsIconUtil;
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.data.Property.ValueChangeEvent;
058import com.vaadin.data.Property.ValueChangeListener;
059import com.vaadin.server.Resource;
060import com.vaadin.ui.ComboBox;
061import com.vaadin.ui.CssLayout;
062import com.vaadin.ui.JavaScript;
063import com.vaadin.ui.Notification;
064import com.vaadin.ui.VerticalLayout;
065
066/**
067 * View used to compare sitemaps across locales.<p>
068 */
069public class CmsLocaleComparePanel extends VerticalLayout implements I_CmsLocaleCompareContext {
070
071    /** The logger instance for this class. */
072    private static final Log LOG = CmsLog.getLog(CmsLocaleComparePanel.class);
073
074    /** The serial version id. */
075    private static final long serialVersionUID = 1L;
076
077    /** Icon for the main locale option in select boxes. */
078    public static final Resource MAIN_LOCALE_ICON = FontOpenCms.CIRCLE_INFO;
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        super();
108        Locale locale = OpenCms.getWorkplaceManager().getWorkplaceLocale(A_CmsUI.getCmsObject());
109        A_CmsUI.get().setLocale(locale);
110        try {
111            initialize(new CmsUUID(id), null);
112        } catch (CmsException e) {
113            LOG.error(e.getLocalizedMessage(), e);
114            CmsErrorDialog.showErrorDialog(e);
115        }
116    }
117
118    /**
119     * @see org.opencms.ui.sitemap.I_CmsLocaleCompareContext#getComparisonLocale()
120     */
121    public Locale getComparisonLocale() {
122
123        return m_comparisonLocale;
124
125    }
126
127    /**
128     * Gets the locales selectable as comparison locales.<p>
129     *
130     * @return the possible comparison locales
131     */
132    public List<Locale> getComparisonLocales() {
133
134        CmsObject cms = A_CmsUI.getCmsObject();
135        cms.getLocaleGroupService();
136        List<Locale> result = CmsLocaleGroupService.getPossibleLocales(cms, m_currentRoot);
137        return result;
138    }
139
140    /**
141     * @see org.opencms.ui.sitemap.I_CmsLocaleCompareContext#getLocaleGroup()
142     */
143    public CmsLocaleGroup getLocaleGroup() {
144
145        try {
146            CmsObject cms = A_CmsUI.getCmsObject();
147            CmsLocaleGroupService service = cms.getLocaleGroupService();
148            return service.readLocaleGroup(m_currentRoot);
149        } catch (Exception e) {
150            LOG.error(e.getLocalizedMessage(), e);
151            return null;
152        }
153
154    }
155
156    /**
157     * @see org.opencms.ui.sitemap.I_CmsLocaleCompareContext#getRoot()
158     */
159    public CmsResource getRoot() {
160
161        return m_currentRoot;
162    }
163
164    /**
165     * @see org.opencms.ui.sitemap.I_CmsLocaleCompareContext#getRootLocale()
166     */
167    public Locale getRootLocale() {
168
169        return m_rootLocale;
170    }
171
172    /**
173     * Initializes the locale comparison view.<p>
174     *
175     * @param id the structure id of the currrent sitemap root entry
176     * @param initialComparisonLocale if not null, the initially selected ccomparison locale
177     *
178     * @throws CmsException if something goes wrong
179     */
180    public void initialize(CmsUUID id, Locale initialComparisonLocale) throws CmsException {
181
182        removeAllComponents();
183        CmsObject cms = A_CmsUI.getCmsObject();
184        CmsResource res = cms.readResource(id);
185        m_currentRoot = res;
186        CmsSite site = OpenCms.getSiteManager().getSiteForRootPath(res.getRootPath());
187
188        Locale rootLocale = OpenCms.getLocaleManager().getDefaultLocale(cms, res);
189        m_rootLocale = rootLocale;
190        Locale mainLocale = site.getMainTranslationLocale(null);
191        List<Locale> secondaryLocales = site.getSecondaryTranslationLocales();
192
193        List<Locale> possibleLocaleSelections = getMainLocaleSelectOptions(cms, res, mainLocale, secondaryLocales);
194        m_rootLocaleSelector = new ComboBox();
195        m_rootLocaleSelector.addStyleName("o-sitemap-localeselect");
196        m_rootLocaleSelector.setNullSelectionAllowed(false);
197        for (Locale selectableLocale : possibleLocaleSelections) {
198            m_rootLocaleSelector.addItem(selectableLocale);
199            m_rootLocaleSelector.setItemIcon(selectableLocale, FontOpenCms.SPACE);
200            m_rootLocaleSelector.setItemCaption(
201                selectableLocale,
202                selectableLocale.getDisplayName(A_CmsUI.get().getLocale()));
203        }
204        m_rootLocaleSelector.setItemIcon(mainLocale, MAIN_LOCALE_ICON);
205        m_rootLocaleSelector.setValue(m_rootLocale);
206        m_rootLocaleSelector.addValueChangeListener(new ValueChangeListener() {
207
208            private static final long serialVersionUID = 1L;
209
210            @SuppressWarnings("synthetic-access")
211            public void valueChange(ValueChangeEvent event) {
212
213                if (!m_handlingLocaleChange) {
214                    m_handlingLocaleChange = true;
215                    try {
216                        Locale newLocale = (Locale)(event.getProperty().getValue());
217                        switchToLocale(newLocale);
218                    } catch (Exception e) {
219                        LOG.error(e.getLocalizedMessage(), e);
220                        CmsErrorDialog.showErrorDialog(e);
221                    } finally {
222                        m_handlingLocaleChange = false;
223                    }
224                }
225            }
226        });
227
228        m_comparisonLocaleSelector = new ComboBox();
229        m_comparisonLocaleSelector.addStyleName("o-sitemap-localeselect");
230        m_comparisonLocaleSelector.setNullSelectionAllowed(false);
231
232        List<Locale> comparisonLocales = getComparisonLocales();
233        Locale selectedComparisonLocale = null;
234        for (Locale comparisonLocale : comparisonLocales) {
235            m_comparisonLocaleSelector.addItem(comparisonLocale);
236            m_comparisonLocaleSelector.setItemIcon(comparisonLocale, FontOpenCms.SPACE);
237            m_comparisonLocaleSelector.setItemCaption(
238                comparisonLocale,
239                comparisonLocale.getDisplayName(A_CmsUI.get().getLocale()));
240            if ((selectedComparisonLocale == null) && !comparisonLocale.equals(m_rootLocale)) {
241                selectedComparisonLocale = comparisonLocale;
242            }
243            if ((initialComparisonLocale != null)
244                && comparisonLocale.equals(initialComparisonLocale)
245                && !comparisonLocale.equals(m_rootLocale)) {
246                // if an initial comparison locale is given, it should have priority over the first comparison locale
247                selectedComparisonLocale = comparisonLocale;
248            }
249
250        }
251        m_comparisonLocale = selectedComparisonLocale;
252        m_comparisonLocaleSelector.setValue(selectedComparisonLocale);
253        m_comparisonLocaleSelector.setItemIcon(mainLocale, MAIN_LOCALE_ICON);
254
255        m_comparisonLocaleSelector.addValueChangeListener(new ValueChangeListener() {
256
257            private static final long serialVersionUID = 1L;
258
259            @SuppressWarnings("synthetic-access")
260            public void valueChange(ValueChangeEvent event) {
261
262                if (!m_handlingLocaleChange) {
263                    m_handlingLocaleChange = true;
264                    try {
265                        Locale locale = (Locale)(event.getProperty().getValue());
266                        if (m_rootLocale.equals(locale)) {
267                            Locale oldComparisonLocale = m_comparisonLocale;
268                            if (getLocaleGroup().getResourcesByLocale().keySet().contains(oldComparisonLocale)) {
269                                m_comparisonLocale = locale;
270                                switchToLocale(oldComparisonLocale);
271                                updateLocaleWidgets();
272                            } else {
273                                Notification.show(
274                                    CmsVaadinUtils.getMessageText(
275                                        Messages.GUI_LOCALECOMPARE_CANNOT_SWITCH_COMPARISON_LOCALE_0));
276                                m_comparisonLocaleSelector.setValue(oldComparisonLocale);
277                            }
278                        } else {
279                            m_comparisonLocale = locale;
280                            updateLocaleWidgets();
281                            initTree(m_currentRoot);
282                        }
283
284                    } catch (Exception e) {
285                        LOG.error(e.getLocalizedMessage(), e);
286                        CmsErrorDialog.showErrorDialog(e);
287                    } finally {
288                        m_handlingLocaleChange = false;
289                    }
290                }
291            }
292        });
293
294        CssLayout localeSelectors = new CssLayout();
295        localeSelectors.addStyleName(OpenCmsTheme.SITEMAP_LOCALE_BAR);
296
297        m_rootLocaleSelector.setCaption(CmsVaadinUtils.getMessageText(Messages.GUI_LOCALECOMPARE_MAIN_LOCALE_0));
298        m_comparisonLocaleSelector.setCaption(
299            CmsVaadinUtils.getMessageText(Messages.GUI_LOCALECOMPARE_COMPARISON_LOCALE_0));
300
301        localeSelectors.setWidth("100%");
302        localeSelectors.addComponent(m_rootLocaleSelector);
303        localeSelectors.addComponent(m_comparisonLocaleSelector);
304        // localeSelectors.setComponentAlignment(wrapper2, Alignment.MIDDLE_RIGHT);
305
306        setSpacing(true);
307        addComponent(localeSelectors);
308        addComponent(m_treeContainer);
309        m_treeContainer.setWidth("100%");
310        initTree(res);
311    }
312
313    /**
314     * @see org.opencms.ui.sitemap.I_CmsLocaleCompareContext#refreshAll()
315     */
316    public void refreshAll() {
317
318        try {
319            initialize(m_currentRoot.getStructureId(), m_comparisonLocale);
320        } catch (CmsException e) {
321            LOG.error(e.getLocalizedMessage(), e);
322            CmsErrorDialog.showErrorDialog(e);
323        }
324    }
325
326    /**
327     * Switches the root locale to the given value.<p>
328     *
329     * @param locale the new root locale
330     * @throws CmsException if something goes wrong
331     */
332    public void switchToLocale(Locale locale) throws CmsException {
333
334        CmsObject cms = A_CmsUI.getCmsObject();
335        CmsLocaleGroupService groupService = cms.getLocaleGroupService();
336        CmsLocaleGroup localeGroup = groupService.readDefaultFileLocaleGroup(m_currentRoot);
337        Collection<CmsResource> resources = localeGroup.getResourcesForLocale(locale);
338        if (resources.isEmpty()) {
339            LOG.error(
340                "Can not switch to locale "
341                    + locale
342                    + ": no page found in locale group of "
343                    + m_currentRoot.getRootPath());
344        }
345        CmsResource localeVariant = resources.iterator().next();
346        if (!localeVariant.isFolder()) {
347            CmsResource parentFolder = cms.readParentFolder(localeVariant.getStructureId());
348            if (m_comparisonLocale.equals(locale)) {
349                m_comparisonLocale = m_rootLocale;
350                m_rootLocale = locale;
351            } else {
352                m_rootLocale = locale;
353            }
354            updateLocaleWidgets();
355            initTree(parentFolder);
356        } else {
357            LOG.error("locale variant should not be a folder: " + localeVariant.getRootPath());
358        }
359    }
360
361    /**
362     * Initializes the tree with the given resource as a root.<p>
363     *
364     * @param rootRes the new tree root resource
365     * @throws CmsException if something goes wrong
366     */
367    protected void initTree(CmsResource rootRes) throws CmsException {
368
369        m_currentRoot = rootRes;
370        m_treeContainer.removeAllComponents();
371        showHeader();
372        CmsSitemapTreeController controller = new CmsSitemapTreeController(
373            A_CmsUI.getCmsObject(),
374            rootRes,
375            this,
376            m_treeContainer);
377
378        // no need to escape a structure id
379        JavaScript.eval(CmsGwtConstants.VAR_LOCALE_ROOT + "='" + rootRes.getStructureId() + "'");
380
381        CmsSitemapUI ui = (CmsSitemapUI)(A_CmsUI.get());
382        ui.getSitemapExtension().setSitemapTreeController(controller);
383        CmsSitemapTreeNode root1 = controller.createRootNode();
384        controller.initEventHandlers(root1);
385        m_treeContainer.addComponent(root1);
386        controller.onClickOpen(root1);
387    }
388
389    /**
390     * Shows the current loale values in their corresponding widgets.
391     */
392    protected void updateLocaleWidgets() {
393
394        m_rootLocaleSelector.setValue(m_rootLocale);
395        m_comparisonLocaleSelector.setValue(m_comparisonLocale);
396    }
397
398    /**
399     * Gets the possible locale values selectable as main locale.<p>
400     *
401     * @param cms the CMS context
402     * @param res the resource
403     * @param mainLocale the main locale
404     * @param secondaryLocales the secondary locales
405     *
406     * @return the possible locale selections
407     */
408    private List<Locale> getMainLocaleSelectOptions(
409        CmsObject cms,
410        CmsResource res,
411        Locale mainLocale,
412        List<Locale> secondaryLocales) {
413
414        try {
415            CmsLocaleGroup localeGroup = cms.getLocaleGroupService().readDefaultFileLocaleGroup(res);
416            List<Locale> result = Lists.newArrayList();
417            if (localeGroup.hasLocale(mainLocale)) {
418                result.add(mainLocale);
419            }
420            for (Locale locale : secondaryLocales) {
421                if (localeGroup.hasLocale(locale)) {
422                    result.add(locale);
423                }
424            }
425            return result;
426        } catch (CmsException e) {
427            LOG.error(e.getLocalizedMessage(), e);
428            return Lists.newArrayList();
429        }
430    }
431
432    /**
433     * Shows the header for the currently selected sitemap root.<p>
434     *
435     * @throws CmsException if something goes wrong
436     */
437    private void showHeader() throws CmsException {
438
439        CmsSitemapUI ui = (CmsSitemapUI)A_CmsUI.get();
440        String title = null;
441        String description = null;
442        String path = null;
443        String locale = m_rootLocale.toString();
444        CmsObject cms = A_CmsUI.getCmsObject();
445        CmsResource targetRes = getRoot();
446        if (targetRes.isFolder()) {
447            targetRes = cms.readDefaultFile(targetRes, CmsResourceFilter.IGNORE_EXPIRATION);
448            if (targetRes == null) {
449                targetRes = getRoot();
450            }
451        }
452        CmsResourceUtil resUtil = new CmsResourceUtil(cms, getRoot());
453        title = resUtil.getTitle();
454        description = resUtil.getGalleryDescription(A_CmsUI.get().getLocale());
455        path = OpenCms.getLinkManager().getServerLink(
456            cms,
457            cms.getRequestContext().removeSiteRoot(targetRes.getRootPath()));
458        String iconClasses = CmsIconUtil.getResourceIconClasses(
459            OpenCms.getResourceManager().getResourceType(getRoot()).getTypeName(),
460            false);
461        ui.getSitemapExtension().showInfoHeader(title, description, path, locale, iconClasses);
462    }
463}