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.editors;
029
030import org.opencms.file.CmsObject;
031import org.opencms.file.CmsResource;
032import org.opencms.file.types.CmsResourceTypeBinary;
033import org.opencms.file.types.CmsResourceTypeImage;
034import org.opencms.file.types.CmsResourceTypeJsp;
035import org.opencms.file.types.CmsResourceTypeXmlContent;
036import org.opencms.file.types.CmsResourceTypeXmlPage;
037import org.opencms.file.types.I_CmsResourceType;
038import org.opencms.i18n.CmsMessages;
039import org.opencms.json.JSONException;
040import org.opencms.json.JSONObject;
041import org.opencms.lock.CmsLockUtil.LockedFile;
042import org.opencms.main.CmsRuntimeException;
043import org.opencms.main.OpenCms;
044import org.opencms.ui.A_CmsUI;
045import org.opencms.ui.CmsVaadinUtils;
046import org.opencms.ui.FontOpenCms;
047import org.opencms.ui.apps.CmsAppWorkplaceUi;
048import org.opencms.ui.apps.CmsEditor;
049import org.opencms.ui.apps.I_CmsAppSettings;
050import org.opencms.ui.apps.I_CmsAppUIContext;
051import org.opencms.ui.apps.I_CmsHasShortcutActions;
052import org.opencms.ui.components.CmsConfirmationDialog;
053import org.opencms.ui.components.CmsErrorDialog;
054import org.opencms.ui.components.CmsToolBar;
055import org.opencms.ui.components.I_CmsWindowCloseListener;
056import org.opencms.ui.components.OpenCmsTheme;
057import org.opencms.ui.components.codemirror.CmsCodeMirror;
058import org.opencms.ui.components.codemirror.CmsCodeMirror.CodeMirrorLanguage;
059import org.opencms.xml.content.CmsXmlContent;
060
061import java.util.HashMap;
062import java.util.Map;
063
064import com.vaadin.event.Action;
065import com.vaadin.event.ShortcutAction;
066import com.vaadin.navigator.ViewChangeListener;
067import com.vaadin.ui.Button;
068import com.vaadin.ui.Button.ClickEvent;
069import com.vaadin.ui.Button.ClickListener;
070import com.vaadin.ui.UI;
071import com.vaadin.v7.data.Property.ValueChangeEvent;
072import com.vaadin.v7.data.Property.ValueChangeListener;
073import com.vaadin.v7.ui.ComboBox;
074
075/**
076 * The plain text editor.<p>
077 */
078@SuppressWarnings("deprecation")
079public class CmsSourceEditor
080implements I_CmsEditor, I_CmsWindowCloseListener, ViewChangeListener, I_CmsHasShortcutActions {
081
082    /**
083     * Stores the editor settings.<p>
084     */
085    public static class EditorSettings implements I_CmsAppSettings {
086
087        /** JSON key constant. */
088        private static final String BRACKETS = "brackets";
089        /** JSON key constant. */
090        private static final String FONTSIZE = "fontsize";
091        /** JSON key constant. */
092        private static final String HIGHLIGHTING = "highlighting";
093        /** JSON key constant. */
094        private static final String TABS = "tabs";
095        /** JSON key constant. */
096        private static final String WRAPPING = "wrapping";
097
098        /** The auto close brackets flag. */
099        boolean m_closeBrackets = true;
100
101        /** The font size. */
102        String m_fontSize = "16px";
103
104        /** The highlighting flag. */
105        boolean m_highlighting = true;
106
107        /** The line wrapping flag. */
108        boolean m_lineWrapping;
109
110        /** The tab visibility flag. */
111        boolean m_tabsVisible = true;
112
113        /**
114         * Returns the font size.
115         * @return the font size.
116         */
117        public String getFontSize() {
118
119            return m_fontSize;
120        }
121
122        /**
123         * @see org.opencms.ui.apps.I_CmsAppSettings#getSettingsString()
124         */
125        public String getSettingsString() {
126
127            JSONObject json = new JSONObject();
128            try {
129                json.put(BRACKETS, m_closeBrackets);
130                json.put(HIGHLIGHTING, m_highlighting);
131                json.put(WRAPPING, m_lineWrapping);
132                json.put(FONTSIZE, m_fontSize);
133                json.put(TABS, m_tabsVisible);
134            } catch (JSONException e) {
135                // TODO Auto-generated catch block
136                e.printStackTrace();
137            }
138
139            return json.toString();
140        }
141
142        /**
143         * Returns a flag, indicating if automatically closing brackets is activated.
144         * @return a flag, indicating if automatically closing brackets is activated.
145         */
146        public boolean isCloseBracketsActive() {
147
148            return m_closeBrackets;
149        }
150
151        /**
152         * Returns a flag, indicating if highlighting is activated.
153         * @return a flag, indicating if highlighting is activated.
154         */
155        public boolean isHighlightingActive() {
156
157            return m_highlighting;
158        }
159
160        /**
161         * Returns a flag, indicating if line wrapping is activated.
162         * @return a flag, indicating if line wrapping is activated.
163         */
164        public boolean isLineWrappingActive() {
165
166            return m_lineWrapping;
167        }
168
169        /**
170         * Returns a flag, indicating if tabs should be visible.
171         * @return a flag, indicating if tabs should be visible.
172         */
173        public boolean isTabsVisibleActive() {
174
175            return m_tabsVisible;
176        }
177
178        /**
179         * @see org.opencms.ui.apps.I_CmsAppSettings#restoreSettings(java.lang.String)
180         */
181        public void restoreSettings(String storedSettings) {
182
183            try {
184                JSONObject json = new JSONObject(storedSettings);
185                if (json.has(BRACKETS)) {
186                    m_closeBrackets = json.getBoolean(BRACKETS);
187                }
188                if (json.has(HIGHLIGHTING)) {
189                    m_highlighting = json.getBoolean(HIGHLIGHTING);
190                }
191                if (json.has(WRAPPING)) {
192                    m_lineWrapping = json.getBoolean(WRAPPING);
193                }
194                if (json.has(TABS)) {
195                    m_tabsVisible = json.getBoolean(TABS);
196                }
197                if (json.has(FONTSIZE)) {
198                    m_fontSize = json.getString(FONTSIZE);
199                }
200
201            } catch (JSONException e) {
202                //       LOG.error("Failed to restore file explorer settings from '" + storedSettings + "'", e);
203            }
204        }
205    }
206
207    /** Exit shortcut. */
208    private static final Action ACTION_EXIT = new ShortcutAction(
209        "Ctrl+Shift+X",
210        ShortcutAction.KeyCode.X,
211        new int[] {ShortcutAction.ModifierKey.CTRL, ShortcutAction.ModifierKey.SHIFT});
212
213    /** Exit shortcut, (using Apple CMD as modifier). */
214    private static final Action ACTION_EXIT_CMD = new ShortcutAction(
215        "CMD+Shift+X",
216        ShortcutAction.KeyCode.X,
217        new int[] {ShortcutAction.ModifierKey.META, ShortcutAction.ModifierKey.SHIFT});
218
219    /** Save shortcut. */
220    private static final Action ACTION_SAVE = new ShortcutAction(
221        "Ctrl+S",
222        ShortcutAction.KeyCode.S,
223        new int[] {ShortcutAction.ModifierKey.CTRL});
224
225    /** Save & Exit shortcut. */
226    private static final Action ACTION_SAVE_AND_EXIT = new ShortcutAction(
227        "Ctrl+Shift+S",
228        ShortcutAction.KeyCode.S,
229        new int[] {ShortcutAction.ModifierKey.CTRL, ShortcutAction.ModifierKey.SHIFT});
230
231    /** Save & Exit shortcut, (using Apple CMD as modifier). */
232    private static final Action ACTION_SAVE_AND_EXIT_CMD = new ShortcutAction(
233        "CMD+Shift+S",
234        ShortcutAction.KeyCode.S,
235        new int[] {ShortcutAction.ModifierKey.META, ShortcutAction.ModifierKey.SHIFT});
236
237    /** Save shortcut, (using Apple CMD as modifier). */
238    private static final Action ACTION_SAVE_CMD = new ShortcutAction(
239        "CMD+S",
240        ShortcutAction.KeyCode.S,
241        new int[] {ShortcutAction.ModifierKey.META});
242
243    /** The available font sizes. */
244    private static final String[] FONT_SIZES = new String[] {"8px", "10px", "12px", "14px", "16px", "18px", "20px"};
245
246    /** The serial version id. */
247    private static final long serialVersionUID = 726920483145397926L;
248
249    /** The editor back link. */
250    String m_backLink;
251
252    /** The code mirror instance. */
253    CmsCodeMirror m_codeMirror;
254
255    /** The bundle editor shortcuts. */
256    Map<Action, Runnable> m_shortcutActions;
257
258    /** The content changed flag. */
259    private boolean m_changed;
260
261    /** The cleared flag. */
262    private boolean m_cleared;
263
264    /** The exit button. */
265    private Button m_exit;
266
267    /** The current file. */
268    private LockedFile m_file;
269
270    /** The save button. */
271    private Button m_save;
272
273    /** The save and exit button. */
274    private Button m_saveAndExit;
275
276    /**
277     * Constructor.<p>
278     */
279    public CmsSourceEditor() {
280
281        m_shortcutActions = new HashMap<Action, Runnable>();
282        Runnable save = new Runnable() {
283
284            public void run() {
285
286                save();
287            }
288        };
289        m_shortcutActions.put(ACTION_SAVE, save);
290        m_shortcutActions.put(ACTION_SAVE_CMD, save);
291        Runnable saveExit = new Runnable() {
292
293            public void run() {
294
295                saveAndExit();
296            }
297        };
298        m_shortcutActions.put(ACTION_SAVE_AND_EXIT, saveExit);
299        m_shortcutActions.put(ACTION_SAVE_AND_EXIT_CMD, saveExit);
300        Runnable exit = new Runnable() {
301
302            public void run() {
303
304                exit();
305            }
306        };
307        m_shortcutActions.put(ACTION_EXIT, exit);
308        m_shortcutActions.put(ACTION_EXIT_CMD, exit);
309    }
310
311    /**
312     * @see com.vaadin.navigator.ViewChangeListener#afterViewChange(com.vaadin.navigator.ViewChangeListener.ViewChangeEvent)
313     */
314    public void afterViewChange(ViewChangeEvent event) {
315
316        // nothing to do
317    }
318
319    /**
320     * @see com.vaadin.navigator.ViewChangeListener#beforeViewChange(com.vaadin.navigator.ViewChangeListener.ViewChangeEvent)
321     */
322    public boolean beforeViewChange(final ViewChangeEvent event) {
323
324        if (m_changed) {
325            CmsConfirmationDialog.show(
326                CmsVaadinUtils.getMessageText(org.opencms.ui.apps.Messages.GUI_EDITOR_CLOSE_CAPTION_0),
327                CmsVaadinUtils.getMessageText(org.opencms.ui.apps.Messages.GUI_EDITOR_CLOSE_TEXT_0),
328                new Runnable() {
329
330                    public void run() {
331
332                        clear();
333                        event.getNavigator().navigateTo(event.getViewName());
334                    }
335                });
336            return false;
337        }
338        if (!m_cleared) {
339            clear();
340        }
341        return true;
342    }
343
344    /**
345     * Returns the syntax highlighting type for the currently edited resource.<p>
346     *
347     * @param resource the resource to edit
348     *
349     * @return the syntax highlighting type
350     */
351    public CodeMirrorLanguage getHighlightMode(CmsResource resource) {
352
353        if (resource != null) {
354            // determine resource type
355            int type = resource.getTypeId();
356            if (CmsResourceTypeJsp.isJspTypeId(type)) {
357                // JSP file
358                return CodeMirrorLanguage.JSP;
359            }
360            if (CmsResourceTypeXmlContent.isXmlContent(resource) || CmsResourceTypeXmlPage.isXmlPage(resource)) {
361                // XML content file or XML page file
362                return CodeMirrorLanguage.XML;
363            }
364            // all other files will be matched according to their suffix
365            int dotIndex = resource.getName().lastIndexOf('.');
366            if (dotIndex != -1) {
367                String suffix = resource.getName().substring(dotIndex + 1).toLowerCase();
368                for (CodeMirrorLanguage lang : CodeMirrorLanguage.values()) {
369                    if (lang.isSupportedFileType(suffix)) {
370                        return lang;
371                    }
372                }
373            }
374        }
375        // return HTML type as default
376        return CodeMirrorLanguage.HTML;
377    }
378
379    /**
380     * @see org.opencms.ui.editors.I_CmsEditor#getPriority()
381     */
382    public int getPriority() {
383
384        return 10;
385    }
386
387    /**
388     * @see org.opencms.ui.apps.I_CmsHasShortcutActions#getShortcutActions()
389     */
390    public Map<Action, Runnable> getShortcutActions() {
391
392        return m_shortcutActions;
393    }
394
395    /**
396     * @see org.opencms.ui.editors.I_CmsEditor#initUI(org.opencms.ui.apps.I_CmsAppUIContext, org.opencms.file.CmsResource, java.lang.String, java.util.Map)
397     */
398    public void initUI(I_CmsAppUIContext context, CmsResource resource, String backLink, Map<String, String> params) {
399
400        CmsObject cms = A_CmsUI.getCmsObject();
401        if (OpenCms.getADEManager().isEditorRestricted(cms, resource)) {
402            throw new CmsRuntimeException(
403                org.opencms.ade.contenteditor.Messages.get().container(
404                    org.opencms.ade.contenteditor.Messages.ERR_EDITOR_RESTRICTED_0));
405        }
406        CmsMessages messages = Messages.get().getBundle(UI.getCurrent().getLocale());
407        context.showInfoArea(false);
408        context.setAppTitle(messages.key(Messages.GUI_SOURCE_EDITOR_TITLE_0));
409        CmsAppWorkplaceUi.setWindowTitle(
410            CmsVaadinUtils.getMessageText(
411                org.opencms.ui.apps.Messages.GUI_CONTENT_EDITOR_TITLE_2,
412                resource.getName(),
413                CmsResource.getParentFolder(A_CmsUI.getCmsObject().getSitePath(resource))));
414        m_backLink = backLink;
415        m_codeMirror = new CmsCodeMirror();
416        m_codeMirror.setSizeFull();
417        context.setAppContent(m_codeMirror);
418        context.enableDefaultToolbarButtons(false);
419        m_saveAndExit = CmsToolBar.createButton(
420            FontOpenCms.SAVE_EXIT,
421            messages.key(Messages.GUI_BUTTON_SAVE_AND_EXIT_0),
422            true);
423        m_saveAndExit.addClickListener(new ClickListener() {
424
425            private static final long serialVersionUID = 1L;
426
427            public void buttonClick(ClickEvent event) {
428
429                saveAndExit();
430            }
431
432        });
433        m_saveAndExit.setEnabled(false);
434        context.addToolbarButton(m_saveAndExit);
435
436        m_save = CmsToolBar.createButton(FontOpenCms.SAVE, messages.key(Messages.GUI_BUTTON_SAVE_0), true);
437        m_save.addClickListener(new ClickListener() {
438
439            private static final long serialVersionUID = 1L;
440
441            public void buttonClick(ClickEvent event) {
442
443                save();
444            }
445
446        });
447        m_save.setEnabled(false);
448        context.addToolbarButton(m_save);
449
450        Button undo = CmsToolBar.createButton(FontOpenCms.UNDO, messages.key(Messages.GUI_BUTTON_UNDO_0), true);
451        context.addToolbarButton(undo);
452
453        Button redo = CmsToolBar.createButton(FontOpenCms.REDO, messages.key(Messages.GUI_BUTTON_REDO_0), true);
454        context.addToolbarButton(redo);
455
456        m_codeMirror.registerUndoRedo(undo, redo);
457
458        Button search = CmsToolBar.createButton(FontOpenCms.SEARCH, messages.key(Messages.GUI_BUTTON_SEARCH_0), true);
459        context.addToolbarButton(search);
460
461        Button replace = CmsToolBar.createButton(
462            FontOpenCms.SEARCH_REPLACE,
463            messages.key(Messages.GUI_BUTTON_REPLACE_0),
464            true);
465        context.addToolbarButton(replace);
466
467        m_codeMirror.registerSearchReplace(search, replace);
468
469        EditorSettings settings;
470        try {
471            settings = OpenCms.getWorkplaceAppManager().getAppSettings(A_CmsUI.getCmsObject(), EditorSettings.class);
472
473        } catch (Exception e) {
474            settings = new EditorSettings();
475        }
476
477        final Button toggleHighlight = CmsToolBar.createButton(
478            FontOpenCms.HIGHLIGHT,
479            messages.key(Messages.GUI_BUTTON_TOGGLE_HIGHLIGHTING_0));
480        toggleHighlight.addClickListener(new ClickListener() {
481
482            private static final long serialVersionUID = 1L;
483
484            public void buttonClick(ClickEvent event) {
485
486                Button b = event.getButton();
487                boolean pressed = b.getStyleName().contains(OpenCmsTheme.BUTTON_PRESSED);
488                if (pressed) {
489                    b.removeStyleName(OpenCmsTheme.BUTTON_PRESSED);
490                } else {
491                    b.addStyleName(OpenCmsTheme.BUTTON_PRESSED);
492                }
493                m_codeMirror.setHighlighting(!pressed);
494            }
495
496        });
497        if (settings.m_highlighting) {
498            m_codeMirror.setHighlighting(true);
499            toggleHighlight.addStyleName(OpenCmsTheme.BUTTON_PRESSED);
500        } else {
501            m_codeMirror.setHighlighting(false);
502        }
503        context.addToolbarButtonRight(toggleHighlight);
504
505        final Button toggleLineWrap = CmsToolBar.createButton(
506            FontOpenCms.WRAP_LINES,
507            messages.key(Messages.GUI_BUTTON_TOGGLE_LINE_WRAPPING_0));
508        toggleLineWrap.addClickListener(new ClickListener() {
509
510            private static final long serialVersionUID = 1L;
511
512            public void buttonClick(ClickEvent event) {
513
514                Button b = event.getButton();
515                boolean pressed = b.getStyleName().contains(OpenCmsTheme.BUTTON_PRESSED);
516                if (pressed) {
517                    b.removeStyleName(OpenCmsTheme.BUTTON_PRESSED);
518                } else {
519                    b.addStyleName(OpenCmsTheme.BUTTON_PRESSED);
520                }
521                m_codeMirror.setLineWrapping(!pressed);
522            }
523
524        });
525        if (settings.m_lineWrapping) {
526            m_codeMirror.setLineWrapping(true);
527            toggleLineWrap.addStyleName(OpenCmsTheme.BUTTON_PRESSED);
528        } else {
529            m_codeMirror.setLineWrapping(false);
530        }
531        context.addToolbarButtonRight(toggleLineWrap);
532
533        final Button toggleBrackets = CmsToolBar.createButton(
534            FontOpenCms.BRACKETS,
535            messages.key(Messages.GUI_BUTTON_TOBBLE_BRACKET_AUTOCLOSE_0));
536        toggleBrackets.addClickListener(new ClickListener() {
537
538            private static final long serialVersionUID = 1L;
539
540            public void buttonClick(ClickEvent event) {
541
542                Button b = event.getButton();
543                boolean pressed = b.getStyleName().contains(OpenCmsTheme.BUTTON_PRESSED);
544                if (pressed) {
545                    b.removeStyleName(OpenCmsTheme.BUTTON_PRESSED);
546                } else {
547                    b.addStyleName(OpenCmsTheme.BUTTON_PRESSED);
548                }
549                m_codeMirror.setCloseBrackets(!pressed);
550            }
551
552        });
553        if (settings.m_closeBrackets) {
554            m_codeMirror.setCloseBrackets(true);
555            toggleBrackets.addStyleName(OpenCmsTheme.BUTTON_PRESSED);
556        } else {
557            m_codeMirror.setCloseBrackets(false);
558        }
559        context.addToolbarButtonRight(toggleBrackets);
560
561        final Button toggleTabs = CmsToolBar.createButton(
562            FontOpenCms.INVISIBLE_CHARS,
563            messages.key(Messages.GUI_BUTTON_TOGGLE_TAB_VISIBILITY_0));
564        toggleTabs.addClickListener(new ClickListener() {
565
566            private static final long serialVersionUID = 1L;
567
568            public void buttonClick(ClickEvent event) {
569
570                Button b = event.getButton();
571                boolean pressed = b.getStyleName().contains(OpenCmsTheme.BUTTON_PRESSED);
572                if (pressed) {
573                    b.removeStyleName(OpenCmsTheme.BUTTON_PRESSED);
574                } else {
575                    b.addStyleName(OpenCmsTheme.BUTTON_PRESSED);
576                }
577                m_codeMirror.setTabsVisible(!pressed);
578            }
579
580        });
581        if (settings.m_tabsVisible) {
582            m_codeMirror.setTabsVisible(true);
583            toggleTabs.addStyleName(OpenCmsTheme.BUTTON_PRESSED);
584        } else {
585            m_codeMirror.setTabsVisible(false);
586        }
587        context.addToolbarButtonRight(toggleTabs);
588
589        ComboBox modeSelect = new ComboBox();
590        modeSelect.setWidth("115px");
591        modeSelect.addStyleName(OpenCmsTheme.TOOLBAR_FIELD);
592        modeSelect.addStyleName(OpenCmsTheme.REQUIRED_BUTTON);
593        modeSelect.setNullSelectionAllowed(false);
594        modeSelect.setImmediate(true);
595        modeSelect.setNewItemsAllowed(false);
596        for (CodeMirrorLanguage lang : CodeMirrorLanguage.values()) {
597            modeSelect.addItem(lang);
598            modeSelect.setItemCaption(lang, lang.name());
599        }
600        CodeMirrorLanguage lang = getHighlightMode(resource);
601        modeSelect.setValue(lang);
602        m_codeMirror.setLanguage(lang);
603        modeSelect.addValueChangeListener(new ValueChangeListener() {
604
605            private static final long serialVersionUID = 1L;
606
607            public void valueChange(ValueChangeEvent event) {
608
609                m_codeMirror.setLanguage((CodeMirrorLanguage)event.getProperty().getValue());
610            }
611        });
612        context.addToolbarButtonRight(modeSelect);
613
614        ComboBox fontSizeSelect = new ComboBox();
615        fontSizeSelect.setWidth("75px");
616        fontSizeSelect.addStyleName(OpenCmsTheme.TOOLBAR_FIELD);
617        fontSizeSelect.addStyleName(OpenCmsTheme.REQUIRED_BUTTON);
618        fontSizeSelect.setNullSelectionAllowed(false);
619        fontSizeSelect.setImmediate(true);
620        fontSizeSelect.setNewItemsAllowed(false);
621        for (int i = 0; i < FONT_SIZES.length; i++) {
622            fontSizeSelect.addItem(FONT_SIZES[i]);
623        }
624        fontSizeSelect.setValue(settings.m_fontSize);
625        fontSizeSelect.addValueChangeListener(new ValueChangeListener() {
626
627            private static final long serialVersionUID = 1L;
628
629            public void valueChange(ValueChangeEvent event) {
630
631                m_codeMirror.setFontSize((String)event.getProperty().getValue());
632            }
633        });
634        context.addToolbarButtonRight(fontSizeSelect);
635        m_codeMirror.setFontSize(settings.m_fontSize);
636
637        m_exit = CmsToolBar.createButton(FontOpenCms.EXIT, messages.key(Messages.GUI_BUTTON_CANCEL_0), true);
638        m_exit.addClickListener(new ClickListener() {
639
640            private static final long serialVersionUID = 1L;
641
642            public void buttonClick(ClickEvent event) {
643
644                exit();
645            }
646
647        });
648        context.addToolbarButtonRight(m_exit);
649
650        try {
651            m_file = LockedFile.lockResource(A_CmsUI.getCmsObject(), resource);
652            String content = new String(m_file.getFile().getContents(), m_file.getEncoding());
653            m_codeMirror.setValue(content);
654        } catch (Exception e) {
655            CmsErrorDialog.showErrorDialog(e);
656        }
657        m_codeMirror.addValueChangeListener(new ValueChangeListener() {
658
659            private static final long serialVersionUID = 1L;
660
661            public void valueChange(ValueChangeEvent event) {
662
663                onChange((String)event.getProperty().getValue());
664            }
665        });
666    }
667
668    /**
669     * @see org.opencms.ui.editors.I_CmsEditor#matchesResource(org.opencms.file.CmsObject, org.opencms.file.CmsResource, boolean)
670     */
671    public boolean matchesResource(CmsObject cms, CmsResource resource, boolean plainText) {
672
673        I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(resource);
674        return matchesType(type, plainText);
675    }
676
677    /**
678     * @see org.opencms.ui.editors.I_CmsEditor#matchesType(org.opencms.file.types.I_CmsResourceType, boolean)
679     */
680    public boolean matchesType(I_CmsResourceType type, boolean plainText) {
681
682        return !((type instanceof CmsResourceTypeBinary) || (type instanceof CmsResourceTypeImage));
683    }
684
685    /**
686     * @see org.opencms.ui.editors.I_CmsEditor#newInstance()
687     */
688    public I_CmsEditor newInstance() {
689
690        return new CmsSourceEditor();
691    }
692
693    /**
694     * @see org.opencms.ui.components.I_CmsWindowCloseListener#onWindowClose()
695     */
696    public void onWindowClose() {
697
698        clear();
699    }
700
701    /**
702     * Unlocks the edited file before leaving the editor.<p>
703     */
704    void clear() {
705
706        m_cleared = true;
707        m_changed = false;
708        m_file.tryUnlock();
709        OpenCms.getWorkplaceAppManager().storeAppSettings(
710            A_CmsUI.getCmsObject(),
711            EditorSettings.class,
712            getCurrentSettings());
713    }
714
715    /**
716     * Exits the editor without saving.<p>
717     * Will ask to confirm exit on changed contents.<p>
718     */
719    void exit() {
720
721        if (m_changed) {
722            CmsConfirmationDialog.show(
723                CmsVaadinUtils.getMessageText(org.opencms.ui.apps.Messages.GUI_EDITOR_CLOSE_CAPTION_0),
724                CmsVaadinUtils.getMessageText(org.opencms.ui.apps.Messages.GUI_EDITOR_CLOSE_TEXT_0),
725                new Runnable() {
726
727                    public void run() {
728
729                        exitInternal();
730                    }
731                });
732        } else {
733            exitInternal();
734        }
735
736    }
737
738    /**
739     * Exits the editor without saving.<p>
740     */
741    void exitInternal() {
742
743        clear();
744        CmsEditor.openBackLink(m_backLink);
745    }
746
747    /**
748     * Called on content change.<p>
749     *
750     * @param value the changed content value
751     */
752    void onChange(String value) {
753
754        m_changed = true;
755        m_save.setEnabled(true);
756        m_saveAndExit.setEnabled(true);
757    }
758
759    /**
760     * Saves the current editor content.<p>
761     */
762    void save() {
763
764        CmsObject cms = A_CmsUI.getCmsObject();
765        try {
766            byte[] content = m_codeMirror.getValue().getBytes(m_file.getEncoding());
767            m_file.getFile().setContents(content);
768            cms.getRequestContext().setAttribute(CmsXmlContent.AUTO_CORRECTION_ATTRIBUTE, Boolean.TRUE);
769            cms.writeFile(m_file.getFile());
770            m_changed = false;
771            m_save.setEnabled(false);
772            m_saveAndExit.setEnabled(false);
773        } catch (Exception e) {
774            CmsErrorDialog.showErrorDialog(e);
775        } finally {
776            cms.getRequestContext().removeAttribute(CmsXmlContent.AUTO_CORRECTION_ATTRIBUTE);
777        }
778    }
779
780    /**
781     * Saves the current editor content and leaves the editor.<p>
782     */
783    void saveAndExit() {
784
785        save();
786        exit();
787    }
788
789    /**
790     * Returns the current editor settings.<p>
791     *
792     * @return the current editor settings
793     */
794    private EditorSettings getCurrentSettings() {
795
796        EditorSettings result = new EditorSettings();
797        result.m_closeBrackets = m_codeMirror.isCloseBrackets();
798        result.m_lineWrapping = m_codeMirror.isLineWrapping();
799        result.m_highlighting = m_codeMirror.isHighlighting();
800        result.m_tabsVisible = m_codeMirror.isTabsVisible();
801        result.m_fontSize = m_codeMirror.getFontSize();
802        return result;
803    }
804}