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.dialogs;
029
030import org.opencms.file.CmsObject;
031import org.opencms.file.CmsResource;
032import org.opencms.file.history.CmsHistoryProject;
033import org.opencms.file.history.I_CmsHistoryResource;
034import org.opencms.file.types.CmsResourceTypeUnknownFile;
035import org.opencms.file.types.CmsResourceTypeUnknownFolder;
036import org.opencms.file.types.I_CmsResourceType;
037import org.opencms.gwt.CmsVfsService;
038import org.opencms.loader.CmsLoaderException;
039import org.opencms.main.CmsException;
040import org.opencms.main.CmsLog;
041import org.opencms.main.OpenCms;
042import org.opencms.ui.CmsVaadinUtils;
043import org.opencms.ui.I_CmsDialogContext;
044import org.opencms.ui.components.CmsBasicDialog;
045import org.opencms.ui.components.CmsOkCancelActionHandler;
046import org.opencms.ui.components.CmsResourceInfo;
047import org.opencms.util.CmsUUID;
048import org.opencms.workplace.explorer.CmsExplorerTypeSettings;
049import org.opencms.workplace.explorer.CmsResourceUtil;
050
051import java.util.ArrayList;
052import java.util.Collections;
053import java.util.Comparator;
054import java.util.List;
055
056import org.apache.commons.logging.Log;
057
058import com.google.common.collect.Lists;
059import com.vaadin.ui.AbstractOrderedLayout;
060import com.vaadin.ui.Alignment;
061import com.vaadin.ui.Button;
062import com.vaadin.ui.Button.ClickEvent;
063import com.vaadin.ui.Button.ClickListener;
064import com.vaadin.v7.data.Property.ValueChangeEvent;
065import com.vaadin.v7.data.Property.ValueChangeListener;
066import com.vaadin.v7.data.util.IndexedContainer;
067import com.vaadin.v7.ui.CheckBox;
068import com.vaadin.v7.ui.HorizontalLayout;
069import com.vaadin.v7.ui.Label;
070
071/**
072 * Dialog for restoring deleted resources in a folder.<p>
073 */
074public class CmsRestoreDeletedDialog extends CmsBasicDialog {
075
076    /** Logger instance for this class. */
077    private static final Log LOG = CmsLog.getLog(CmsRestoreDeletedDialog.class);
078
079    /** Property for storing selection status. */
080    private static final String PROP_SELECTED = "selected";
081
082    /** Serial version id. */
083    private static final long serialVersionUID = 1L;
084
085    /** The cancel button. */
086    private Button m_cancelButton;
087
088    /** The box containing the widgets representing the deleted resources. */
089    private AbstractOrderedLayout m_deletedResourceContainer;
090
091    /** The dialog context. */
092    private I_CmsDialogContext m_dialogContext;
093
094    /** Checkbox for including subfolders. */
095    private CheckBox m_includeSubfoldersField;
096
097    /** The OK button. */
098    private Button m_okButton;
099
100    /** Check box to select all resources. */
101    private CheckBox m_selectAllField;
102
103    /** Data model for check boxes / selection. */
104    private IndexedContainer m_selectionContainer;
105
106    /**
107     * Creates a new instance.<p>
108     *
109     * @param context the dialog context
110     * @throws CmsException if something goes wrong
111     */
112    public CmsRestoreDeletedDialog(I_CmsDialogContext context)
113    throws CmsException {
114
115        m_dialogContext = context;
116        CmsVaadinUtils.readAndLocalizeDesign(this, CmsVaadinUtils.getWpMessagesForCurrentLocale(), null);
117        CmsObject cms = context.getCms();
118        List<I_CmsHistoryResource> deletedResources = readDeletedResources(
119            m_includeSubfoldersField.getValue().booleanValue());
120        initDeletedResources(cms, deletedResources);
121        m_cancelButton.addClickListener(new ClickListener() {
122
123            private static final long serialVersionUID = 1L;
124
125            public void buttonClick(ClickEvent event) {
126
127                cancel();
128            }
129        });
130
131        m_includeSubfoldersField.addValueChangeListener(new ValueChangeListener() {
132
133            private static final long serialVersionUID = 1L;
134
135            public void valueChange(ValueChangeEvent event) {
136
137                onSubFolderChange((Boolean)event.getProperty().getValue());
138            }
139        });
140
141        m_selectAllField.addValueChangeListener(new ValueChangeListener() {
142
143            private static final long serialVersionUID = 1L;
144
145            public void valueChange(ValueChangeEvent event) {
146
147                onSelectAllChange((Boolean)(event.getProperty().getValue()));
148            }
149        });
150        m_okButton.addClickListener(new ClickListener() {
151
152            private static final long serialVersionUID = 1L;
153
154            public void buttonClick(ClickEvent event) {
155
156                submit();
157            }
158        });
159
160        setActionHandler(new CmsOkCancelActionHandler() {
161
162            private static final long serialVersionUID = 1L;
163
164            @Override
165            protected void cancel() {
166
167                CmsRestoreDeletedDialog.this.cancel();
168            }
169
170            @Override
171            protected void ok() {
172
173                submit();
174            }
175        });
176    }
177
178    /**
179     * Gets the ids of the selected resources.<p>
180     *
181     * @return the ids of the selected resources
182     */
183    public List<CmsUUID> getSelectedIds() {
184
185        List<?> itemIds = m_selectionContainer.getItemIds();
186        List<CmsUUID> result = Lists.newArrayList();
187        for (Object itemId : itemIds) {
188            CmsUUID structureId = (CmsUUID)itemId;
189            Boolean value = (Boolean)(m_selectionContainer.getItem(itemId).getItemProperty(PROP_SELECTED).getValue());
190            if (value.booleanValue()) {
191                result.add(structureId);
192            }
193        }
194        return result;
195    }
196
197    /**
198     * Cancels the dialog.<p>
199     */
200    void cancel() {
201
202        m_dialogContext.finish(new ArrayList<CmsUUID>());
203    }
204
205    /**
206     * Called on select all change.<p>
207     *
208     * @param value the new value
209     */
210    void onSelectAllChange(Boolean value) {
211
212        for (Object id : m_selectionContainer.getItemIds()) {
213            m_selectionContainer.getItem(id).getItemProperty(PROP_SELECTED).setValue(value);
214        }
215    }
216
217    /**
218     * Called on include sub folders change.<p>
219     *
220     * @param value the new value
221     */
222    void onSubFolderChange(Boolean value) {
223
224        List<I_CmsHistoryResource> historyResources;
225        try {
226            CmsObject cms = m_dialogContext.getCms();
227            historyResources = readDeletedResources(value.booleanValue());
228            initDeletedResources(cms, historyResources);
229        } catch (CmsException e) {
230            m_dialogContext.error(e);
231        }
232    }
233
234    /**
235     * Submits the dialog.<p>
236     */
237    void submit() {
238
239        List<CmsUUID> selectedIds = getSelectedIds();
240        List<CmsUUID> updated = Lists.newArrayList();
241        CmsObject cms = m_dialogContext.getCms();
242        try {
243            for (CmsUUID selectedId : selectedIds) {
244                cms.restoreDeletedResource(selectedId);
245                updated.add(selectedId);
246            }
247            m_dialogContext.finish(updated);
248        } catch (CmsException e) {
249            m_dialogContext.error(e);
250        }
251    }
252
253    /**
254     * Fills the list of resources to select from.<p>
255     *
256     * @param cms the cms context
257     * @param deletedResources the deleted resources
258     *
259     * @throws CmsException if something goes wrong
260     */
261    private void initDeletedResources(CmsObject cms, List<I_CmsHistoryResource> deletedResources) throws CmsException {
262
263        Collections.sort(deletedResources, new Comparator<I_CmsHistoryResource>() {
264
265            public int compare(I_CmsHistoryResource first, I_CmsHistoryResource second) {
266
267                return first.getRootPath().compareTo(second.getRootPath());
268            }
269        });
270        m_deletedResourceContainer.removeAllComponents();
271        m_selectionContainer = new IndexedContainer();
272        m_selectionContainer.addContainerProperty(PROP_SELECTED, Boolean.class, Boolean.FALSE);
273        m_okButton.setEnabled(!deletedResources.isEmpty());
274        if (deletedResources.isEmpty()) {
275            m_deletedResourceContainer.addComponent(
276                new Label(CmsVaadinUtils.getMessageText(org.opencms.workplace.list.Messages.GUI_LIST_EMPTY_0)));
277
278        }
279        for (I_CmsHistoryResource deleted : deletedResources) {
280            CmsExplorerTypeSettings explorerType;
281            try {
282                I_CmsResourceType resType = OpenCms.getResourceManager().getResourceType(deleted.getTypeId());
283                String typeName = resType.getTypeName();
284                explorerType = OpenCms.getWorkplaceManager().getExplorerTypeSetting(typeName);
285            } catch (CmsLoaderException e) {
286                explorerType = OpenCms.getWorkplaceManager().getExplorerTypeSetting(
287                    deleted.isFile()
288                    ? CmsResourceTypeUnknownFile.getStaticTypeName()
289                    : CmsResourceTypeUnknownFolder.getStaticTypeName());
290            }
291            String title = cms.getRequestContext().removeSiteRoot(deleted.getRootPath());
292
293            long deletionDate = 0;
294            try {
295                CmsHistoryProject hp = cms.readHistoryProject(deleted.getPublishTag());
296                if (hp != null) {
297                    deletionDate = hp.getPublishingDate();
298                }
299            } catch (CmsException e) {
300                LOG.debug(
301                    "Failed to retrieve deletion date for deleted resource "
302                        + deleted.getRootPath()
303                        + ". Last modification date will be shown.");
304            }
305            String subtitle = CmsVaadinUtils.getMessageText(
306                org.opencms.ui.Messages.GUI_RESTOREDELETED_DATE_VERSION_2,
307                CmsVfsService.formatDateTime(cms, deletionDate == 0 ? deleted.getDateLastModified() : deletionDate),
308                "" + deleted.getVersion());
309            if (explorerType == null) {
310                explorerType = OpenCms.getWorkplaceManager().getExplorerTypeSetting(
311                    deleted.isFile()
312                    ? CmsResourceTypeUnknownFile.RESOURCE_TYPE_NAME
313                    : CmsResourceTypeUnknownFolder.RESOURCE_TYPE_NAME);
314            }
315            CmsResourceInfo info = new CmsResourceInfo(
316                title,
317                subtitle,
318                CmsResourceUtil.getBigIconResource(explorerType, deleted.getName()));
319            info.setWidth("100%");
320            HorizontalLayout hl = new HorizontalLayout();
321            hl.setWidth("100%");
322            CheckBox checkbox = new CheckBox();
323            hl.addComponent(checkbox);
324            hl.addComponent(info);
325            hl.setExpandRatio(info, 1);
326            hl.setComponentAlignment(checkbox, Alignment.MIDDLE_LEFT);
327            m_selectionContainer.addItem(deleted.getStructureId());
328            checkbox.setPropertyDataSource(
329                m_selectionContainer.getItem(deleted.getStructureId()).getItemProperty(PROP_SELECTED));
330            m_deletedResourceContainer.addComponent(hl);
331        }
332    }
333
334    /**
335     * Reads the deleted resources in the folders selected for the dialog.
336     *
337     * @param includeSubFolders true if deleted resources in subfolders should be included
338     * @return the list of deleted resources
339     *
340     * @throws CmsException if something goes wrong
341     */
342    private List<I_CmsHistoryResource> readDeletedResources(boolean includeSubFolders) throws CmsException {
343
344        CmsObject cms = m_dialogContext.getCms();
345        List<I_CmsHistoryResource> result = new ArrayList<>();
346        for (CmsResource res : m_dialogContext.getResources()) {
347            result.addAll(cms.readDeletedResources(cms.getSitePath(res), includeSubFolders));
348        }
349        return result;
350    }
351
352}