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