Java tutorial
/* * This library is part of OpenCms - * the Open Source Content Management System * * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * For further information about Alkacon Software, please see the * company website: http://www.alkacon.com * * For further information about OpenCms, please see the * project website: http://www.opencms.org * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.opencms.ui.editors; import org.opencms.file.CmsResource; import org.opencms.file.types.CmsResourceTypeBinary; import org.opencms.file.types.CmsResourceTypeImage; import org.opencms.file.types.CmsResourceTypeJsp; import org.opencms.file.types.CmsResourceTypeXmlContent; import org.opencms.file.types.CmsResourceTypeXmlPage; import org.opencms.file.types.I_CmsResourceType; import org.opencms.i18n.CmsMessages; import org.opencms.json.JSONException; import org.opencms.json.JSONObject; import org.opencms.lock.CmsLockUtil.LockedFile; import org.opencms.main.CmsException; import org.opencms.main.OpenCms; import org.opencms.ui.A_CmsUI; import org.opencms.ui.CmsVaadinUtils; import org.opencms.ui.FontOpenCms; import org.opencms.ui.apps.CmsAppWorkplaceUi; import org.opencms.ui.apps.CmsEditor; import org.opencms.ui.apps.I_CmsAppSettings; import org.opencms.ui.apps.I_CmsAppUIContext; import org.opencms.ui.apps.I_CmsHasShortcutActions; import org.opencms.ui.components.CmsConfirmationDialog; import org.opencms.ui.components.CmsErrorDialog; import org.opencms.ui.components.CmsToolBar; import org.opencms.ui.components.I_CmsWindowCloseListener; import org.opencms.ui.components.OpenCmsTheme; import org.opencms.ui.components.codemirror.CmsCodeMirror; import org.opencms.ui.components.codemirror.CmsCodeMirror.CodeMirrorLanguage; import java.util.HashMap; import java.util.Map; import com.vaadin.data.Property.ValueChangeEvent; import com.vaadin.data.Property.ValueChangeListener; import com.vaadin.event.Action; import com.vaadin.event.ShortcutAction; import com.vaadin.navigator.ViewChangeListener; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.ComboBox; import com.vaadin.ui.UI; /** * The plain text editor.<p> */ public class CmsSourceEditor implements I_CmsEditor, I_CmsWindowCloseListener, ViewChangeListener, I_CmsHasShortcutActions { /** * Stores the editor settings.<p> */ public static class EditorSettings implements I_CmsAppSettings { /** JSON key constant. */ private static final String BRACKETS = "brackets"; /** JSON key constant. */ private static final String FONTSIZE = "fontsize"; /** JSON key constant. */ private static final String HIGHLIGHTING = "highlighting"; /** JSON key constant. */ private static final String TABS = "tabs"; /** JSON key constant. */ private static final String WRAPPING = "wrapping"; /** The auto close brackets flag. */ boolean m_closeBrackets = true; /** The font size. */ String m_fontSize = "16px"; /** The highlighting flag. */ boolean m_highlighting = true; /** The line wrapping flag. */ boolean m_lineWrapping = false; /** The tab visibility flag. */ boolean m_tabsVisible = true; /** * @see org.opencms.ui.apps.I_CmsAppSettings#getSettingsString() */ public String getSettingsString() { JSONObject json = new JSONObject(); try { json.put(BRACKETS, m_closeBrackets); json.put(HIGHLIGHTING, m_highlighting); json.put(WRAPPING, m_lineWrapping); json.put(FONTSIZE, m_fontSize); json.put(TABS, m_tabsVisible); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } return json.toString(); } /** * @see org.opencms.ui.apps.I_CmsAppSettings#restoreSettings(java.lang.String) */ public void restoreSettings(String storedSettings) { try { JSONObject json = new JSONObject(storedSettings); if (json.has(BRACKETS)) { m_closeBrackets = json.getBoolean(BRACKETS); } if (json.has(HIGHLIGHTING)) { m_highlighting = json.getBoolean(HIGHLIGHTING); } if (json.has(WRAPPING)) { m_lineWrapping = json.getBoolean(WRAPPING); } if (json.has(TABS)) { m_tabsVisible = json.getBoolean(TABS); } if (json.has(FONTSIZE)) { m_fontSize = json.getString(FONTSIZE); } } catch (JSONException e) { // LOG.error("Failed to restore file explorer settings from '" + storedSettings + "'", e); } } } /** Exit shortcut. */ private static final Action ACTION_EXIT = new ShortcutAction("Ctrl+Shift+X", ShortcutAction.KeyCode.X, new int[] { ShortcutAction.ModifierKey.CTRL, ShortcutAction.ModifierKey.SHIFT }); /** Save shortcut. */ private static final Action ACTION_SAVE = new ShortcutAction("Ctrl+S", ShortcutAction.KeyCode.S, new int[] { ShortcutAction.ModifierKey.CTRL }); /** Save & Exit shortcut. */ private static final Action ACTION_SAVE_AND_EXIT = new ShortcutAction("Ctrl+Shift+S", ShortcutAction.KeyCode.S, new int[] { ShortcutAction.ModifierKey.CTRL, ShortcutAction.ModifierKey.SHIFT }); /** The available font sizes. */ private static final String[] FONT_SIZES = new String[] { "8px", "10px", "12px", "14px", "16px", "18px", "20px" }; /** The serial version id. */ private static final long serialVersionUID = 726920483145397926L; /** The editor back link. */ String m_backLink; /** The code mirror instance. */ CmsCodeMirror m_codeMirror; /** The bundle editor shortcuts. */ Map<Action, Runnable> m_shortcutActions; /** The content changed flag. */ private boolean m_changed; /** The cleared flag. */ private boolean m_cleared; /** The exit button. */ private Button m_exit; /** The current file. */ private LockedFile m_file; /** The save button. */ private Button m_save; /** The save and exit button. */ private Button m_saveAndExit; /** * Constructor.<p> */ public CmsSourceEditor() { m_shortcutActions = new HashMap<Action, Runnable>(); m_shortcutActions.put(ACTION_SAVE, new Runnable() { public void run() { save(); } }); m_shortcutActions.put(ACTION_SAVE_AND_EXIT, new Runnable() { public void run() { saveAndExit(); } }); m_shortcutActions.put(ACTION_EXIT, new Runnable() { public void run() { exit(); } }); } /** * @see com.vaadin.navigator.ViewChangeListener#afterViewChange(com.vaadin.navigator.ViewChangeListener.ViewChangeEvent) */ public void afterViewChange(ViewChangeEvent event) { // nothing to do } /** * @see com.vaadin.navigator.ViewChangeListener#beforeViewChange(com.vaadin.navigator.ViewChangeListener.ViewChangeEvent) */ public boolean beforeViewChange(final ViewChangeEvent event) { if (m_changed) { CmsConfirmationDialog.show( CmsVaadinUtils.getMessageText(org.opencms.ui.apps.Messages.GUI_EDITOR_CLOSE_CAPTION_0), CmsVaadinUtils.getMessageText(org.opencms.ui.apps.Messages.GUI_EDITOR_CLOSE_TEXT_0), new Runnable() { public void run() { clear(); event.getNavigator().navigateTo(event.getViewName()); } }); return false; } if (!m_cleared) { clear(); } return true; } /** * Returns the syntax highlighting type for the currently edited resource.<p> * * @param resource the resource to edit * * @return the syntax highlighting type */ public CodeMirrorLanguage getHighlightMode(CmsResource resource) { if (resource != null) { // determine resource type int type = resource.getTypeId(); if (CmsResourceTypeJsp.isJspTypeId(type)) { // JSP file return CodeMirrorLanguage.JSP; } if (CmsResourceTypeXmlContent.isXmlContent(resource) || CmsResourceTypeXmlPage.isXmlPage(resource)) { // XML content file or XML page file return CodeMirrorLanguage.XML; } // all other files will be matched according to their suffix int dotIndex = resource.getName().lastIndexOf('.'); if (dotIndex != -1) { String suffix = resource.getName().substring(dotIndex + 1).toLowerCase(); for (CodeMirrorLanguage lang : CodeMirrorLanguage.values()) { if (lang.isSupportedFileType(suffix)) { return lang; } } } } // return HTML type as default return CodeMirrorLanguage.HTML; } /** * @see org.opencms.ui.editors.I_CmsEditor#getPriority() */ public int getPriority() { return 10; } /** * @see org.opencms.ui.apps.I_CmsHasShortcutActions#getShortcutActions() */ public Map<Action, Runnable> getShortcutActions() { return m_shortcutActions; } /** * @see org.opencms.ui.editors.I_CmsEditor#initUI(org.opencms.ui.apps.I_CmsAppUIContext, org.opencms.file.CmsResource, java.lang.String) */ public void initUI(I_CmsAppUIContext context, CmsResource resource, String backLink) { CmsMessages messages = Messages.get().getBundle(UI.getCurrent().getLocale()); context.showInfoArea(false); context.setAppTitle(messages.key(Messages.GUI_SOURCE_EDITOR_TITLE_0)); CmsAppWorkplaceUi.setWindowTitle(CmsVaadinUtils.getMessageText( org.opencms.ui.apps.Messages.GUI_CONTENT_EDITOR_TITLE_2, resource.getName(), CmsResource.getParentFolder(A_CmsUI.getCmsObject().getSitePath(resource)))); m_backLink = backLink; m_codeMirror = new CmsCodeMirror(); m_codeMirror.setSizeFull(); context.setAppContent(m_codeMirror); context.enableDefaultToolbarButtons(false); m_saveAndExit = CmsToolBar.createButton(FontOpenCms.SAVE_EXIT, messages.key(Messages.GUI_BUTTON_SAVE_AND_EXIT_0), true); m_saveAndExit.addClickListener(new ClickListener() { private static final long serialVersionUID = 1L; public void buttonClick(ClickEvent event) { saveAndExit(); } }); m_saveAndExit.setEnabled(false); context.addToolbarButton(m_saveAndExit); m_save = CmsToolBar.createButton(FontOpenCms.SAVE, messages.key(Messages.GUI_BUTTON_SAVE_0), true); m_save.addClickListener(new ClickListener() { private static final long serialVersionUID = 1L; public void buttonClick(ClickEvent event) { save(); } }); m_save.setEnabled(false); context.addToolbarButton(m_save); Button undo = CmsToolBar.createButton(FontOpenCms.UNDO, messages.key(Messages.GUI_BUTTON_UNDO_0), true); context.addToolbarButton(undo); Button redo = CmsToolBar.createButton(FontOpenCms.REDO, messages.key(Messages.GUI_BUTTON_REDO_0), true); context.addToolbarButton(redo); m_codeMirror.registerUndoRedo(undo, redo); Button search = CmsToolBar.createButton(FontOpenCms.SEARCH, messages.key(Messages.GUI_BUTTON_SEARCH_0), true); context.addToolbarButton(search); Button replace = CmsToolBar.createButton(FontOpenCms.SEARCH_REPLACE, messages.key(Messages.GUI_BUTTON_REPLACE_0), true); context.addToolbarButton(replace); m_codeMirror.registerSearchReplace(search, replace); EditorSettings settings; try { settings = OpenCms.getWorkplaceAppManager().getAppSettings(A_CmsUI.getCmsObject(), EditorSettings.class); } catch (Exception e) { settings = new EditorSettings(); } final Button toggleHighlight = CmsToolBar.createButton(FontOpenCms.HIGHLIGHT, messages.key(Messages.GUI_BUTTON_TOGGLE_HIGHLIGHTING_0)); toggleHighlight.addClickListener(new ClickListener() { private static final long serialVersionUID = 1L; public void buttonClick(ClickEvent event) { Button b = event.getButton(); boolean pressed = b.getStyleName().contains(OpenCmsTheme.BUTTON_PRESSED); if (pressed) { b.removeStyleName(OpenCmsTheme.BUTTON_PRESSED); } else { b.addStyleName(OpenCmsTheme.BUTTON_PRESSED); } m_codeMirror.setHighlighting(!pressed); } }); if (settings.m_highlighting) { m_codeMirror.setHighlighting(true); toggleHighlight.addStyleName(OpenCmsTheme.BUTTON_PRESSED); } else { m_codeMirror.setHighlighting(false); } context.addToolbarButtonRight(toggleHighlight); final Button toggleLineWrap = CmsToolBar.createButton(FontOpenCms.WRAP_LINES, messages.key(Messages.GUI_BUTTON_TOGGLE_LINE_WRAPPING_0)); toggleLineWrap.addClickListener(new ClickListener() { private static final long serialVersionUID = 1L; public void buttonClick(ClickEvent event) { Button b = event.getButton(); boolean pressed = b.getStyleName().contains(OpenCmsTheme.BUTTON_PRESSED); if (pressed) { b.removeStyleName(OpenCmsTheme.BUTTON_PRESSED); } else { b.addStyleName(OpenCmsTheme.BUTTON_PRESSED); } m_codeMirror.setLineWrapping(!pressed); } }); if (settings.m_lineWrapping) { m_codeMirror.setLineWrapping(true); toggleLineWrap.addStyleName(OpenCmsTheme.BUTTON_PRESSED); } else { m_codeMirror.setLineWrapping(false); } context.addToolbarButtonRight(toggleLineWrap); final Button toggleBrackets = CmsToolBar.createButton(FontOpenCms.BRACKETS, messages.key(Messages.GUI_BUTTON_TOBBLE_BRACKET_AUTOCLOSE_0)); toggleBrackets.addClickListener(new ClickListener() { private static final long serialVersionUID = 1L; public void buttonClick(ClickEvent event) { Button b = event.getButton(); boolean pressed = b.getStyleName().contains(OpenCmsTheme.BUTTON_PRESSED); if (pressed) { b.removeStyleName(OpenCmsTheme.BUTTON_PRESSED); } else { b.addStyleName(OpenCmsTheme.BUTTON_PRESSED); } m_codeMirror.setCloseBrackets(!pressed); } }); if (settings.m_closeBrackets) { m_codeMirror.setCloseBrackets(true); toggleBrackets.addStyleName(OpenCmsTheme.BUTTON_PRESSED); } else { m_codeMirror.setCloseBrackets(false); } context.addToolbarButtonRight(toggleBrackets); final Button toggleTabs = CmsToolBar.createButton(FontOpenCms.INVISIBLE_CHARS, messages.key(Messages.GUI_BUTTON_TOGGLE_TAB_VISIBILITY_0)); toggleTabs.addClickListener(new ClickListener() { private static final long serialVersionUID = 1L; public void buttonClick(ClickEvent event) { Button b = event.getButton(); boolean pressed = b.getStyleName().contains(OpenCmsTheme.BUTTON_PRESSED); if (pressed) { b.removeStyleName(OpenCmsTheme.BUTTON_PRESSED); } else { b.addStyleName(OpenCmsTheme.BUTTON_PRESSED); } m_codeMirror.setTabsVisible(!pressed); } }); if (settings.m_tabsVisible) { m_codeMirror.setTabsVisible(true); toggleTabs.addStyleName(OpenCmsTheme.BUTTON_PRESSED); } else { m_codeMirror.setTabsVisible(false); } context.addToolbarButtonRight(toggleTabs); ComboBox modeSelect = new ComboBox(); modeSelect.setWidth("115px"); modeSelect.addStyleName(OpenCmsTheme.TOOLBAR_FIELD); modeSelect.addStyleName(OpenCmsTheme.REQUIRED_BUTTON); modeSelect.setNullSelectionAllowed(false); modeSelect.setImmediate(true); modeSelect.setNewItemsAllowed(false); for (CodeMirrorLanguage lang : CodeMirrorLanguage.values()) { modeSelect.addItem(lang); modeSelect.setItemCaption(lang, lang.name()); } CodeMirrorLanguage lang = getHighlightMode(resource); modeSelect.setValue(lang); m_codeMirror.setLanguage(lang); modeSelect.addValueChangeListener(new ValueChangeListener() { private static final long serialVersionUID = 1L; public void valueChange(ValueChangeEvent event) { m_codeMirror.setLanguage((CodeMirrorLanguage) event.getProperty().getValue()); } }); context.addToolbarButtonRight(modeSelect); ComboBox fontSizeSelect = new ComboBox(); fontSizeSelect.setWidth("75px"); fontSizeSelect.addStyleName(OpenCmsTheme.TOOLBAR_FIELD); fontSizeSelect.addStyleName(OpenCmsTheme.REQUIRED_BUTTON); fontSizeSelect.setNullSelectionAllowed(false); fontSizeSelect.setImmediate(true); fontSizeSelect.setNewItemsAllowed(false); for (int i = 0; i < FONT_SIZES.length; i++) { fontSizeSelect.addItem(FONT_SIZES[i]); } fontSizeSelect.setValue(settings.m_fontSize); fontSizeSelect.addValueChangeListener(new ValueChangeListener() { private static final long serialVersionUID = 1L; public void valueChange(ValueChangeEvent event) { m_codeMirror.setFontSize((String) event.getProperty().getValue()); } }); context.addToolbarButtonRight(fontSizeSelect); m_codeMirror.setFontSize(settings.m_fontSize); m_exit = CmsToolBar.createButton(FontOpenCms.EXIT, messages.key(Messages.GUI_BUTTON_CANCEL_0), true); m_exit.addClickListener(new ClickListener() { private static final long serialVersionUID = 1L; public void buttonClick(ClickEvent event) { exit(); } }); context.addToolbarButtonRight(m_exit); try { m_file = LockedFile.lockResource(A_CmsUI.getCmsObject(), resource); String content = new String(m_file.getFile().getContents(), m_file.getEncoding()); m_codeMirror.setValue(content); } catch (Exception e) { CmsErrorDialog.showErrorDialog(e); } m_codeMirror.addValueChangeListener(new ValueChangeListener() { private static final long serialVersionUID = 1L; public void valueChange(ValueChangeEvent event) { onChange((String) event.getProperty().getValue()); } }); } /** * @see org.opencms.ui.editors.I_CmsEditor#matchesResource(org.opencms.file.CmsResource, boolean) */ public boolean matchesResource(CmsResource resource, boolean plainText) { I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(resource); return !((type instanceof CmsResourceTypeBinary) || (type instanceof CmsResourceTypeImage)); } /** * @see org.opencms.ui.editors.I_CmsEditor#newInstance() */ public I_CmsEditor newInstance() { return new CmsSourceEditor(); } /** * @see org.opencms.ui.components.I_CmsWindowCloseListener#onWindowClose() */ public void onWindowClose() { clear(); } /** * Unlocks the edited file before leaving the editor.<p> */ void clear() { m_cleared = true; m_changed = false; try { m_file.unlock(); } catch (CmsException e) { // ignore } OpenCms.getWorkplaceAppManager().storeAppSettings(A_CmsUI.getCmsObject(), EditorSettings.class, getCurrentSettings()); } /** * Exits the editor without saving.<p> * Will ask to confirm exit on changed contents.<p> */ void exit() { if (m_changed) { CmsConfirmationDialog.show( CmsVaadinUtils.getMessageText(org.opencms.ui.apps.Messages.GUI_EDITOR_CLOSE_CAPTION_0), CmsVaadinUtils.getMessageText(org.opencms.ui.apps.Messages.GUI_EDITOR_CLOSE_TEXT_0), new Runnable() { public void run() { exitInternal(); } }); } else { exitInternal(); } } /** * Exits the editor without saving.<p> */ void exitInternal() { clear(); CmsEditor.openBackLink(m_backLink); } /** * Called on content change.<p> * * @param value the changed content value */ void onChange(String value) { m_changed = true; m_save.setEnabled(true); m_saveAndExit.setEnabled(true); } /** * Saves the current editor content.<p> */ void save() { try { byte[] content = m_codeMirror.getValue().getBytes(m_file.getEncoding()); m_file.getFile().setContents(content); A_CmsUI.getCmsObject().writeFile(m_file.getFile()); m_changed = false; m_save.setEnabled(false); m_saveAndExit.setEnabled(false); } catch (Exception e) { CmsErrorDialog.showErrorDialog(e); } } /** * Saves the current editor content and leaves the editor.<p> */ void saveAndExit() { save(); exit(); } /** * Returns the current editor settings.<p> * * @return the current editor settings */ private EditorSettings getCurrentSettings() { EditorSettings result = new EditorSettings(); result.m_closeBrackets = m_codeMirror.isCloseBrackets(); result.m_lineWrapping = m_codeMirror.isLineWrapping(); result.m_highlighting = m_codeMirror.isHighlighting(); result.m_tabsVisible = m_codeMirror.isTabsVisible(); result.m_fontSize = m_codeMirror.getFontSize(); return result; } }