Index: /CKEditor/trunk/_source/core/config.js
===================================================================
--- /CKEditor/trunk/_source/core/config.js	(revision 3119)
+++ /CKEditor/trunk/_source/core/config.js	(revision 3120)
@@ -148,5 +148,5 @@
 	 */
 
-	plugins : 'basicstyles,blockquote,button,clipboard,elementspath,find,flash,font,format,forms,horizontalrule,htmldataprocessor,image,indent,justify,keystrokes,link,list,newpage,pagebreak,pastefromword,pastetext,preview,print,removeformat,smiley,showblocks,sourcearea,table,specialchar,tab,templates,toolbar,undo,wysiwygarea',
+	plugins : 'basicstyles,blockquote,button,clipboard,elementspath,find,flash,font,format,forms,horizontalrule,htmldataprocessor,image,indent,justify,keystrokes,link,list,newpage,pagebreak,pastefromword,pastetext,preview,print,removeformat,smiley,showblocks,sourcearea,stylescombo,table,specialchar,tab,templates,toolbar,undo,wysiwygarea',
 
 	/**
Index: /CKEditor/trunk/_source/lang/en.js
===================================================================
--- /CKEditor/trunk/_source/lang/en.js	(revision 3119)
+++ /CKEditor/trunk/_source/lang/en.js	(revision 3120)
@@ -439,4 +439,12 @@
 	showBlocks : 'Show Blocks',
 
+	stylesCombo :
+	{
+		label : 'Styles',
+		panelTitle1 : 'Block Styles',
+		panelTitle2 : 'Inline Styles',
+		panelTitle3 : 'Object Styles'
+	},
+
 	format :
 	{
Index: /CKEditor/trunk/_source/plugins/listblock/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/listblock/plugin.js	(revision 3119)
+++ /CKEditor/trunk/_source/plugins/listblock/plugin.js	(revision 3120)
@@ -7,5 +7,5 @@
 {
 	requires : [ 'panel' ],
-	
+
 	onLoad : function()
 	{
@@ -29,5 +29,6 @@
 					{
 						pendingHtml : [],
-						items : {}
+						items : {},
+						groups : {}
 					};
 				},
@@ -87,5 +88,10 @@
 					{
 						this._.close();
-						this._.pendingHtml.push( '<h1 class=cke_panel_grouptitle>', title, '</h1>' );
+
+						var id = CKEDITOR.tools.getNextNumber();
+
+						this._.groups[ title ] = id;
+
+						this._.pendingHtml.push( '<h1 id=cke_', id, ' class=cke_panel_grouptitle>', title, '</h1>' );
 					},
 
@@ -106,4 +112,46 @@
 
 						return !isMarked;
+					},
+
+					hideGroup : function( groupTitle )
+					{
+						var group = this.element.getDocument().getById( 'cke_' + this._.groups[ groupTitle ] ),
+							list = group && group.getNext();
+
+						if ( group )
+						{
+							group.setStyle( 'display', 'none' );
+
+							if ( list && list.getName() == 'ul' )
+								list.setStyle( 'display', 'none' );
+						}
+					},
+
+					hideItem : function( value )
+					{
+						this.element.getDocument().getById( 'cke_' + this._.items[ value ] ).setStyle( 'display', 'none' );
+					},
+
+					showAll : function()
+					{
+						var items = this._.items,
+							groups = this._.groups,
+							doc = this.element.getDocument();
+
+						for ( var value in items )
+						{
+							doc.getById( 'cke_' + items[ value ] ).setStyle( 'display', '' );
+						}
+
+						for ( title in groups )
+						{
+							var group = doc.getById( 'cke_' + groups[ title ] ),
+								list = group.getNext();
+
+							group.setStyle( 'display', '' );
+
+							if ( list && list.getName() == 'ul' )
+								list.setStyle( 'display', '' );
+						}
 					},
 
Index: /CKEditor/trunk/_source/plugins/richcombo/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/richcombo/plugin.js	(revision 3119)
+++ /CKEditor/trunk/_source/plugins/richcombo/plugin.js	(revision 3120)
@@ -234,4 +234,29 @@
 			return this._.value || '';
 		},
+		
+		unmarkAll : function()
+		{
+			this._.list.unmarkAll();
+		},
+
+		mark : function( value )
+		{
+			this._.list.mark( value );
+		},
+		
+		hideItem : function( value )
+		{
+			this._.list.hideItem( value );
+		},
+		
+		hideGroup : function( groupTitle )
+		{
+			this._.list.hideGroup( groupTitle );
+		},
+		
+		showAll : function()
+		{
+			this._.list.showAll();
+		},
 
 		add : function( value, html, text )
@@ -244,4 +269,9 @@
 		{
 			this._.list.startGroup( title );
+		},
+		
+		commit : function()
+		{
+			this._.list.commit();
 		}
 	}
Index: /CKEditor/trunk/_source/plugins/styles/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/styles/plugin.js	(revision 3119)
+++ /CKEditor/trunk/_source/plugins/styles/plugin.js	(revision 3120)
@@ -81,4 +81,6 @@
 	var objectElements	= { a:1,embed:1,hr:1,img:1,li:1,object:1,ol:1,table:1,td:1,tr:1,ul:1 };
 
+	var semicolonFixRegex = /\s*(?:;\s*|$)/;
+
 	CKEDITOR.style = function( styleDefinition, variablesValues )
 	{
@@ -136,4 +138,9 @@
 						: null ).call( this, range );
 		},
+		
+		applyToObject : function( element )
+		{
+			setupElement( element, this );
+		},
 
 		/**
@@ -201,4 +208,38 @@
 			return true;
 		}
+	};
+
+	// Build the cssText based on the styles definition.
+	CKEDITOR.style.getStyleText = function( styleDefinition )
+	{
+		// If we have already computed it, just return it.
+		var stylesDef = styleDefinition._ST;
+		if ( stylesDef )
+			return stylesDef;
+
+		stylesDef = styleDefinition.styles;
+
+		// Builds the StyleText.
+
+		var stylesText = ( styleDefinition.attributes && styleDefinition.attributes[ 'style' ] ) || '';
+
+		if ( stylesText.length )
+			stylesText = stylesText.replace( semicolonFixRegex, ';' );
+
+		for ( var style in stylesDef )
+			stylesText += style + ':' + stylesDef[ style ] + ';';
+
+		// Browsers make some changes to the style when applying them. So, here
+		// we normalize it to the browser format.
+		if ( stylesText.length )
+		{
+			stylesText = normalizeCssText( stylesText );
+
+			if ( stylesText.length )
+				stylesText = stylesText.replace( semicolonFixRegex, ';' );
+		}
+
+		// Return it, saving it to the next request.
+		return ( styleDefinition._ST = stylesText );
 	};
 
@@ -669,6 +710,4 @@
 
 		var elementName = style.element;
-		var attributes = def.attributes;
-		var styles = getStyleText( def );
 
 		// The "*" element name will always be a span for this function.
@@ -678,4 +717,13 @@
 		// Create the element.
 		el = new CKEDITOR.dom.element( elementName, targetDocument );
+		
+		return setupElement( el, style );
+	}
+	
+	function setupElement( el, style )
+	{
+		var def = style._.definition;
+		var attributes = def.attributes;
+		var styles = CKEDITOR.style.getStyleText( def );
 
 		// Assign all defined attributes.
@@ -735,5 +783,5 @@
 
 		// Includes the style definitions.
-		var styleText = getStyleText( styleDefinition );
+		var styleText = CKEDITOR.style.getStyleText( styleDefinition );
 		if ( styleText.length > 0 )
 		{
@@ -749,40 +797,4 @@
 		// Return it, saving it to the next request.
 		return ( styleDefinition._AC = attribs );
-	}
-
-	var semicolonFixRegex = /\s*(?:;\s*|$)/;
-
-	// Build the cssText based on the styles definition.
-	function getStyleText( styleDefinition )
-	{
-		// If we have already computed it, just return it.
-		var stylesDef = styleDefinition._ST;
-		if ( stylesDef )
-			return stylesDef;
-
-		stylesDef = styleDefinition.styles;
-
-		// Builds the StyleText.
-
-		var stylesText = ( styleDefinition.attributes && styleDefinition.attributes[ 'style' ] ) || '';
-
-		if ( stylesText.length )
-			stylesText = stylesText.replace( semicolonFixRegex, ';' );
-
-		for ( var style in stylesDef )
-			stylesText += style + ':' + stylesDef[ style ] + ';';
-
-		// Browsers make some changes to the style when applying them. So, here
-		// we normalize it to the browser format.
-		if ( stylesText.length )
-		{
-			stylesText = normalizeCssText( stylesText );
-
-			if ( stylesText.length )
-				stylesText = stylesText.replace( semicolonFixRegex, ';' );
-		}
-
-		// Return it, saving it to the next request.
-		return ( styleDefinition._ST = stylesText );
 	}
 
Index: /CKEditor/trunk/_source/plugins/stylescombo/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/stylescombo/plugin.js	(revision 3120)
+++ /CKEditor/trunk/_source/plugins/stylescombo/plugin.js	(revision 3120)
@@ -0,0 +1,289 @@
+/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+(function()
+{
+	CKEDITOR.plugins.add( 'stylescombo',
+	{
+		requires : [ 'richcombo', 'styles' ],
+
+		init : function( editor )
+		{
+			var config = editor.config,
+				lang = editor.lang.stylesCombo,
+				pluginPath = this.path,
+				styles,
+				saveRanges;
+
+			editor.ui.addRichCombo( 'Styles',
+				{
+					label : lang.label,
+					title : lang.panelTitle,
+					className : 'cke_styles',
+					multiSelect : true,
+
+					panel :
+					{
+						css : [ config.contentsCss, editor.skinPath + 'editor.css' ],
+						className : 'cke_skin_default'
+					},
+
+					init : function()
+					{
+						var combo = this,
+							stylesSet = config.stylesCombo_stylesSet.split( ':', 1 ),
+							stylesSetPath = stylesSet[ 1 ] || CKEDITOR.getUrl( pluginPath + 'styles/' + stylesSet[ 0 ] + '.js' ) ;
+
+						stylesSet = stylesSet[ 0 ];
+
+						CKEDITOR.loadStylesSet( stylesSet, stylesSetPath, function( stylesDefinitions )
+							{
+								var style,
+									styleName,
+									stylesList = [];
+
+								styles = {};
+
+								// Put all styles into an Array.
+								for ( var i = 0 ; i < stylesDefinitions.length ; i++ )
+								{
+									var styleDefinition = stylesDefinitions[ i ];
+
+									styleName = styleDefinition.name;
+
+									style = styles[ styleName ] = new CKEDITOR.style( styleDefinition );
+									style._name = styleName;
+
+									stylesList.push( style );
+								}
+
+								// Sorts the Array, so the styles get grouped
+								// by type.
+								stylesList.sort( sortStyles );
+
+								// Loop over the Array, adding all items to the
+								// combo.
+								var lastType;
+								for ( var i = 0 ; i < stylesList.length ; i++ )
+								{
+									style = stylesList[ i ];
+									styleName = style._name;
+
+									var type = style.type;
+
+									if ( type != lastType )
+									{
+										combo.startGroup( lang[ 'panelTitle' + String( type ) ] );
+										lastType = type;
+									}
+
+									combo.add(
+										styleName,
+										style.type == CKEDITOR.STYLE_OBJECT ? styleName : buildPreview( style._.definition ),
+										styleName );
+								}
+
+								combo.commit();
+
+								combo.onOpen();
+							});
+					},
+
+					onClick : function( value )
+					{
+						editor.focus();
+
+						var style = styles[ value ],
+							selection = editor.getSelection();
+						
+						if ( saveRanges )
+						{
+							selection.selectRanges( saveRanges );
+							saveRanges = false;
+						}
+
+						if ( style.type == CKEDITOR.STYLE_OBJECT )
+						{
+							var element = selection.getSelectedElement();
+							if ( element )
+								style.applyToObject( element );
+							
+							return;
+						}
+						
+						var elementPath = new CKEDITOR.dom.elementPath( selection.getStartElement() );
+
+						if ( style.type == CKEDITOR.STYLE_INLINE && style.checkActive( elementPath ) )
+							style.remove( editor.document );
+						else
+							style.apply( editor.document );
+					},
+
+					onRender : function()
+					{
+						editor.on( 'selectionChange', function( ev )
+							{
+								var currentTag = this.getValue();
+
+								var elementPath = ev.data.path;
+
+								for ( var tag in styles )
+								{
+									if ( styles[ tag ].checkActive( elementPath ) )
+									{
+										if ( tag != currentTag )
+											this.setValue( tag );
+										return;
+									}
+								}
+
+								// If no styles match, just empty it.
+								this.setValue( '' );
+							},
+							this);
+					},
+
+					onOpen : function()
+					{
+						var selection = editor.getSelection();
+
+						if ( CKEDITOR.env.ie )
+						{
+							editor.focus();
+							saveRanges = selection.getRanges();
+						}
+
+						var elementPath,
+							element = selection.getSelectedElement(),
+							elementName = element && element.getName(),
+							isInline = elementName &&
+								!CKEDITOR.dtd.$block[ elementName ] &&
+								!CKEDITOR.dtd.$listItem[ elementName ] &&
+								!CKEDITOR.dtd.$tableContent[ elementName ];
+
+						var counter = [ 0, 0, 0, 0 ];
+
+						if ( !element || isInline )
+							elementPath = new CKEDITOR.dom.elementPath( selection.getStartElement() );
+
+						this.showAll();
+						this.unmarkAll();
+
+						for ( var name in styles )
+						{
+							var style = styles[ name ]
+								type = style.type;
+
+							if ( type == CKEDITOR.STYLE_OBJECT )
+							{
+								if ( element && style.element == elementName )
+								{
+									if ( style.checkElementRemovable( element, true ) )
+										this.mark( name );
+
+									counter[ type ]++;
+								}
+								else
+									this.hideItem( name );
+							}
+							else
+							{
+								if ( elementPath )
+								{
+									if ( style.checkActive( elementPath ) )
+										this.mark( name );
+
+									counter[ type ]++;
+
+								}
+								else
+									this.hideItem( name );
+							}
+						}
+
+						if ( !counter[ CKEDITOR.STYLE_BLOCK ] )
+							this.hideGroup( lang[ 'panelTitle' + String( CKEDITOR.STYLE_BLOCK ) ] );
+
+						if ( !counter[ CKEDITOR.STYLE_INLINE ] )
+							this.hideGroup( lang[ 'panelTitle' + String( CKEDITOR.STYLE_INLINE ) ] );
+
+						if ( !counter[ CKEDITOR.STYLE_OBJECT ] )
+							this.hideGroup( lang[ 'panelTitle' + String( CKEDITOR.STYLE_OBJECT ) ] );
+					},
+
+					onClose : function()
+					{
+						saveRanges = null;
+					}
+				});
+		}
+	});
+
+	var stylesSets = {};
+
+	CKEDITOR.addStylesSet = function( name, styles )
+	{
+		stylesSets[ name ] = styles;
+	};
+
+	CKEDITOR.loadStylesSet = function( name, url, callback )
+	{
+		var stylesSet = stylesSets[ name ];
+
+		if ( stylesSet )
+			return callback( stylesSets );
+
+		CKEDITOR.scriptLoader.load( url, function()
+			{
+				callback( stylesSets[ name ] );
+			});
+	};
+
+	function buildPreview( styleDefinition )
+	{
+		var html = [];
+
+		var elementName = styleDefinition.element;
+
+		// Avoid <bdo> in the preview.
+		if ( elementName == 'bdo' )
+			elementName = 'span';
+
+		html = [ '<', elementName ];
+
+		// Assign all defined attributes.
+		var attribs	= styleDefinition.attributes;
+		if ( attribs )
+		{
+			for ( var att in attribs )
+			{
+				html.push( ' ', att, '="', attribs[ att ], '"' );
+			}
+		}
+
+		// Assign the style attribute.
+		var cssStyle = CKEDITOR.style.getStyleText( styleDefinition );
+		if ( cssStyle )
+			html.push( ' style="', cssStyle, '"' );
+
+		html.push( '>', styleDefinition.name, '</', elementName, '>' );
+
+		return html.join( '' );
+	}
+
+	function sortStyles( styleA, styleB )
+	{
+		var typeA = styleA.type,
+			typeB = styleB.type;
+
+		return typeA == typeB ? 0 :
+			typeA == CKEDITOR.STYLE_OBJECT ? -1 :
+			typeB == CKEDITOR.STYLE_OBJECT ? 1 :
+			typeB == CKEDITOR.STYLE_BLOCK ? 1 :
+			-1;
+	}
+})();
+
+CKEDITOR.config.stylesCombo_stylesSet = 'default';
Index: /CKEditor/trunk/_source/plugins/stylescombo/styles/default.js
===================================================================
--- /CKEditor/trunk/_source/plugins/stylescombo/styles/default.js	(revision 3120)
+++ /CKEditor/trunk/_source/plugins/stylescombo/styles/default.js	(revision 3120)
@@ -0,0 +1,85 @@
+﻿/*
+Copyright (c) 2003-2009, CKSource - Frederico Knabben. All rights reserved.
+For licensing, see LICENSE.html or http://ckeditor.com/license
+*/
+
+CKEDITOR.addStylesSet( 'default',
+[
+	/* Block Styles */
+
+	// These styles are already available in the "Format" combo, so they are
+	// not needed here by default. You may enable them to avoid placing the
+	// "Format" combo in the toolbar, maintaining the same features.
+	/*
+	{ name : 'Paragraph'		, element : 'p' },
+	{ name : 'Heading 1'		, element : 'h1' },
+	{ name : 'Heading 2'		, element : 'h2' },
+	{ name : 'Heading 3'		, element : 'h3' },
+	{ name : 'Heading 4'		, element : 'h4' },
+	{ name : 'Heading 5'		, element : 'h5' },
+	{ name : 'Heading 6'		, element : 'h6' },
+	{ name : 'Preformatted Text', element : 'pre' },
+	{ name : 'Address'			, element : 'address' },
+	*/
+
+	{ name : 'Blue Title'		, element : 'h3', styles : { 'color' : 'Blue' } },
+	{ name : 'Red Title'		, element : 'h3', styles : { 'color' : 'Red' } },
+
+	/* Inline Styles */
+
+	// These are core styles available as toolbar buttons. You may opt enabling
+	// some of them in the Styles combo, removing them from the toolbar.
+	/*
+	{ name : 'Strong'			, element : 'strong', overrides : 'b' },
+	{ name : 'Emphasis'			, element : 'em'	, overrides : 'i' },
+	{ name : 'Underline'		, element : 'u' },
+	{ name : 'Strikethrough'	, element : 'strike' },
+	{ name : 'Subscript'		, element : 'sub' },
+	{ name : 'Superscript'		, element : 'sup' },
+	*/
+
+	{ name : 'Marker: Yellow'	, element : 'span', styles : { 'background-color' : 'Yellow' } },
+	{ name : 'Marker: Green'	, element : 'span', styles : { 'background-color' : 'Lime' } },
+
+	{ name : 'Big'				, element : 'big' },
+	{ name : 'Small'			, element : 'small' },
+	{ name : 'Typewriter'		, element : 'tt' },
+
+	{ name : 'Computer Code'	, element : 'code' },
+	{ name : 'Keyboard Phrase'	, element : 'kbd' },
+	{ name : 'Sample Text'		, element : 'samp' },
+	{ name : 'Variable'			, element : 'var' },
+
+	{ name : 'Deleted Text'		, element : 'del' },
+	{ name : 'Inserted Text'	, element : 'ins' },
+
+	{ name : 'Cited Work'		, element : 'cite' },
+	{ name : 'Inline Quotation'	, element : 'q' },
+
+	{ name : 'Language: RTL'	, element : 'span', attributes : { 'dir' : 'rtl' } },
+	{ name : 'Language: LTR'	, element : 'span', attributes : { 'dir' : 'ltr' } },
+
+	/* Object Styles */
+
+	{
+		name : 'Image on Left',
+		element : 'img',
+		attributes :
+		{
+			'style' : 'padding: 5px; margin-right: 5px',
+			'border' : '2',
+			'align' : 'left'
+		}
+	},
+
+	{
+		name : 'Image on Right',
+		element : 'img',
+		attributes :
+		{
+			'style' : 'padding: 5px; margin-left: 5px',
+			'border' : '2',
+			'align' : 'right'
+		}
+	}
+]);
Index: /CKEditor/trunk/_source/plugins/toolbar/plugin.js
===================================================================
--- /CKEditor/trunk/_source/plugins/toolbar/plugin.js	(revision 3119)
+++ /CKEditor/trunk/_source/plugins/toolbar/plugin.js	(revision 3120)
@@ -222,5 +222,5 @@
 	['Link','Unlink','Anchor'],	['Image','Flash','Table','HorizontalRule','Smiley','SpecialChar','PageBreak'],
 	'/',
-	['Format','Font','FontSize'],
+	['Styles','Format','Font','FontSize'],
 	['ShowBlocks']
 ];
Index: /CKEditor/trunk/_source/skins/default/presets.css
===================================================================
--- /CKEditor/trunk/_source/skins/default/presets.css	(revision 3119)
+++ /CKEditor/trunk/_source/skins/default/presets.css	(revision 3120)
@@ -3,4 +3,11 @@
 For licensing, see LICENSE.html or http://ckeditor.com/license
 */
+
+/* "Styles" panel size */
+.cke_skin_default.cke_panel.cke_styles
+{
+	width: 150px;
+	height: 170px;
+}
 
 /* "Format" panel size */
