/*****************************************************************************
* Copyright (c) 2016 Dirk Fauth.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Dirk Fauth <dirk.fauth@googlemail.com> - Initial API and implementation
* Wojtek Polcwiartek <wojciech.polcwiartek@tolina.de> - RAP implementation
*
*****************************************************************************/
package org.eclipse.nebula.widgets.richtext;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.eclipse.rap.json.JsonObject;
import org.eclipse.rap.json.JsonValue;
/**
* Configuration class that is used for general configurations of the CKEditor instance.
*
* @since 3.2
*/
public class RichTextEditorConfiguration {
/**
* Key for the default language configuration.
*/
public static final String DEFAULT_LANGUAGE = "defaultLanguage";
/**
* Key for the language configuration.
*/
public static final String LANGUAGE = "language";
/**
* Key for toolbar groups configuration.
*/
public static final String TOOLBAR_GROUPS = "toolbarGroups";
/**
* Key for toolbar buttons that should not be rendered.
*/
public static final String REMOVE_BUTTONS = "removeButtons";
/**
*
* Key to configure whether the toolbar can be collapsed by the user.
*/
public static final String TOOLBAR_CAN_COLLAPSE = "toolbarCanCollapse";
/**
* Key to configure whether the toolbar must start expanded when the editor is loaded.
*/
public static final String TOOLBAR_STARTUP_EXPANDED = "toolbarStartupExpanded";
private static final String DEFAULT_TOOLBAR_GROUPS = createDefaultToolbarGroups();
/**
* Configure whether to remove the <i>paste text</i> button from the toolbar. Default is
* <code>true</code>.
*/
private boolean removePasteText = true;
/**
* Configure whether to remove the <i>paste from word</i> button from the toolbar. Default is
* <code>true</code>.
*/
private boolean removePasteFromWord = true;
/**
* Configure whether to remove the <i>styles</i> combo box from the toolbar. Default is
* <code>true</code>.
*/
private boolean removeStyles = true;
/**
* Configure whether to remove <i>format</i> combo box from the toolbar. Default is
* <code>true</code>.
*/
private boolean removeFormat = true;
private final Map<String, Object> options = new HashMap<>();
private final Set<String> removedButtons = new HashSet<>();
/**
* Creates a new instance for general configurations that are added to the created CKEditor
* instance at initialization.
*/
public RichTextEditorConfiguration() {
options.put( DEFAULT_LANGUAGE, Locale.ENGLISH.getLanguage() );
options.put( LANGUAGE, Locale.getDefault().getLanguage() );
setToolbarCollapsible( false );
setToolbarInitialExpanded( true );
options.put( TOOLBAR_GROUPS, DEFAULT_TOOLBAR_GROUPS );
options.put( REMOVE_BUTTONS, getRemoveButtonConfiguration() );
}
@SuppressWarnings( "deprecation" )
RichTextEditorConfiguration( org.eclipse.nebula.widgets.richtext.toolbar.ToolbarConfiguration config ) {
this();
removePasteText = config.removePasteText;
removePasteFromWord = config.removePasteFromWord;
removeStyles = config.removeStyles;
removeFormat = config.removeFormat;
removedButtons.addAll( config.getRemovedButtons() );
setToolbarCollapsible( config.toolbarCollapsible );
setToolbarInitialExpanded( config.toolbarInitialExpanded );
JsonObject jsonConfig = JsonObject.readFrom( config.toString() );
// set the option like this in case the method itself was overridden by subclassing
options.put( TOOLBAR_GROUPS, jsonConfig.get( TOOLBAR_GROUPS ).toString() );
// set the option like this in case the method itself was overridden by subclassing
options.put( REMOVE_BUTTONS, jsonConfig.get( REMOVE_BUTTONS ).asString() );
}
private static String createDefaultToolbarGroups() {
StringBuilder builder = new StringBuilder();
builder.append( "[" );
builder.append( "{\"name\":\"basicstyles\",\"groups\":[\"basicstyles\",\"cleanup\"]}," );
builder.append( "{\"name\":\"paragraph\",\"groups\":[\"list\",\"indent\",\"align\"]}," );
builder.append( "\"/\"," );
builder.append( "{\"name\":\"styles\"}," );
builder.append( "{\"name\":\"colors\" }" );
builder.append( "]" );
return builder.toString();
}
/**
* Adds a new option to the configuration.
*
* @param key The configuration option key.
* @param value The configuration option value.
* @see <a href="http://docs.ckeditor.com/#!/api/CKEDITOR.config">CKEDITOR.config</a>
*/
public void setOption( String key, Object value ) {
options.put( key, value );
}
/**
* Returns a configuration option set in this {@link RichTextEditorConfiguration}.
*
* @param key The configuration option key for which the value is requested.
* @return The configuration option value for the given key or <code>null</code> in case there is
* nothing configured for that key.
*/
public Object getOption( String key ) {
return options.get( key );
}
/**
* @return An unmodifiable map that contains all configuration option values.
*/
public Map<String, Object> getAllOptions() {
return Collections.unmodifiableMap( options );
}
// convenience methods
/**
* @param lang The user interface language localization to use. If left empty, the editor will
* automatically be localized to the user language. If the user language is not
* supported, the language specified in the <i>defaultLanguage</i> configuration setting
* is used.
*/
public void setLanguage( String lang ) {
options.put( LANGUAGE, lang );
}
/**
* @param locale The user interface language localization to use. If left empty, the editor will
* automatically be localized to the user language. If the user language is not
* supported, the language specified in the <i>defaultLanguage</i> configuration setting
* is used.
*/
public void setLanguage( Locale locale ) {
setLanguage( locale.getLanguage() );
}
/**
* @param lang The language to be used if the language setting is left empty and it is not
* possible to localize the editor to the user language.
*/
public void setDefaultLanguage( String lang ) {
options.put( DEFAULT_LANGUAGE, lang );
}
/**
* @param locale The language to be used if the language setting is left empty and it is not
* possible to localize the editor to the user language.
*/
public void setDefaultLanguage( Locale locale ) {
setDefaultLanguage( locale.getLanguage() );
}
/**
* @param removePasteText <code>true</code> to remove the <i>paste text</i> button from the
* toolbar.
*/
public void setRemovePasteText( boolean removePasteText ) {
this.removePasteText = removePasteText;
options.put( REMOVE_BUTTONS, getRemoveButtonConfiguration() );
}
/**
* @param removePasteFromWord <code>true</code> to remove the <i>paste from word</i> button from
* the toolbar.
*/
public void setRemovePasteFromWord( boolean removePasteFromWord ) {
this.removePasteFromWord = removePasteFromWord;
options.put( REMOVE_BUTTONS, getRemoveButtonConfiguration() );
}
/**
* @param removeStyles <code>true</code> to remove the <i>styles</i> combo box from the toolbar.
*/
public void setRemoveStyles( boolean removeStyles ) {
this.removeStyles = removeStyles;
options.put( REMOVE_BUTTONS, getRemoveButtonConfiguration() );
}
/**
* @param removeFormat <code>true</code> to remove <i>format</i> combo box from the toolbar.
*/
public void setRemoveFormat( boolean removeFormat ) {
this.removeFormat = removeFormat;
options.put( REMOVE_BUTTONS, getRemoveButtonConfiguration() );
}
/**
* Adds the CKEditor default button for the given name to the toolbar.
* <p>
* <i>Note: This works only for buttons that have been removed using
* {@link #removeDefaultToolbarButton(String[])}</i>
* </p>
*
* @param buttonNames The names of the CKEditor default button to add.
*/
public void addDefaultToolbarButton( String... buttonNames ) {
for( String buttonName : buttonNames ) {
removedButtons.remove( buttonName );
}
options.put( REMOVE_BUTTONS, getRemoveButtonConfiguration() );
}
/**
* Removes the CKEditor default button for the given name from the toolbar.
*
* @param buttonNames The names of the CKEditor default button to remove.
*/
public void removeDefaultToolbarButton( String... buttonNames ) {
// remember the button that should be removed
for( String buttonName : buttonNames ) {
removedButtons.add( buttonName );
}
options.put( REMOVE_BUTTONS, getRemoveButtonConfiguration() );
}
/**
* @return The configuration which default buttons should be removed from the toolbar.
*/
private String getRemoveButtonConfiguration() {
// Subscript and Superscript are not supported styling options for the
// Rich Text Viewer
StringBuilder builder = new StringBuilder();
if( removePasteText ) {
builder.append( ",PasteText" );
}
if( removePasteFromWord ) {
builder.append( ",PasteFromWord" );
}
if( removeStyles ) {
builder.append( ",Styles" );
}
if( removeFormat ) {
builder.append( ",Format" );
}
for( String removed : this.removedButtons ) {
builder.append( "," ).append( removed );
}
String removeButtons = builder.toString();
if( removeButtons.startsWith( "," ) ) {
return removeButtons.substring( 1 );
}
return removeButtons;
}
/**
* Configure if the toolbar should be collapsible. Default is <code>false</code>.
*
* @param toolbarCollapsible <code>true</code> if the toolbar should be collapsible,
* <code>false</code> if not.
*/
public void setToolbarCollapsible( boolean toolbarCollapsible ) {
this.options.put( TOOLBAR_CAN_COLLAPSE, Boolean.valueOf( toolbarCollapsible ) );
}
/**
* Configure if the toolbar should be initially expanded. Default is <code>true</code>.
*
* @param toolbarInitialExpanded <code>true</code> if the toolbar should be initially expanded,
* <code>false</code> if not.
*/
public void setToolbarInitialExpanded( boolean toolbarInitialExpanded ) {
this.options.put( TOOLBAR_STARTUP_EXPANDED, Boolean.valueOf( toolbarInitialExpanded ) );
}
JsonObject toJson() {
JsonObject jsonObject = new JsonObject();
Map<String, Object> allOptions = getAllOptions();
for( Entry<String, Object> entry : allOptions.entrySet() ) {
String optionName = entry.getKey();
Object optionValue = entry.getValue();
JsonValue jsonValue = createJsonValue( optionValue );
jsonObject.add( optionName, jsonValue );
}
return jsonObject;
}
private static JsonValue createJsonValue( Object value ) {
if( value instanceof Boolean ) {
Boolean bool = ( Boolean )value;
return JsonValue.valueOf( bool.booleanValue() );
}
if( value instanceof String ) {
String str = ( String )value;
return processString( str );
}
if( value instanceof Integer ) {
Integer num = ( Integer )value;
return JsonValue.valueOf( num.intValue() );
}
if( value instanceof Long ) {
Long num = ( Long )value;
return JsonValue.valueOf( num.longValue() );
}
if( value instanceof Float ) {
Float num = ( Float )value;
return JsonValue.valueOf( num.floatValue() );
}
if( value instanceof Double ) {
Double num = ( Double )value;
return JsonValue.valueOf( num.doubleValue() );
}
System.out.println( value );
String message = "Only a RichTextEditorConfiguration with Boolean, String, Integer, Long, "
+ "Float and Double values is currently supported";
throw new IllegalArgumentException( message );
}
private static JsonValue processString( String str ) {
if( str == null || str.length() < 1 ) {
return JsonValue.valueOf( "" );
}
if( str.charAt( 0 ) == '[' || str.charAt( 0 ) == '{' ) {
return JsonValue.readFrom( str );
}
return JsonValue.valueOf( str );
}
}