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