001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://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: https://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: https://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.workplace.comparison;
029
030import com.alkacon.diff.Diff;
031
032import org.opencms.jsp.CmsJspActionElement;
033import org.opencms.util.CmsStringUtil;
034import org.opencms.workplace.CmsDialog;
035import org.opencms.workplace.CmsWorkplace;
036import org.opencms.workplace.CmsWorkplaceSettings;
037import org.opencms.workplace.list.A_CmsListDialog;
038import org.opencms.workplace.tools.A_CmsHtmlIconButton;
039import org.opencms.workplace.tools.CmsHtmlIconButtonStyleEnum;
040
041import java.io.BufferedReader;
042import java.io.IOException;
043import java.io.StringReader;
044
045import jakarta.servlet.http.HttpServletRequest;
046import jakarta.servlet.jsp.JspException;
047import jakarta.servlet.jsp.JspWriter;
048
049/**
050 * Provides a GUI for the configuration file comparison dialog.<p>
051 *
052 * @since 6.0.0
053 */
054public abstract class A_CmsDiffViewDialog extends CmsDialog {
055
056    /** Diff mode. */
057    private CmsDiffViewMode m_mode;
058
059    /**
060     * Default constructor.<p>
061     *
062     * @param jsp an initialized JSP action element
063     */
064    protected A_CmsDiffViewDialog(CmsJspActionElement jsp) {
065
066        super(jsp);
067        setParamStyle(STYLE_NEW);
068    }
069
070    /**
071     * Returns the html code for a deactivated empfasized button.<p>
072     *
073     * @param name the label of the button
074     * @param iconPath the path to the icon
075     *
076     * @return the html code for a deactivated empfasized button
077     */
078    public String deactivatedEmphasizedButtonHtml(String name, String iconPath) {
079
080        StringBuffer result = new StringBuffer();
081        result.append(
082            "<span style='vertical-align:middle;'><img style='width:20px;height:20px;display:inline;vertical-align:middle;text-decoration:none;' src=\'");
083        result.append(CmsWorkplace.getSkinUri());
084        result.append(iconPath);
085        result.append("\' alt=\'");
086        result.append(name);
087        result.append("\' title=\'");
088        result.append(name);
089        result.append("\'>&nbsp;<b>");
090        result.append(name);
091        result.append("</b></span>");
092        return result.toString();
093    }
094
095    /**
096     * Performs the dialog actions depending on the initialized action and displays the dialog form.<p>
097     *
098     * @throws Exception if writing to the JSP out fails
099     */
100    public void displayDialog() throws Exception {
101
102        if (getAction() == ACTION_CANCEL) {
103            actionCloseDialog();
104        }
105        JspWriter out = getJsp().getJspContext().getOut();
106        out.print("<link rel='stylesheet' type='text/css' href='");
107        out.print(getStyleUri(getJsp()));
108        out.println("diff.css'>");
109        out.println(dialogContentStart(getParamTitle()));
110        out.print("<form name='diff-form' method='post' action='");
111        out.print(getDialogUri());
112        out.println("'>");
113        out.println(allParamsAsHidden());
114        out.println("</form>");
115        // icon is displayed on the right in order that the user needs not scroll to the icon for long lines
116        out.println("<p>");
117        out.println(getDiffOnlyButtonsHtml());
118        out.println("</p>");
119        out.println(dialogBlockStart(null));
120        out.println("<table cellspacing='0' cellpadding='0' class='xmlTable'>\n<tr><td><pre style='overflow:auto'>");
121        try {
122            CmsHtmlDifferenceConfiguration conf = new CmsHtmlDifferenceConfiguration(
123                getMode() == CmsDiffViewMode.ALL ? -1 : getLinesBeforeSkip(),
124                getLocale());
125            String diff = Diff.diffAsHtml(getOriginalSource(), getCopySource(), conf);
126            if (CmsStringUtil.isNotEmpty(diff)) {
127                out.println(diff);
128            } else {
129                // print original source, if there are no differences
130                out.println(
131                    wrapLinesWithUnchangedStyle(
132                        CmsStringUtil.substitute(CmsStringUtil.escapeHtml(getOriginalSource()), "<br/>", "")));
133            }
134        } catch (Exception e) {
135            out.print(e);
136        }
137        out.println("</pre></td></tr>\n</table>");
138        out.println(dialogBlockEnd());
139        out.println(dialogContentEnd());
140        out.println(dialogEnd());
141        out.println(bodyEnd());
142        out.println(htmlEnd());
143    }
144
145    /**
146     * Returns the mode.<p>
147     *
148     * @return the mode
149     */
150    public CmsDiffViewMode getMode() {
151
152        return m_mode;
153    }
154
155    /**
156     * Returns the parameter value for the Mode.<p>
157     *
158     * @return the parameter value for the Mode
159     */
160    public String getParamMode() {
161
162        if (m_mode == null) {
163            return null;
164        }
165        return m_mode.getMode();
166    }
167
168    /**
169     * Returns the html for two buttons, whereby the third parameter determines which one is active.<p>
170     *
171     * @param label1 the label for the first button
172     * @param label2 the label for the second button
173     * @param firstActive a flag indicating wheter the first or second button is active
174     * @param onClick1 the action to be performed if the first button is clicked
175     * @param onClick2 the action to be performed if the second button is clicked
176     *
177     * @return the html for two buttons, whereby the third parameter determines which one is active
178     */
179    public String getTwoButtonsHtml(
180        String label1,
181        String label2,
182        String onClick1,
183        String onClick2,
184        boolean firstActive) {
185
186        StringBuffer result = new StringBuffer();
187        if (firstActive) {
188            result.append(
189                A_CmsHtmlIconButton.defaultButtonHtml(
190                    CmsHtmlIconButtonStyleEnum.SMALL_ICON_TEXT,
191                    "id",
192                    label1,
193                    null,
194                    true,
195                    A_CmsListDialog.ICON_DETAILS_SHOW,
196                    null,
197                    onClick1));
198            result.append("&nbsp;&nbsp;");
199            result.append(deactivatedEmphasizedButtonHtml(label2, A_CmsListDialog.ICON_DETAILS_HIDE));
200        } else {
201
202            result.append(deactivatedEmphasizedButtonHtml(label1, A_CmsListDialog.ICON_DETAILS_HIDE));
203            result.append("&nbsp;&nbsp;");
204            result.append(
205                A_CmsHtmlIconButton.defaultButtonHtml(
206                    CmsHtmlIconButtonStyleEnum.SMALL_ICON_TEXT,
207                    "id",
208                    label2,
209                    null,
210                    true,
211                    A_CmsListDialog.ICON_DETAILS_SHOW,
212                    null,
213                    onClick2));
214        }
215        result.append("&nbsp;&nbsp;");
216        return result.toString();
217    }
218
219    /**
220     * Sets the mode.<p>
221     *
222     * @param mode the mode to set
223     */
224    public void setMode(CmsDiffViewMode mode) {
225
226        m_mode = mode;
227    }
228
229    /**
230     * Sets the parameter value for the Mode.<p>
231     *
232     * @param mode the parameter value for the Mode to set
233     */
234    public void setParamMode(String mode) {
235
236        m_mode = CmsDiffViewMode.valueOf(mode);
237    }
238
239    /**
240     * Returns the text to compare as copy.<p>
241     *
242     * @return the text to compare as copy
243     */
244    protected abstract String getCopySource();
245
246    /**
247     * Returns the number of lines to show before they are skipped.<p>
248     *
249     * @return the number of lines to show before they are skipped
250     */
251    protected abstract int getLinesBeforeSkip();
252
253    /**
254     * Returns the text to compare as original.<p>
255     *
256     * @return the text to compare as original
257     */
258    protected abstract String getOriginalSource();
259
260    /**
261     * @see org.opencms.workplace.CmsWorkplace#initWorkplaceRequestValues(org.opencms.workplace.CmsWorkplaceSettings, jakarta.servlet.http.HttpServletRequest)
262     */
263    @Override
264    protected void initWorkplaceRequestValues(CmsWorkplaceSettings settings, HttpServletRequest request) {
265
266        super.initWorkplaceRequestValues(settings, request);
267        if (CmsStringUtil.isEmptyOrWhitespaceOnly(getParamMode())) {
268            // ensure a valid mode is set
269            m_mode = CmsDiffViewMode.DIFF_ONLY;
270        }
271        // test the needed parameters
272        try {
273            validateParamaters();
274        } catch (Exception e) {
275            // close if parameters not available
276            setAction(ACTION_CANCEL);
277            try {
278                actionCloseDialog();
279            } catch (JspException e1) {
280                // noop
281            }
282            return;
283        }
284    }
285
286    /**
287     * Validates the parameters.<p>
288     *
289     * @throws Exception if something goes wrong
290     */
291    protected abstract void validateParamaters() throws Exception;
292
293    /**
294     *
295     * Returns a diff text wrapped with formatting style.<p>
296     *
297     * @param diff the text to wrap with CSS formatting
298     * @return the text with formatting styles wrapped
299     * @throws IOException if something goes wrong
300     */
301    protected String wrapLinesWithUnchangedStyle(String diff) throws IOException {
302
303        String line;
304        StringBuffer result = new StringBuffer();
305        BufferedReader br = new BufferedReader(new StringReader(diff));
306        while ((line = br.readLine()) != null) {
307            if ("".equals(line.trim())) {
308                line = "&nbsp;";
309            }
310            result.append("<div class=\"df-unc\"><span class=\"df-unc\">").append(line).append("</span></div>\n");
311        }
312        return result.toString();
313    }
314
315    /**
316     * Returns the html code for the buttons 'show only differences' and 'show everything'.<p>
317     *
318     * @return the html code for the buttons 'show only differences' and 'show everything'
319     */
320    String getDiffOnlyButtonsHtml() {
321
322        StringBuffer result = new StringBuffer();
323        if (!getOriginalSource().equals(getCopySource())) {
324            String onClick1 = "javascript:document.forms['diff-form'].mode.value = '";
325            String onClick2 = "javascript:document.forms['diff-form'].mode.value = '";
326            onClick1 += CmsDiffViewMode.ALL;
327            onClick2 += CmsDiffViewMode.DIFF_ONLY;
328            onClick1 += "'; document.forms['diff-form'].submit();";
329            onClick2 += "'; document.forms['diff-form'].submit();";
330            result.append(
331                getTwoButtonsHtml(
332                    CmsDiffViewMode.DIFF_ONLY.getName().key(getLocale()),
333                    CmsDiffViewMode.ALL.getName().key(getLocale()),
334                    onClick1,
335                    onClick2,
336                    getMode() == CmsDiffViewMode.DIFF_ONLY));
337        } else {
338            // display all text, if there are no differences
339            setMode(CmsDiffViewMode.ALL);
340        }
341        return result.toString();
342    }
343
344}