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.history.diff;
029
030import org.opencms.file.CmsFile;
031import org.opencms.file.CmsObject;
032import org.opencms.file.CmsResource;
033import org.opencms.file.types.CmsResourceTypeBinary;
034import org.opencms.file.types.CmsResourceTypeJsp;
035import org.opencms.file.types.CmsResourceTypePlain;
036import org.opencms.file.types.CmsResourceTypePointer;
037import org.opencms.file.types.CmsResourceTypeXmlContent;
038import org.opencms.file.types.CmsResourceTypeXmlPage;
039import org.opencms.file.types.I_CmsResourceType;
040import org.opencms.gwt.shared.CmsHistoryResourceBean;
041import org.opencms.i18n.CmsLocaleManager;
042import org.opencms.main.CmsException;
043import org.opencms.main.CmsLog;
044import org.opencms.main.OpenCms;
045import org.opencms.search.extractors.CmsExtractorMsOfficeOLE2;
046import org.opencms.search.extractors.CmsExtractorPdf;
047import org.opencms.search.extractors.CmsExtractorRtf;
048import org.opencms.search.extractors.I_CmsTextExtractor;
049import org.opencms.ui.CmsVaadinUtils;
050import org.opencms.ui.Messages;
051
052import java.io.BufferedReader;
053import java.io.IOException;
054import java.io.StringReader;
055import java.io.UnsupportedEncodingException;
056
057import org.apache.commons.logging.Log;
058
059import com.google.common.base.Optional;
060import com.vaadin.ui.Component;
061import com.vaadin.ui.Panel;
062import com.vaadin.v7.ui.VerticalLayout;
063
064/**
065 * Interprets two versions of a resource as text files, and shows a diff view for the two texts.<p>
066 *
067 * This should work for both plaintext files as well as binary documents which from which OpenCms can extract text content.
068 */
069public class CmsTextDiff implements I_CmsDiffProvider {
070
071    /** Logger instance for this class. */
072    private static final Log LOG = CmsLog.getLog(CmsTextDiff.class);
073
074    /**
075     * @see org.opencms.ui.dialogs.history.diff.I_CmsDiffProvider#diff(org.opencms.file.CmsObject, org.opencms.gwt.shared.CmsHistoryResourceBean, org.opencms.gwt.shared.CmsHistoryResourceBean)
076     */
077    public Optional<Component> diff(CmsObject cms, CmsHistoryResourceBean v1, CmsHistoryResourceBean v2)
078    throws CmsException {
079
080        CmsResource resource1 = A_CmsAttributeDiff.readResource(cms, v1);
081        String encoding = CmsLocaleManager.getResourceEncoding(cms, resource1);
082        I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(resource1);
083        if ((type instanceof CmsResourceTypeXmlContent)
084            || (type instanceof CmsResourceTypePlain)
085            || (type instanceof CmsResourceTypeJsp)
086            || (type instanceof CmsResourceTypeXmlPage)
087            || (type instanceof CmsResourceTypePointer)
088            || (type instanceof CmsResourceTypeBinary)) {
089            CmsResource resource2 = A_CmsAttributeDiff.readResource(cms, v2);
090
091            String path1 = resource1.getRootPath();
092            String path2 = resource2.getRootPath();
093
094            CmsFile file1 = cms.readFile(resource1);
095            CmsFile file2 = cms.readFile(resource2);
096
097            byte[] content1 = file1.getContents();
098            byte[] content2 = file2.getContents();
099
100            String originalSource = null;
101            String copySource = null;
102
103            I_CmsTextExtractor textExtractor = null;
104            // only if both files have contents
105            if ((content1.length > 0) && (content2.length > 0)) {
106                if (path1.endsWith(".pdf") && path2.endsWith(".pdf")) {
107                    textExtractor = CmsExtractorPdf.getExtractor();
108                } else if (path1.endsWith(".doc") && path2.endsWith(".doc")) {
109                    textExtractor = CmsExtractorMsOfficeOLE2.getExtractor();
110                } else if (path1.endsWith(".xls") && path2.endsWith(".xls")) {
111                    textExtractor = CmsExtractorMsOfficeOLE2.getExtractor();
112                } else if (path1.endsWith(".rtf") && path2.endsWith(".rtf")) {
113                    textExtractor = CmsExtractorRtf.getExtractor();
114                } else if (path1.endsWith(".ppt") && path2.endsWith(".ppt")) {
115                    textExtractor = CmsExtractorMsOfficeOLE2.getExtractor();
116                }
117            }
118            if (textExtractor != null) {
119                try {
120                    // extract the content
121                    originalSource = textExtractor.extractText(content1).getContent();
122                    copySource = textExtractor.extractText(content2).getContent();
123                } catch (Exception e) {
124                    // something goes wrong on extracting content
125                    // set the content to null, so the content dialog will not be shown
126                    originalSource = null;
127                    copySource = null;
128                    LOG.error(e.getMessage(), e);
129                }
130            } else if ((type instanceof CmsResourceTypePlain)
131                || (type instanceof CmsResourceTypeJsp)
132                || (type instanceof CmsResourceTypePointer)) {
133                try {
134                    originalSource = new String(content1, encoding);
135                    copySource = new String(content2, encoding);
136                } catch (UnsupportedEncodingException e) {
137                    LOG.error(e.getLocalizedMessage(), e);
138                }
139            }
140            if ((copySource == null) || (originalSource == null)) {
141                return Optional.absent();
142            }
143            try {
144                CmsTextDiffPanel diffPanel = new CmsTextDiffPanel(originalSource, copySource, false, true);
145                diffPanel.setWidth("100%");
146                Panel panel = new Panel(
147                    CmsVaadinUtils.getMessageText(Messages.GUI_HISTORY_DIALOG_TEXT_COMPARISON_CAPTION_0));
148                panel.setWidth("100%");
149                VerticalLayout vl = new VerticalLayout();
150                vl.setMargin(true);
151                vl.addComponent(diffPanel);
152
153                panel.setContent(vl);
154                return Optional.<Component> fromNullable(panel);
155            } catch (Exception e) {
156                LOG.error(e.getLocalizedMessage(), e);
157                return Optional.absent();
158            }
159        } else {
160            return Optional.absent();
161        }
162    }
163
164    /**
165    *
166    * Returns a diff text wrapped with formatting style.<p>
167    *
168    * @param diff the text to wrap with CSS formatting
169    * @return the text with formatting styles wrapped
170    * @throws IOException if something goes wrong
171    */
172    protected String wrapLinesWithUnchangedStyle(String diff) throws IOException {
173
174        String line;
175        StringBuffer result = new StringBuffer();
176        BufferedReader br = new BufferedReader(new StringReader(diff));
177        while ((line = br.readLine()) != null) {
178            if ("".equals(line.trim())) {
179                line = "&nbsp;";
180            }
181            result.append("<div class=\"df-unc\"><span class=\"df-unc\">").append(line).append("</span></div>\n");
182        }
183        return result.toString();
184    }
185
186}