Index: editor/_source/classes/fckdomrange_gecko.js
===================================================================
--- editor/_source/classes/fckdomrange_gecko.js	(revision 1504)
+++ editor/_source/classes/fckdomrange_gecko.js	(working copy)
@@ -101,4 +101,4 @@
 	var selection = this.Window.getSelection() ;
 	selection.removeAllRanges() ;
 	selection.addRange( domRange ) ;
-}
\ No newline at end of file
+}
Index: editor/_source/classes/fckhtmliterator.js
===================================================================
--- editor/_source/classes/fckhtmliterator.js	(revision 0)
+++ editor/_source/classes/fckhtmliterator.js	(revision 0)
@@ -0,0 +1,71 @@
+/*
+ * FCKeditor - The text editor for Internet - http://www.fckeditor.net
+ * Copyright (C) 2003-2007 Frederico Caldeira Knabben
+ *
+ * == BEGIN LICENSE ==
+ *
+ * Licensed under the terms of any of the following licenses at your
+ * choice:
+ *
+ *  - GNU General Public License Version 2 or later (the "GPL")
+ *    http://www.gnu.org/licenses/gpl.html
+ *
+ *  - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
+ *    http://www.gnu.org/licenses/lgpl.html
+ *
+ *  - Mozilla Public License Version 1.1 or later (the "MPL")
+ *    http://www.mozilla.org/MPL/MPL-1.1.html
+ *
+ * == END LICENSE ==
+ *
+ * This class can be used to interate through nodes inside a range.
+ *
+ * During interation, the provided range can become invalid, due to document
+ * mutations, so CreateBookmark() used to restore it after processing, if
+ * needed.
+ */
+
+var FCKHtmlIterator = function( source )
+{
+	this._sourceHtml = source ;
+}
+FCKHtmlIterator.prototype = 
+{
+	Next : function()
+	{
+		var sourceHtml = this._sourceHtml ;
+		if ( sourceHtml == null )
+			return null ;
+
+		var match = FCKRegexLib.HtmlTag.exec( sourceHtml ) ;
+		var isTag = false ;
+		var value = "" ;
+		if ( match )
+		{
+			if ( match.index > 0 )
+			{
+				value = sourceHtml.substr( 0, match.index ) ;
+				this._sourceHtml = sourceHtml.substr( match.index ) ;
+			}
+			else
+			{
+				isTag = true ;
+				value = match[0] ;
+				this._sourceHtml = sourceHtml.substr( match[0].length ) ;
+			}
+		}
+		else
+		{
+			value = sourceHtml ;
+			this._sourceHtml = null ;
+		}
+		return { 'isTag' : isTag, 'value' : value } ;
+	},
+
+	Each : function( func )
+	{
+		var chunk ;
+		while ( ( chunk = this.Next() ) )
+			func( chunk.isTag, chunk.value ) ;
+	}
+} ;
Index: editor/_source/classes/fckstyle.js
===================================================================
--- editor/_source/classes/fckstyle.js	(revision 1504)
+++ editor/_source/classes/fckstyle.js	(working copy)
@@ -747,6 +747,101 @@
 	},
 
 	/**
+	 * Converting from a PRE block to a non-PRE block in formatting operations.
+	 */
+	_FromPre : function( doc, block, newBlock )
+	{
+		var innerHTML = block.innerHTML ;
+
+		// Trim the first and last linebreaks immediately after and before <pre>, </pre>,
+		// if they exist.
+		// This is done because the linebreaks are not rendered.
+		innerHTML = innerHTML.replace( /(\r\n|\r)/g, '\n' ) ;
+		innerHTML = innerHTML.match( /^(?:[ \t]*\n)?((?:[a]|[^a])*)$/ )[1] ;
+		var lastWhiteSpaceMatch = /\n$/.exec( innerHTML ) ;
+		if ( lastWhiteSpaceMatch )
+			innerHTML = innerHTML.substr( 0, lastWhiteSpaceMatch.index ) ;
+
+		// 1. Convert spaces or tabs at the beginning or at the end to &nbsp;
+		var beginSpaces = /^[ \t]+/.exec( innerHTML ) ;
+		var endSpaces = /[ \t]+$/.exec( innerHTML ) ;
+		if ( endSpaces )
+			innerHTML = innerHTML.substr( 0, endSpaces.index ) + endSpaces[0].replace( /[ \t]/g, '&nbsp;' ) ;
+		if ( beginSpaces )
+			innerHTML = beginSpaces[0].replace( /[ \t]/g, '&nbsp;' ) + innerHTML.substr( beginSpaces[0].length ) ;
+
+		// 2. Convert \n to <BR>.
+		// 3. Convert contiguous (i.e. non-singular) spaces or tabs to &nbsp;
+		var htmlIterator = new FCKHtmlIterator( innerHTML ) ;
+		var results = [] ;
+		var processor = function( isTag, value )
+		{
+			if ( !isTag )
+			{
+				value = value.replace( /\n/g, '<BR>' ) ;
+				value = value.replace( /[ \t]{2}/g, '&nbsp;&nbsp;' ) ;
+			}
+			results.push( value ) ;
+		}
+		htmlIterator.Each( processor ) ;
+		newBlock.innerHTML = results.join( '' ) ;
+	},
+
+	/**
+	 * Converting from a non-PRE block to a PRE block in formatting operations.
+	 */
+	_ToPre : function( doc, block, newBlock )
+	{
+		// Handle converting from a regular block to a <pre> block.
+		var innerHTML = block.innerHTML.Trim() ;
+		var htmlIterator = new FCKHtmlIterator( innerHTML ) ;
+		var results = [] ;
+		var lastNodeWasBr = false ;
+
+		// 1. Delete ANSI whitespaces immediately before and after <BR> because they are not visible.
+		// 2. Compress other ANSI whitespaces since they're only visible as one single space previously.
+		// 3. Convert &nbsp; to spaces since &nbsp; is no longer needed in <PRE>.
+		var processor = function( isTag, value )
+		{
+			if ( isTag )
+			{
+				if ( /^<BR/i.test( value ) )
+				{
+					value = '\n' ;
+					if ( results.length > 0 )
+						results[results.length - 1] = results[results.length - 1].RTrim() ;
+					lastNodeWasBr = true ;
+				}
+				else
+					lastNodeWasBr = false ;
+			}
+			else
+			{
+				if ( lastNodeWasBr )
+					value = value.LTrim() ;
+				value = value.replace( /([ \t\n\r]+|&nbsp;)/g, ' ' ) ;
+				lastNodeWasBr = false ;
+			}
+			results.push( value ) ;
+		}
+		htmlIterator.Each( processor ) ;
+
+		// Assigning innerHTML to <PRE> in IE causes all linebreaks to be reduced to spaces.
+		// Assigning outerHTML to <PRE> in IE doesn't work if the <PRE> isn't contained in another node
+		// since the node reference is changed after outerHTML assignment.
+		// So, we need some hacks to workaround IE bugs here.
+		if ( FCKBrowserInfo.IsIE )
+		{
+			var temp = doc.createElement( 'div' ) ;
+			temp.appendChild( newBlock ) ;
+			newBlock.outerHTML = '<PRE>\n' + results.join( '' ) + '</PRE>' ;
+			newBlock = temp.removeChild( temp.firstChild ) ;
+		}
+		else
+			newBlock.innerHTML = results.join( '' ) ;
+	},
+
+	/**
 	 * Apply an inline style to a FCKDomRange.
 	 *
 	 * TODO
@@ -759,21 +854,29 @@
 		var bookmark ;
 
 		if ( selectIt )
-			bookmark = range.CreateBookmark( true ) ;
+			bookmark = range.CreateBookmark() ;
 
 		var iterator = new FCKDomRangeIterator( range ) ;
 		iterator.EnforceRealBlocks = true ;
 
 		var block ;
+		var doc = range.Window.document ;
+
 		while( ( block = iterator.GetNextParagraph() ) )		// Only one =
 		{
 			// Create the new node right before the current one.
-			var newBlock = block.parentNode.insertBefore( this.BuildElement( range.Window.document ), block ) ;
+			var newBlock = this.BuildElement( doc ) ;
 
 			// Move everything from the current node to the new one.
-			FCKDomTools.MoveChildren( block, newBlock ) ;
+			if ( newBlock.nodeName.IEquals( 'pre' ) && !block.nodeName.IEquals( 'pre' ) )
+				this._ToPre( doc, block, newBlock ) ;
+			else if ( !newBlock.nodeName.IEquals( 'pre' ) && block.nodeName.IEquals( 'pre' ) )
+				this._FromPre( doc, block, newBlock ) ;
+			else	// Convering from a regular block to another regular block.
+				FCKDomTools.MoveChildren( block, newBlock ) ;
 
-			// Delete the current node.
+			// Replace the current block.
+			block.parentNode.insertBefore( newBlock, block ) ;
 			FCKDomTools.RemoveNode( block ) ;
 		}
 
@@ -782,7 +885,7 @@
 			range.SelectBookmark( bookmark ) ;
 
 		if ( updateRange )
-			range.MoveToBookmark( range ) ;
+			range.MoveToBookmark( bookmark ) ;
 	},
 
 	/**
Index: editor/_source/internals/fckregexlib.js
===================================================================
--- editor/_source/internals/fckregexlib.js	(revision 1504)
+++ editor/_source/internals/fckregexlib.js	(working copy)
@@ -93,5 +93,7 @@
 // name is returned with $2.
 StyleVariableAttName : /#\(\s*("|')(.+?)\1[^\)]*\s*\)/g,
 
-RegExp : /^\/(.*)\/([gim]*)$/
+RegExp : /^\/(.*)\/([gim]*)$/,
+
+HtmlTag : /<[^\s<>](?:"[^"]*"|'[^']*'|[^<])*>/
 } ;
Index: editor/fckeditor.html
===================================================================
--- editor/fckeditor.html	(revision 1504)
+++ editor/fckeditor.html	(working copy)
@@ -186,6 +186,7 @@
 LoadScript( '_source/classes/fckmenublockpanel.js' ) ;
 LoadScript( '_source/classes/fckcontextmenu.js' ) ;
 LoadScript( '_source/internals/fck_contextmenu.js' ) ;
+LoadScript( '_source/classes/fckhtmliterator.js' ) ;
 LoadScript( '_source/classes/fckplugin.js' ) ;
 LoadScript( '_source/internals/fckplugins.js' ) ;
 
Index: fckpackager.xml
===================================================================
--- fckpackager.xml	(revision 1504)
+++ fckpackager.xml	(working copy)
@@ -157,6 +157,7 @@
 		<File path="editor/_source/classes/fckmenublockpanel.js" />
 		<File path="editor/_source/classes/fckcontextmenu.js" />
 		<File path="editor/_source/internals/fck_contextmenu.js" />
+		<File path="editor/_source/class/fckhtmliterator.js" />
 
 		<File path="editor/_source/classes/fckplugin.js" />
 		<File path="editor/_source/internals/fckplugins.js" />
@@ -252,6 +253,7 @@
 		<File path="editor/_source/classes/fckmenublockpanel.js" />
 		<File path="editor/_source/classes/fckcontextmenu.js" />
 		<File path="editor/_source/internals/fck_contextmenu.js" />
+		<File path="editor/_source/class/fckhtmliterator.js" />
 
 		<File path="editor/_source/classes/fckplugin.js" />
 		<File path="editor/_source/internals/fckplugins.js" />
