platform-ui-home/R3_1/undo-redo-proposal/undo-redo support.html

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.5 - (download) (as text) (annotate)
Wed Feb 23 20:09:52 2005 UTC (4 years, 9 months ago) by sfranklin
Branch: MAIN
CVS Tags: HEAD
Changes since 1.4: +346 -1277 lines
reflect M5 implementation
<html xmlns:v="urn:schemas-microsoft-com:vml"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:w="urn:schemas-microsoft-com:office:word"
xmlns:st1="urn:schemas-microsoft-com:office:smarttags"
xmlns="http://www.w3.org/TR/REC-html40">

<head>
<meta http-equiv=Content-Type content="text/html; charset=windows-1252">
<meta name=ProgId content=Word.Document>
<meta name=Generator content="Microsoft Word 10">
<meta name=Originator content="Microsoft Word 10">
<link rel=File-List href="undo-redo%20support_files/filelist.xml">
<title>Undo/redo support in Eclipse</title>
<o:SmartTagType namespaceuri="urn:schemas-microsoft-com:office:smarttags"
 name="date"/>
<!--[if gte mso 9]><xml>
 <o:DocumentProperties>
  <o:Author>IBM_USER</o:Author>
  <o:LastAuthor>IBM_USER</o:LastAuthor>
  <o:Revision>16</o:Revision>
  <o:TotalTime>4560</o:TotalTime>
  <o:LastPrinted>2004-11-08T17:14:00Z</o:LastPrinted>
  <o:Created>2004-12-20T21:30:00Z</o:Created>
  <o:LastSaved>2005-02-23T20:07:00Z</o:LastSaved>
  <o:Pages>1</o:Pages>
  <o:Words>3508</o:Words>
  <o:Characters>20002</o:Characters>
  <o:Company>IBM</o:Company>
  <o:Lines>166</o:Lines>
  <o:Paragraphs>46</o:Paragraphs>
  <o:CharactersWithSpaces>23464</o:CharactersWithSpaces>
  <o:Version>10.6626</o:Version>
 </o:DocumentProperties>
</xml><![endif]--><!--[if gte mso 9]><xml>
 <w:WordDocument>
  <w:SpellingState>Clean</w:SpellingState>
  <w:GrammarState>Clean</w:GrammarState>
  <w:Compatibility>
   <w:BreakWrappedTables/>
   <w:SnapToGridInCell/>
   <w:WrapTextWithPunct/>
   <w:UseAsianBreakRules/>
  </w:Compatibility>
  <w:BrowserLevel>MicrosoftInternetExplorer4</w:BrowserLevel>
 </w:WordDocument>
</xml><![endif]--><!--[if !mso]><object
 classid="clsid:38481807-CA0E-42D2-BF39-B33AF135CC4D" id=ieooui></object>
<style>
st1\:*{behavior:url(#ieooui) }
</style>
<![endif]-->
<style>
<!--
 /* Font Definitions */
 @font-face
	{font-family:Wingdings;
	panose-1:5 0 0 0 0 0 0 0 0 0;
	mso-font-charset:2;
	mso-generic-font-family:auto;
	mso-font-pitch:variable;
	mso-font-signature:0 268435456 0 0 -2147483648 0;}
 /* Style Definitions */
 p.MsoNormal, li.MsoNormal, div.MsoNormal
	{mso-style-parent:"";
	margin:0in;
	margin-bottom:.0001pt;
	mso-pagination:widow-orphan;
	font-size:12.0pt;
	font-family:"Times New Roman";
	mso-fareast-font-family:"Times New Roman";}
h1
	{mso-style-next:Normal;
	margin-top:12.0pt;
	margin-right:0in;
	margin-bottom:3.0pt;
	margin-left:0in;
	mso-pagination:widow-orphan;
	page-break-after:avoid;
	mso-outline-level:1;
	font-size:16.0pt;
	font-family:Arial;
	mso-font-kerning:16.0pt;}
h2
	{mso-style-next:Normal;
	margin-top:12.0pt;
	margin-right:0in;
	margin-bottom:3.0pt;
	margin-left:0in;
	mso-pagination:widow-orphan;
	page-break-after:avoid;
	mso-outline-level:2;
	font-size:14.0pt;
	font-family:Arial;
	font-style:italic;}
h3
	{mso-style-next:Normal;
	margin-top:12.0pt;
	margin-right:0in;
	margin-bottom:3.0pt;
	margin-left:0in;
	mso-pagination:widow-orphan;
	page-break-after:avoid;
	mso-outline-level:3;
	font-size:13.0pt;
	font-family:Arial;}
h4
	{mso-style-next:Normal;
	margin-top:12.0pt;
	margin-right:0in;
	margin-bottom:3.0pt;
	margin-left:0in;
	mso-pagination:widow-orphan;
	page-break-after:avoid;
	mso-outline-level:4;
	font-size:14.0pt;
	font-family:"Times New Roman";}
h5
	{mso-style-next:Normal;
	margin-top:12.0pt;
	margin-right:0in;
	margin-bottom:3.0pt;
	margin-left:0in;
	mso-pagination:widow-orphan;
	mso-outline-level:5;
	font-size:13.0pt;
	font-family:"Times New Roman";
	font-style:italic;}
p.MsoFootnoteText, li.MsoFootnoteText, div.MsoFootnoteText
	{mso-style-noshow:yes;
	margin:0in;
	margin-bottom:.0001pt;
	mso-pagination:widow-orphan;
	font-size:10.0pt;
	font-family:"Times New Roman";
	mso-fareast-font-family:"Times New Roman";}
span.MsoFootnoteReference
	{mso-style-noshow:yes;
	vertical-align:super;}
p.MsoBodyText2, li.MsoBodyText2, div.MsoBodyText2
	{margin-top:0in;
	margin-right:0in;
	margin-bottom:6.0pt;
	margin-left:0in;
	line-height:200%;
	mso-pagination:widow-orphan;
	font-size:12.0pt;
	font-family:"Times New Roman";
	mso-fareast-font-family:"Times New Roman";}
a:link, span.MsoHyperlink
	{color:#0000EE;
	text-decoration:underline;
	text-underline:single;}
a:visited, span.MsoHyperlinkFollowed
	{color:purple;
	text-decoration:underline;
	text-underline:single;}
code
	{font-family:"Courier New";
	mso-ascii-font-family:"Courier New";
	mso-fareast-font-family:"Times New Roman";
	mso-hansi-font-family:"Courier New";
	mso-bidi-font-family:"Courier New";}
pre
	{margin:0in;
	margin-bottom:.0001pt;
	mso-pagination:widow-orphan;
	font-size:10.0pt;
	font-family:"Courier New";
	mso-fareast-font-family:"Times New Roman";}
span.SpellE
	{mso-style-name:"";
	mso-spl-e:yes;}
span.GramE
	{mso-style-name:"";
	mso-gram-e:yes;}
@page Section1
	{size:8.5in 11.0in;
	margin:1.0in .75in .5in 1.0in;
	mso-header-margin:.5in;
	mso-footer-margin:.5in;
	mso-paper-source:0;}
div.Section1
	{page:Section1;}
 /* List Definitions */
 @list l0
	{mso-list-id:125585718;
	mso-list-template-ids:-472349186;}
@list l0:level1
	{mso-level-number-format:bullet;
	mso-level-text:\F0B7;
	mso-level-tab-stop:.5in;
	mso-level-number-position:left;
	text-indent:-.25in;
	mso-ansi-font-size:10.0pt;
	font-family:Symbol;}
@list l1
	{mso-list-id:186870198;
	mso-list-template-ids:1303815946;}
@list l2
	{mso-list-id:200558114;
	mso-list-template-ids:-1989615594;}
@list l2:level1
	{mso-level-number-format:bullet;
	mso-level-text:\F0B7;
	mso-level-tab-stop:.5in;
	mso-level-number-position:left;
	text-indent:-.25in;
	mso-ansi-font-size:10.0pt;
	font-family:Symbol;}
@list l3
	{mso-list-id:347761159;
	mso-list-type:hybrid;
	mso-list-template-ids:-1680017606 67698689 67698691 67698693 67698689 67698691 67698693 67698689 67698691 67698693;}
@list l3:level1
	{mso-level-number-format:bullet;
	mso-level-text:\F0B7;
	mso-level-tab-stop:.5in;
	mso-level-number-position:left;
	text-indent:-.25in;
	font-family:Symbol;}
@list l3:level2
	{mso-level-tab-stop:1.0in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l3:level3
	{mso-level-tab-stop:1.5in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l3:level4
	{mso-level-tab-stop:2.0in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l3:level5
	{mso-level-tab-stop:2.5in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l3:level6
	{mso-level-tab-stop:3.0in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l3:level7
	{mso-level-tab-stop:3.5in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l3:level8
	{mso-level-tab-stop:4.0in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l3:level9
	{mso-level-tab-stop:4.5in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l4
	{mso-list-id:604456885;
	mso-list-type:hybrid;
	mso-list-template-ids:1734899956 67698703 67698691 67698693 67698689 67698691 67698693 67698689 67698691 67698693;}
@list l4:level1
	{mso-level-tab-stop:.5in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l4:level2
	{mso-level-number-format:bullet;
	mso-level-text:o;
	mso-level-tab-stop:1.0in;
	mso-level-number-position:left;
	text-indent:-.25in;
	font-family:"Courier New";}
@list l4:level3
	{mso-level-number-format:bullet;
	mso-level-text:\F0A7;
	mso-level-tab-stop:1.5in;
	mso-level-number-position:left;
	text-indent:-.25in;
	font-family:Wingdings;}
@list l4:level4
	{mso-level-number-format:bullet;
	mso-level-text:\F0B7;
	mso-level-tab-stop:2.0in;
	mso-level-number-position:left;
	text-indent:-.25in;
	font-family:Symbol;}
@list l4:level5
	{mso-level-tab-stop:2.5in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l4:level6
	{mso-level-tab-stop:3.0in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l4:level7
	{mso-level-tab-stop:3.5in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l4:level8
	{mso-level-tab-stop:4.0in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l4:level9
	{mso-level-tab-stop:4.5in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l5
	{mso-list-id:798038152;
	mso-list-type:hybrid;
	mso-list-template-ids:-2087438622 67698703 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;}
@list l5:level1
	{mso-level-tab-stop:39.0pt;
	mso-level-number-position:left;
	margin-left:39.0pt;
	text-indent:-.25in;}
@list l5:level2
	{mso-level-tab-stop:1.0in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l5:level3
	{mso-level-tab-stop:1.5in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l5:level4
	{mso-level-tab-stop:2.0in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l5:level5
	{mso-level-tab-stop:2.5in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l5:level6
	{mso-level-tab-stop:3.0in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l5:level7
	{mso-level-tab-stop:3.5in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l5:level8
	{mso-level-tab-stop:4.0in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l5:level9
	{mso-level-tab-stop:4.5in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l6
	{mso-list-id:818612470;
	mso-list-template-ids:-543663642;}
@list l7
	{mso-list-id:974408184;
	mso-list-template-ids:-653113708;}
@list l8
	{mso-list-id:1085106306;
	mso-list-type:hybrid;
	mso-list-template-ids:1015583604 67698703 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;}
@list l8:level1
	{mso-level-tab-stop:.5in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l8:level2
	{mso-level-tab-stop:1.0in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l8:level3
	{mso-level-tab-stop:1.5in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l8:level4
	{mso-level-tab-stop:2.0in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l8:level5
	{mso-level-tab-stop:2.5in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l8:level6
	{mso-level-tab-stop:3.0in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l8:level7
	{mso-level-tab-stop:3.5in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l8:level8
	{mso-level-tab-stop:4.0in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l8:level9
	{mso-level-tab-stop:4.5in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l9
	{mso-list-id:1478297229;
	mso-list-type:hybrid;
	mso-list-template-ids:-438127954 67698689 67698691 67698693 67698689 67698691 67698693 67698689 67698691 67698693;}
@list l9:level1
	{mso-level-number-format:bullet;
	mso-level-text:\F0B7;
	mso-level-tab-stop:.5in;
	mso-level-number-position:left;
	text-indent:-.25in;
	font-family:Symbol;}
@list l9:level2
	{mso-level-tab-stop:1.0in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l9:level3
	{mso-level-tab-stop:1.5in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l9:level4
	{mso-level-tab-stop:2.0in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l9:level5
	{mso-level-tab-stop:2.5in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l9:level6
	{mso-level-tab-stop:3.0in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l9:level7
	{mso-level-tab-stop:3.5in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l9:level8
	{mso-level-tab-stop:4.0in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l9:level9
	{mso-level-tab-stop:4.5in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l10
	{mso-list-id:1723091313;
	mso-list-type:hybrid;
	mso-list-template-ids:-1797201838 67698703 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;}
@list l10:level1
	{mso-level-tab-stop:.5in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l10:level2
	{mso-level-tab-stop:1.0in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l10:level3
	{mso-level-tab-stop:1.5in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l10:level4
	{mso-level-tab-stop:2.0in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l10:level5
	{mso-level-tab-stop:2.5in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l10:level6
	{mso-level-tab-stop:3.0in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l10:level7
	{mso-level-tab-stop:3.5in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l10:level8
	{mso-level-tab-stop:4.0in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l10:level9
	{mso-level-tab-stop:4.5in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l11
	{mso-list-id:1731031428;
	mso-list-type:hybrid;
	mso-list-template-ids:1886447558 67698703 67698713 67698715 67698703 67698713 67698715 67698703 67698713 67698715;}
@list l11:level1
	{mso-level-tab-stop:39.0pt;
	mso-level-number-position:left;
	margin-left:39.0pt;
	text-indent:-.25in;}
@list l11:level2
	{mso-level-tab-stop:1.0in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l11:level3
	{mso-level-tab-stop:1.5in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l11:level4
	{mso-level-tab-stop:2.0in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l11:level5
	{mso-level-tab-stop:2.5in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l11:level6
	{mso-level-tab-stop:3.0in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l11:level7
	{mso-level-tab-stop:3.5in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l11:level8
	{mso-level-tab-stop:4.0in;
	mso-level-number-position:left;
	text-indent:-.25in;}
@list l11:level9
	{mso-level-tab-stop:4.5in;
	mso-level-number-position:left;
	text-indent:-.25in;}
ol
	{margin-bottom:0in;}
ul
	{margin-bottom:0in;}
-->
</style>
<!--[if gte mso 10]>
<style>
 /* Style Definitions */
 table.MsoNormalTable
	{mso-style-name:"Table Normal";
	mso-tstyle-rowband-size:0;
	mso-tstyle-colband-size:0;
	mso-style-noshow:yes;
	mso-style-parent:"";
	mso-padding-alt:0in 5.4pt 0in 5.4pt;
	mso-para-margin:0in;
	mso-para-margin-bottom:.0001pt;
	mso-pagination:widow-orphan;
	font-size:10.0pt;
	font-family:"Times New Roman";}
</style>
<![endif]-->
</head>

<body lang=EN-US link="#0000EE" vlink=purple style='tab-interval:.5in'>

<div class=Section1>

<h1>Generalized Undo Support in Eclipse</h1>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>Last
updated:<span style='mso-spacerun:yes'>  </span></span><st1:date Year="2005"
Day="22" Month="2"><span style='font-size:10.0pt;font-family:Arial'>Feb. 22,
 2005</span></st1:date><span style='font-size:10.0pt;font-family:Arial'><o:p></o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>Status:<span
style='mso-spacerun:yes'>  </span>Proposal – Implemented in 3.1M5<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>(<span
class=GramE>see</span> also bug <span style='mso-spacerun:yes'> </span></span><a
href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=37716">37716</a>)<span
style='font-size:10.0pt;font-family:Arial'><o:p></o:p></span></p>

<h2>Problem Description</h2>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>In R3.0.1
of the Eclipse SDK, there is no generalized support for undoing user
actions.<span style='mso-spacerun:yes'>  </span>Each plug-in is left to
implement its own strategy for undo, if at all.<span style='mso-spacerun:yes'> 
</span>This approach can cause problems for both Eclipse users and plug-in
developers:<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'><span
style='mso-spacerun:yes'> </span><o:p></o:p></span></p>

<ul style='margin-top:0in' type=disc>
 <li class=MsoNormal style='mso-list:l3 level1 lfo3;tab-stops:list .5in'><span
     style='font-size:10.0pt;font-family:Arial'>Undo and redo actions appear in
     different menus, causing user confusion and UI clutter<o:p></o:p></span></li>
 <li class=MsoNormal style='mso-list:l3 level1 lfo3;tab-stops:list .5in'><span
     style='font-size:10.0pt;font-family:Arial'>Undo and redo implementations
     may have different semantics.<o:p></o:p></span></li>
 <li class=MsoNormal style='mso-list:l3 level1 lfo3;tab-stops:list .5in'><span
     style='font-size:10.0pt;font-family:Arial'>Plug-ins that depend on other
     plug-ins which implement their own undo strategy are forced to choose
     between different implementations and possibly write integration code to
     allow the different frameworks to coexist.<o:p></o:p></span></li>
</ul>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>Further,
the meaning of undo can be very different depending on what the user is
doing.<span style='mso-spacerun:yes'>  </span>The most common type of undo is
text undo.<span style='mso-spacerun:yes'>  </span>The user can undo lightweight
edit operations such as inserting, replacing, or deleting text.<span
style='mso-spacerun:yes'>  </span>Other types of undo may involve more complex,
heavyweight operations that affect an underlying model of many elements.<span
style='mso-spacerun:yes'>  </span>For example, the JDT refactoring support
provides undo support for refactoring operations that involve many Java
elements at different levels, such as Java packages, compilation units,
classes, and methods.<o:p></o:p></span></p>

<h2>Operations Framework</h2>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>The
proposed framework defines an interface for describing work, called an “undoable
operation” (<span class=SpellE>IUndoableOperation</span><span class=GramE>),
that</span> can be executed, undone, and redone.<span
style='mso-spacerun:yes'>  </span>Undoable operations are created, executed,
and added to an operations history (<span class=SpellE>IOperationHistory</span>).<span
style='mso-spacerun:yes'>  </span>Operations which are comprised of distinct
steps should be represented as compound operations, which are executed, undone,
or redone as a unit, and can never be partially undone.<span
style='mso-spacerun:yes'>  </span><o:p></o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>Operations
can be assigned one or more contexts (<span class=SpellE>IUndoContext</span>)
to which they apply.<span style='mso-spacerun:yes'>  </span>An undo context
describes the context in which the user is working when an operation is performed,
undone, or redone.<span style='mso-spacerun:yes'>  </span>Undo contexts can be
used by workbench parts to filter the operations history, so that only those
operations that have been assigned the context of interest to a particular part
are available for undo/redo when that part is active.<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>The
interface for undo contexts is left very general so that operation implementers
may choose the appropriate representation for their contexts.<span
style='mso-spacerun:yes'>  </span>In some cases, a part-oriented context may be
appropriate. For example, a text editor’s context is related to the editor
itself and its life-cycle is similar to that of the editor.<span
style='mso-spacerun:yes'>  </span>The resource navigator’s context is closely
related to the workspace model objects, and the context related to the
workspace has a life cycle to similar to that of the workspace itself.<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>Contexts
can be assigned to operations in multiple ways:<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal style='margin-left:39.0pt;text-indent:-.25in;mso-list:l11 level1 lfo5;
tab-stops:list 39.0pt'><![if !supportLists]><span style='font-size:10.0pt;
font-family:Arial;mso-fareast-font-family:Arial'><span style='mso-list:Ignore'>1.<span
style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]><span
style='font-size:10.0pt;font-family:Arial'>The context can be assigned
initially when the operation is created.<span style='mso-spacerun:yes'> 
</span>For example, text operations are triggered by typing in the editor, and
the editor can assign its context to the operation before adding it to the
history.<span style='mso-spacerun:yes'>  </span><o:p></o:p></span></p>

<p class=MsoNormal style='margin-left:39.0pt;text-indent:-.25in;mso-list:l11 level1 lfo5;
tab-stops:list 39.0pt'><![if !supportLists]><span style='font-size:10.0pt;
font-family:Arial;mso-fareast-font-family:Arial'><span style='mso-list:Ignore'>2.<span
style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]><span
style='font-size:10.0pt;font-family:Arial'>A listener interface on the
operations history allows listeners to detect when an operation is added to the
history.<span style='mso-spacerun:yes'>  </span>Listeners can decide if their
context should be added to the operation.<span style='mso-spacerun:yes'> 
</span><o:p></o:p></span></p>

<p class=MsoNormal style='margin-left:39.0pt;text-indent:-.25in;mso-list:l11 level1 lfo5;
tab-stops:list 39.0pt'><![if !supportLists]><span style='font-size:10.0pt;
font-family:Arial;mso-fareast-font-family:Arial'><span style='mso-list:Ignore'>3.<span
style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]><span
style='font-size:10.0pt;font-family:Arial'>Operations can be executed in a
batch mode.<span style='mso-spacerun:yes'>  </span>When a batching operation is
being executed, any other operations that execute have their contexts assigned
to the batch operation.<o:p></o:p></span></p>

<p class=MsoNormal style='margin-left:21.0pt'><span style='font-size:10.0pt;
font-family:Arial'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>An
operation may have more than one context.<span style='mso-spacerun:yes'> 
</span>For example, an operation may affect many elements in the workspace,
including one that is currently open in an editor.<span
style='mso-spacerun:yes'>  </span>That operation could be assigned two
independent contexts, so that it can be undone from both the editor and the
view manipulating the model.<span style='mso-spacerun:yes'>   </span><o:p></o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'><o:p>&nbsp;</o:p></span></p>

<h2>Levels of Integration and Migration</h2>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>Many
plug-ins have already invested heavily in building objects that describe
undoable user commands or operations.<span style='mso-spacerun:yes'>  </span>It
is not expected that all plug-ins will adopt the framework completely, given
the individual schedules and other constraints for each plug-in.<span
style='mso-spacerun:yes'>  </span>However, the integration can be achieved in
phases that will immediately provide value to dependent plug-ins.<span
style='mso-spacerun:yes'>  </span>The following adoption strategy is strongly
encouraged:<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'><o:p>&nbsp;</o:p></span></p>

<ol style='margin-top:0in' start=1 type=1>
 <li class=MsoNormal style='mso-list:l10 level1 lfo8;tab-stops:list .5in'><span
     style='font-size:10.0pt;font-family:Arial'>Existing command/undo
     frameworks can implement the <span class=SpellE>IUndoableOperation</span>
     interface on their existing command objects, while still maintaining their
     individual strategies for managing undo stacks or histories.<span
     style='mso-spacerun:yes'>  </span>If there is a substantial investment in
     an existing model-based operation or command framework, wrappers could be
     used to map <span class=SpellE>IUndoableOperation</span> protocol to the
     existing protocol.<span style='mso-spacerun:yes'>  </span>The
     commands/operations need not be assigned a context or added to a common
     operation history.<span style='mso-spacerun:yes'>  </span>This level of
     integration allows command hierarchies built in different frameworks to be
     treated the same by plug-ins that depend upon these different
     frameworks.<span style='mso-spacerun:yes'>  </span>Clients of existing
     command frameworks may then use the workbench operation history, assign
     contexts to operations as needed, and even add operations to the history,
     while still using commands built on earlier frameworks.<o:p></o:p></span></li>
 <li class=MsoNormal style='mso-list:l10 level1 lfo8;tab-stops:list .5in'><span
     style='font-size:10.0pt;font-family:Arial'>Existing command/undo
     frameworks may use the listener interfaces provided by the operations
     history to listen for operations that are of interest.<span
     style='mso-spacerun:yes'>  </span>These commands may be wrapped or
     otherwise recorded so that they can be undone from privately maintained
     undo implementations.<span style='mso-spacerun:yes'>  </span>This level of
     integration allows views and editors to appear more tightly integrated
     with the operations framework, since workbench operations of interest can
     be undone or redone from private undo implementations.<o:p></o:p></span></li>
 <li class=MsoNormal style='mso-list:l10 level1 lfo8;tab-stops:list .5in'><span
     style='font-size:10.0pt;font-family:Arial'>Full integration is achieved by
     using the workbench operation history to record the undo and redo history
     as operations occur.<span style='mso-spacerun:yes'>  </span>Once all
     plug-ins share an operation history, clients will be able to use unified
     listeners and handlers to track execution of operations, undo, and redo
     them.<span style='mso-spacerun:yes'>  </span><o:p></o:p></span></li>
</ol>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>Framework
interfaces will be defined in the <span class=SpellE>org.eclipse.core.commands.operations</span>
package in the <span class=SpellE>org.eclipse.core.commands</span>
plug-in.<span style='mso-spacerun:yes'>  </span>This plug-in has no
dependencies on the Eclipse runtime architecture (apart from some runtime classes
such as <span class=SpellE>IProgressMonitor</span>, <span class=SpellE>IStatus</span>,
<span class=SpellE><span class=GramE>IAdaptable</span></span>), so raw <span
class=SpellE>JFace</span> clients may make use of it.<o:p></o:p></span></p>

<h2>Operations and Concurrency</h2>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>The
operations framework relies on the notion of sequential execution of undoable
operations.<span style='mso-spacerun:yes'>  </span>For R3.1, there will be no
specific support built into the framework for concurrent operations that
execute inside platform Jobs.<span style='mso-spacerun:yes'>  </span>Actions whose
work is currently executed inside a Job may be converted to <span class=SpellE>IUndoableOperation</span>,
but they should not be added to the operation history until after they have
finished their execution.<span style='mso-spacerun:yes'>  </span>The undo and
redo behavior for these kinds of <span class=SpellE>IUndoableOperation</span> must
be implemented in a synchronous manner for R3.1, since the validity of other
operations in the operation history may not be properly determined if an undo
or redo is executing asynchronously in a Job.<span style='mso-spacerun:yes'> 
</span>More robust support for concurrent, undoable operations may be
considered in future releases as requirements are discovered.<o:p></o:p></span></p>

<h2>Framework interfaces</h2>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>Initial
implementations of the proposed framework interfaces appear in R3.1 M5.<span
style='mso-spacerun:yes'>  </span>See the <span class=SpellE>Javadoc</span> for
the described classes for the complete specification.<span
style='mso-spacerun:yes'>   </span>Please note that the specification is still
evolving and early adopters should be prepared for API changes throughout the
R3.1 development cycle.<o:p></o:p></span></p>

<h3><span class=SpellE>IUndoableOperation</span></h3>

<p class=MsoNormal><span class=SpellE><span style='font-size:10.0pt;font-family:
Arial'>IUndoableOperation</span></span><span style='font-size:10.0pt;
font-family:Arial'> defines an operation that can be executed, undone, and
redone.<span style='mso-spacerun:yes'>  </span>Operations typically have fully
defined parameters. That is, they are usually created after the user has been
queried for any input needed to define the operation.<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>Operations
determine their ability to execute, undo, or redo according to the current
state of the application. They do not make decisions about their validity based
on where they occur in the operation history. That is left to the particular
operation history.<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'><o:p>&nbsp;</o:p></span></p>

<h3><span class=SpellE>IOperationHistory</span></h3>

<p class=MsoNormal><span class=SpellE><span style='font-size:10.0pt;font-family:
Arial'>IOperationHistory</span></span><span style='font-size:10.0pt;font-family:
Arial'> tracks a history of operations that can be undone or redone. Operations
are added to the history after they have been initially executed. Clients may
choose whether to have the operations history perform the initial execution or
simply add the operation to the history. Once operations are added to the
history, the methods <span class=SpellE><span class=GramE>canRedo</span></span><span
class=GramE>(</span>) and <span class=SpellE>canUndo</span>() are used to
determine whether there is an operation available for undo and redo in a given undo
context.<span style='mso-spacerun:yes'>  </span>The context-based protocol
implies that there is only one operation that can be undone or redone at a
given time in a given context. This is typical of a linear undo model, when
only the most recently executed operation is available for undo. When this
protocol is used, a linear model is enforced by the history. It is up to
clients to determine how to maintain a history that is invalid or stale. For
example, when the most recent operation for a context cannot be performed,
clients may wish to flush the history for that context.<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>Additional
protocol allows direct undo and redo of a specified operation, regardless of
its position in the history. When a more flexible undo model is supported,
these methods can be implemented to undo and redo directly specified
operations. If an implementer of <span class=SpellE>IOperationHistory</span>
does not allow direct undo and redo, these methods can return a status
indicating that it is not allowed.<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>Listeners (<span
class=SpellE>IOperationHistoryListener</span>) can listen for notifications
about changes in the history (operations added or removed), and for
notification before and after any operation is executed, undone or redone.
Notification of operation execution only occurs when clients direct the history
to execute the operation. If the operation is added after it is executed, there
can be no notification of its execution.<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span class=SpellE><span style='font-size:10.0pt;font-family:
Arial'>IOperationApprover</span></span><span style='font-size:10.0pt;
font-family:Arial'> defines an interface for approving an undo or redo before
it occurs. This is useful for injecting policy-decisions into the model -
whether direct undo and redo are supported, or warning the user about certain
kinds of operations. It can also be used when objects have state related to the
operation and need to determine whether an undo or redo will cause any
conflicts with their local state.<o:p></o:p></span></p>

<h3><span class=SpellE>IOperationApprover</span></h3>

<p class=MsoNormal><span class=SpellE><span style='font-size:10.0pt;font-family:
Arial'>IOperationApprover</span></span><span style='font-size:10.0pt;
font-family:Arial'> defines an interface for approving the undo or redo of a
particular operation within an operation history. Operations that are
candidates for undo or redo have already been validated against their current
state and according to the rules of the history.<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>By the time
an <span class=SpellE>IOperationApprover</span> is consulted, the undo has
already been requested. Approvers should true if the operation should proceed,
and false if it should not. When an operation is rejected, it is expected that
the object rejecting the operation has already consulted the user if necessary
or otherwise provided any necessary information to the user about the
rejection.<span style='mso-spacerun:yes'>  </span>If an undo or redo is
triggered from the UI, clients provide UI info (such as an <span class=SpellE>org.eclipse.swt.Shell</span>)
to assist in prompting the user where necessary.<o:p></o:p></span></p>

<h3><span class=SpellE>IOperationHistoryListener</span></h3>

<p class=MsoNormal><span class=SpellE><span style='font-size:10.0pt;font-family:
Arial'>IOperationHistoryListener</span></span><span style='font-size:10.0pt;
font-family:Arial'> defines the interface for being notified about particular
events that take place inside the operation history.<o:p></o:p></span></p>

<h3><span class=SpellE>OperationHistoryEvent</span></h3>

<p class=MsoNormal><span class=SpellE><span style='font-size:10.0pt;font-family:
Arial'>OperationHistoryEvent</span></span><span style='font-size:10.0pt;
font-family:Arial'> defines the different types of events that occur inside an
operation history.<span style='mso-spacerun:yes'>  </span><span class=GramE>Listeners
are notified before and after an operation is</span> executed, undone, or
redone.<span style='mso-spacerun:yes'>  </span>Listeners are also notified when
operations are added or removed from the history.<o:p></o:p></span></p>

<h3><span class=SpellE>OperationHistoryFactory</span></h3>

<p class=MsoNormal><span class=SpellE><span style='font-size:10.0pt;font-family:
Arial'>OperationHistoryFactory</span></span><span style='font-size:10.0pt;
font-family:Arial'> provides access to a singleton instance of an operation
history.<span style='mso-spacerun:yes'>  </span>This factory will provide a
default implementation for an operation history if one is not set by a
caller.<span style='mso-spacerun:yes'>  </span>Once the singleton is obtained
by any client, the instance cannot be reset.<o:p></o:p></span></p>

<h2>UI Support Classes<span style='font-size:10.0pt'><o:p></o:p></span></h2>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>Additional
support classes are provided in the package <span class=SpellE>org.eclipse.ui.operations</span>.<span
style='mso-spacerun:yes'>  </span>These classes handle policy decisions about
the undo model to be used by the workbench.<span style='mso-spacerun:yes'> 
</span>Access to the undo and redo handlers, as well as the operations history,
will be provided through workbench.<o:p></o:p></span></p>

<h3>Workbench Operation History</h3>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>The
workbench will configure the default operation history supplied by the <span
class=SpellE>OperationHistoryFactory</span> and register an <span class=SpellE>IUndoContext</span>
adapter onto the workspace.<span style='mso-spacerun:yes'> 
</span>Configuration of the operation history includes setting an undo limit
for the workspace undo context and adding an <span class=SpellE>IOperationApprover</span>
that enforces a per-context linear undo model.<span style='mso-spacerun:yes'> 
</span><o:p></o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>Undo
contexts will be defined for text editors and for the workspace.<span
style='mso-spacerun:yes'>  </span>Throughout the development of R3.1, plug-ins
will be encouraged to define operations that represent their existing actions
or command handlers.<span style='mso-spacerun:yes'>  </span>Additional contexts
may be defined by plug-ins as necessary.<span style='mso-spacerun:yes'> 
</span>Undoable operations will be added incrementally once the framework is in
place.<span style='mso-spacerun:yes'>  </span><o:p></o:p></span></p>

<h3><span class=SpellE>IWorkbenchOperationSupport</span></h3>

<p class=MsoNormal><span class=SpellE><span style='font-size:10.0pt;font-family:
Arial'>IWorkbenchOperationSupport</span></span><span style='font-size:10.0pt;
font-family:Arial'> provides access to the workbench operation history and the
workspace undo context.<span style='mso-spacerun:yes'>  </span>Although these objects
are actually managed elsewhere (in the <span class=SpellE>OperationHistoryFactory</span>
and as an adapter on the workspace), <span class=SpellE>IWorkbenchOperationSupport</span>
provides integrated access to all undo facilities used by the workbench.<span
style='mso-spacerun:yes'>  </span>Plug-ins aware of the workbench will typically
get the <span class=SpellE>IWorkbenchOperationSupport</span> from the workbench
to obtain the appropriate context and operation history.<span
style='mso-spacerun:yes'>  </span>Lower-level (headless) plug-ins that implement
undo support will use the lower level constructs, such as the <span
class=SpellE>OperationHistoryFactory</span>, to obtain these objects.</span><o:p></o:p></p>

<h3><span class=SpellE>UndoActionHandler</span> and <span class=SpellE>RedoActionHandler</span></h3>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>The
Edit&gt;Undo and Edit&gt;Redo commands should be handled by any parts that wish
to support undo.<span style='mso-spacerun:yes'>  </span>Common handlers for the
undo and redo commands will be provided.<span style='mso-spacerun:yes'> 
</span>These handlers can be assigned an undo context that should be used to
filter the undo and redo history.<span style='mso-spacerun:yes'>  </span>The
handlers are responsible for the following:<o:p></o:p></span></p>

<ul style='margin-top:0in' type=disc>
 <li class=MsoNormal style='mso-list:l9 level1 lfo11;tab-stops:list .5in'><span
     style='font-size:10.0pt;font-family:Arial'>Undo and Redo commands will be
     enabled based on the status of the history.<o:p></o:p></span></li>
 <li class=MsoNormal style='mso-list:l9 level1 lfo11;tab-stops:list .5in'><span
     style='font-size:10.0pt;font-family:Arial'>The Undo and Redo commands will
     be appended with the label of the operation for the handler’s context.<o:p></o:p></span></li>
 <li class=MsoNormal style='mso-list:l9 level1 lfo11;tab-stops:list .5in'><span
     style='font-size:10.0pt;font-family:Arial'>The handlers can be configured
     to flush the undo and redo history for their context whenever the most
     recent operation in the history is invalid.<span
     style='mso-spacerun:yes'>  </span>This aggressive maintenance of the
     history is the most conservative approach for ensuring that the history
     contains valid operations, and this strategy may evolve with experience.<span
     style='mso-spacerun:yes'>  </span>Localized undo contexts, such as text
     edits, may not need this aggressive pruning of the history.<o:p></o:p></span></li>
</ul>

<h3>Undo and Redo Toolbar Items</h3>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>Time
permitting, classes that support toolbar dropdown items for undo and redo will
be developed.<span style='mso-spacerun:yes'>  </span>These will also be
assigned a context.<span style='mso-spacerun:yes'>  </span>By clicking on the
drop-down arrow, the user will see the history for that particular
context.<span style='mso-spacerun:yes'>  </span>The user will only be able to
select a range, starting from the top item, to be undone or redone.<span
style='mso-spacerun:yes'>  </span>It is expected that the ability to view the
history is more valuable to the user than the ability to multi-select
operations for undo.<o:p></o:p></span></p>

<h3>Operation Approvers</h3>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>The <span
class=SpellE>IOperationApprover</span> installed by the workbench enforces a
per-context linear undo model by consulting all contexts of an operation to
determine whether undo or redo should proceed.<span style='mso-spacerun:yes'> 
</span>The policy is described as follows:<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>The
workbench will allow undo or redo of any valid operation in the history, <i
style='mso-bidi-font-style:normal'>as long as there are no more recent
operations in the history that share a context with the operation to be
executed.</i><span style='mso-spacerun:yes'>   </span>If the operation to be
undone or redone has contexts that are also present in operations appearing
later in the history, then the undo or redo of the operation will not be
permitted.<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>A concrete
example will help explain this.<span style='mso-spacerun:yes'>  </span><o:p></o:p></span></p>

<ol style='margin-top:0in' start=1 type=1>
 <li class=MsoNormal style='mso-list:l4 level1 lfo14;tab-stops:list .5in'><span
     style='font-size:10.0pt;font-family:Arial'>The user makes local edits in
     editor A.<o:p></o:p></span></li>
 <li class=MsoNormal style='mso-list:l4 level1 lfo14;tab-stops:list .5in'><span
     style='font-size:10.0pt;font-family:Arial'>The user initiates a
     refactoring operation whose context is “A” and “workspace.”<o:p></o:p></span></li>
 <li class=MsoNormal style='mso-list:l4 level1 lfo14;tab-stops:list .5in'><span
     style='font-size:10.0pt;font-family:Arial'>The user makes additional local
     edits to editor A.<o:p></o:p></span></li>
 <li class=MsoNormal style='mso-list:l4 level1 lfo14;tab-stops:list .5in'><span
     style='font-size:10.0pt;font-family:Arial'>The user goes to the navigator
     and selects Undo.<o:p></o:p></span></li>
</ol>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>In the
proposed implementation, the navigator requests an undo for the workspace
context.<span style='mso-spacerun:yes'>  </span>The refactoring operation
triggered in the editor is the most recent operation that has the workspace
context, but it also contains context “A.”<span style='mso-spacerun:yes'> 
</span>Since subsequent operations in the history also have context “A,”, the
operation will not be allowed.<span style='mso-spacerun:yes'>  </span>An
explanation will be provided to the user after the fact:<span
style='mso-spacerun:yes'>  </span>“Cannot undo the refactoring operation
because there have been subsequent changes to A.”<span
style='mso-spacerun:yes'>  </span><o:p></o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>Future
releases may warn the user or provide a preference to determine whether the
undo should proceed anyway, and whether the subsequent changes to “A” should
also be undone, or be flushed from the history. Early prototypes of the
framework showed that such warnings interrupt workflow and can be very
difficult to understand, so the initial UI will be to prohibit the undo,
explaining why.<span style='mso-spacerun:yes'>   </span><o:p></o:p></span></p>

<h2>Migration Examples</h2>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>The
following examples explain how existing code can be migrated to use the
operations framework.<span style='mso-spacerun:yes'>  </span>An early prototype
used these techniques to integrate the SDK text editor, refactoring framework,
and sample applications into a common undo framework.<span
style='mso-spacerun:yes'>  </span></span></p>

<h3>Mapping existing actions or command handlers to operations</h3>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>Converting an
existing action to use operations is straightforward, apart from implementing
the undo and redo behavior for the action.<span style='mso-spacerun:yes'> 
</span>The run() or <span class=SpellE>runWithEvent</span> method inside the
action should create an operation, execute it, and add it to the operations
history, rather than run the code inside the method.<span
style='mso-spacerun:yes'>  </span>The following code shows the existing run()
method in the <span class=SpellE>EditorAction</span> of the <span class=SpellE>readme</span>
tool example (<span class=SpellE>org.eclipse.ui.examples.readmetool</span>):<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'><o:p>&nbsp;</o:p></span></p>

<pre>public void run() {</pre><pre><span style='mso-spacerun:yes'>            </span>String <span
class=SpellE>editorName</span> = <span class=SpellE>MessageUtil.getString</span>(&quot;<span
class=SpellE>Empty_Editor_Name</span>&quot;); </pre><pre><span style='mso-spacerun:yes'>            </span>if (<span
class=SpellE>activeEditor</span> != null)</pre><pre><span style='mso-spacerun:yes'>                </span><span
class=SpellE>editorName</span> = <span class=SpellE>activeEditor.getTitle</span>();</pre><pre><span style='mso-spacerun:yes'>            </span><span
class=SpellE>MessageDialog</span></pre><pre><span style='mso-spacerun:yes'>                    </span>.<span
class=SpellE>openInformation</span>(</pre><pre><span style='mso-spacerun:yes'>                            </span>shell,</pre><pre><span style='mso-spacerun:yes'>                            </span><span
class=SpellE>MessageUtil.getString</span>(&quot;<span class=SpellE>Readme_Editor</span>&quot;), </pre><pre><span style='mso-spacerun:yes'>                            </span><span
class=SpellE>MessageUtil.format</span>(&quot;<span class=SpellE>ReadmeEditorActionExecuted</span>&quot;, </pre><pre><span
style='mso-tab-count:4'>                               </span>new Object[] { <span
class=SpellE>getText</span>(), <span class=SpellE>editorName</span> })); </pre><pre><span style='mso-spacerun:yes'>        </span>}</pre><pre><span
style='font-family:Arial'>Using operations, the run method simplifies:<o:p></o:p></span></pre><pre><span
style='font-family:Arial'><o:p>&nbsp;</o:p></span></pre><pre><span style='mso-spacerun:yes'>        </span>public void run() {</pre><pre><span style='mso-spacerun:yes'>            </span>String <span
class=SpellE>editorName</span> = <span class=SpellE>MessageUtil.getString</span>(&quot;<span
class=SpellE>Empty_Editor_Name</span>&quot;); </pre><pre><span style='mso-spacerun:yes'>            </span>if (<span
class=SpellE>activeEditor</span> != null)</pre><pre><span style='mso-spacerun:yes'>                </span><span
class=SpellE>editorName</span> = <span class=SpellE>activeEditor.getTitle</span>();</pre><pre><span style='mso-spacerun:yes'>            </span>// create the operation</pre><pre><span style='mso-spacerun:yes'>            </span><span
class=SpellE>IUndoableOperation</span> operation = new <span class=SpellE><span
class=GramE>EditorOperation</span></span><span class=GramE>(</span></pre><pre><span
style='mso-tab-count:2'>               </span><span class=SpellE>getText</span>(),shell, <span
class=SpellE>editorName</span>);</pre><pre><span style='mso-spacerun:yes'>            </span>// execute (and add to the history)</pre><pre><span style='mso-spacerun:yes'>            </span><span
class=SpellE>history.execute</span>(operation, null, null);<span style='mso-spacerun:yes'>  </span></pre><pre><span style='mso-spacerun:yes'>        </span>}</pre><pre><span
style='font-family:Arial'>The operation encapsulates the old run behavior, as well as the undo and redo for the operation:<o:p></o:p></span></pre><pre><span
style='font-family:Arial'><o:p>&nbsp;</o:p></span></pre><pre>class <span
class=SpellE>EditorOperation</span> extends <span class=SpellE>AbstractOperation</span> {</pre><pre><span style='mso-spacerun:yes'>        </span>Shell <span
class=SpellE>fShell</span>;</pre><pre><span style='mso-spacerun:yes'>        </span>String <span
class=SpellE>fEditorName</span>;</pre><pre><span style='mso-spacerun:yes'>        </span>public <span
class=SpellE>EditorOperation</span>(String label, Shell <span class=SpellE>shell</span>, String <span
class=SpellE>editorName</span>) {</pre><pre><span style='mso-spacerun:yes'>            </span>super(label);</pre><pre><span style='mso-spacerun:yes'>            </span><span
class=SpellE>fShell</span> = shell;</pre><pre><span style='mso-spacerun:yes'>            </span><span
class=SpellE>fEditorName</span> = <span class=SpellE>editorName</span>;</pre><pre><span style='mso-spacerun:yes'>            </span></pre><pre><span style='mso-spacerun:yes'>   </span><span style='mso-spacerun:yes'>     </span>}</pre><pre><span style='mso-spacerun:yes'>        </span>public <span
class=SpellE>IStatus</span> execute(<span class=SpellE>IProgressMonitor</span> monitor) {</pre><pre><span style='mso-spacerun:yes'>            </span><span
class=SpellE>MessageDialog.openInformation</span>(</pre><pre><span style='mso-spacerun:yes'>                    </span><span
class=SpellE>fShell</span>,</pre><pre><span style='mso-spacerun:yes'>                    </span><span
class=SpellE>MessageUtil.getString</span>(&quot;<span class=SpellE>Readme_Editor</span>&quot;), </pre><pre><span style='mso-spacerun:yes'>                    </span><span
class=SpellE>MessageUtil.format</span>(&quot;<span class=SpellE>ReadmeEditorActionExecuted</span>&quot;, </pre><pre><span
style='mso-tab-count:3'>                       </span>new Object[] { <span
class=SpellE>getLabel</span>(), <span class=SpellE>fEditorName</span> }));<span style='mso-spacerun:yes'>  </span></pre><pre><span style='mso-spacerun:yes'>            </span>return <span
class=SpellE>Status.OK_STATUS</span>;</pre><pre><span style='mso-spacerun:yes'>        </span>}</pre><pre><span style='mso-spacerun:yes'>        </span>public <span
class=SpellE>IStatus</span> undo(<span class=SpellE>IProgressMonitor</span> monitor) {</pre><pre><span style='mso-spacerun:yes'>            </span>// implement the undo here</pre><pre><span style='mso-spacerun:yes'>            </span>return <span
class=SpellE>Status.OK_STATUS</span>;</pre><pre><span style='mso-spacerun:yes'>        </span>}</pre><pre><span style='mso-spacerun:yes'>      </span><span style='mso-spacerun:yes'>  </span>public <span
class=SpellE>IStatus</span> redo(<span class=SpellE>IProgressMonitor</span> monitor) {</pre><pre><span style='mso-spacerun:yes'>            </span>// implement the redo here</pre><pre><span style='mso-spacerun:yes'>            </span>return <span
class=SpellE>Status.OK_STATUS</span>;</pre><pre><span style='mso-spacerun:yes'>        </span>}</pre><pre><span style='mso-spacerun:yes'>    </span>}</pre><pre><o:p>&nbsp;</o:p></pre><pre><span
style='font-family:Arial'>If an <span class=SpellE>IHandler</span> is provided for a command instead of using actions, the execute method of the handler is mapped similarly to the run method in an action:<o:p></o:p></span></pre><pre><span
style='font-family:Arial'><o:p>&nbsp;</o:p></span></pre><pre><span style='mso-spacerun:yes'>        </span>public Object execute(Map <span
class=SpellE>params</span>) throws <span class=SpellE>ExecutionException</span> {</pre><pre><span style='mso-spacerun:yes'>        </span>try {</pre><pre><span
style='mso-tab-count:1'>        </span><span style='mso-spacerun:yes'>    </span><span
class=SpellE>IEditorPart</span> <span class=SpellE>activeEditor</span> = <span
class=SpellE>params.get</span>(&quot;ACTIVE_EDITOR&quot;);</pre><pre><span
style='mso-tab-count:1'>        </span><span style='mso-spacerun:yes'>    </span>Shell <span
class=SpellE>shell</span> = <span class=SpellE>params.get</span>(&quot;SHELL&quot;);</pre><pre><span
style='mso-tab-count:1'>        </span><span style='mso-spacerun:yes'>    </span>String label = <span
class=SpellE>params.get</span>(&quot;NAME&quot;);</pre><pre><span
style='mso-tab-count:1'>        </span><span style='mso-spacerun:yes'>    </span>String <span
class=SpellE>editorName</span> = <span class=SpellE>MessageUtil.getString</span>(&quot;<span
class=SpellE>Empty_Editor_Name</span>&quot;); </pre><pre><span style='mso-spacerun:yes'>            </span>if (<span
class=SpellE>activeEditor</span> != null)</pre><pre><span style='mso-spacerun:yes'>                </span><span
class=SpellE>editorName</span> = <span class=SpellE>activeEditor.getTitle</span>();</pre><pre><span style='mso-spacerun:yes'>            </span>// create the operation</pre><pre><span style='mso-spacerun:yes'>            </span><span
class=SpellE>IUndoableOperation</span> operation =new <span class=SpellE><span
class=GramE>EditorOperation</span></span><span class=GramE>(</span>label, shell, <span
class=SpellE>editorName</span>);</pre><pre><o:p>&nbsp;</o:p></pre><pre><span style='mso-spacerun:yes'>            </span>// execute (and add to the history)</pre><pre><span style='mso-spacerun:yes'>            </span><span
class=SpellE><span class=GramE>history.execute</span></span><span class=GramE>(</span>operation, null, null);</pre><pre><span style='mso-spacerun:yes'>        </span>} catch (Exception e) {</pre><pre><span style='mso-spacerun:yes'>            </span>throw new <span
class=SpellE>ExecutionException</span>(</pre><pre><span style='mso-spacerun:yes'>                    </span>&quot;While executing the operation, an exception occurred&quot;, e); </pre><pre><span style='mso-spacerun:yes'>        </span>}</pre><pre><span style='mso-spacerun:yes'>        </span>return null;</pre><pre><span style='mso-spacerun:yes'>    </span>}</pre><pre><span
style='font-family:Arial'><o:p>&nbsp;</o:p></span></pre>

<p class=MsoNormal><span class=GramE><span style='font-size:10.0pt;font-family:
Arial'>When an action launches a wizard.</span></span><span style='font-size:
10.0pt;font-family:Arial'> <span class=GramE>then</span> the operation is
typically created as part of processing the “Finish” button in the wizard.<span
style='mso-spacerun:yes'>  </span>Some restructuring may be required.<span
style='mso-spacerun:yes'>  </span>For example, wizards are often implemented in
hierarchies and make use of convenience methods in the wizard hierarchy.<span
style='mso-spacerun:yes'>  </span>Some of these methods may have to move to a
corresponding hierarchy of operations. <o:p></o:p></span></p>

<h3>Refactoring example:<span style='mso-spacerun:yes'>  </span>mapping
existing protocol to <span class=SpellE>IUndoableOperation</span></h3>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>In the
current SDK implementation, <span class=SpellE>org.eclipse.ltk.core.refactoring</span>
provides an undo framework for undoing refactoring operations.<span
style='mso-spacerun:yes'>  </span>This framework is based on the notion of
“Change” objects.<span style='mso-spacerun:yes'>  </span>Change objects that
can be undone are responsible for returning the undo version of a change when
they are executed.<span style='mso-spacerun:yes'>  </span>An undo stack is
maintained by an internal undo manager.<span style='mso-spacerun:yes'> 
</span>This undo manager invalidates the history whenever an unknown workspace
change occurs.<span style='mso-spacerun:yes'>  </span>Undo-aware objects send
signals to the undo manager as they perform operations, so that the undo
manager will not invalidate the history.<o:p></o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>A prototype
integrated the refactoring change framework with the operations framework as
follows:<o:p></o:p></span></p>

<p class=MsoNormal style='margin-left:39.0pt;text-indent:-.25in;mso-list:l5 level1 lfo16;
tab-stops:list 39.0pt'><![if !supportLists]><span style='font-size:10.0pt;
font-family:Arial;mso-fareast-font-family:Arial'><span style='mso-list:Ignore'>1.<span
style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]><span
style='font-size:10.0pt;font-family:Arial'>The change objects are <span
class=SpellE>wrappered</span> with a class that implements <span class=SpellE>IUndoableOperation</span>
and maps the operation protocol to the Change protocol.<o:p></o:p></span></p>

<p class=MsoNormal style='margin-left:39.0pt;text-indent:-.25in;mso-list:l5 level1 lfo16;
tab-stops:list 39.0pt'><![if !supportLists]><span style='font-size:10.0pt;
font-family:Arial;mso-fareast-font-family:Arial'><span style='mso-list:Ignore'>2.<span
style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]><span
style='font-size:10.0pt;font-family:Arial'>The refactoring undo manager is
replaced with an alternate implementation that uses the operations history to
maintain the undo and redo history.<o:p></o:p></span></p>

<p class=MsoNormal style='margin-left:39.0pt;text-indent:-.25in;mso-list:l5 level1 lfo16;
tab-stops:list 39.0pt'><![if !supportLists]><span style='font-size:10.0pt;
font-family:Arial;mso-fareast-font-family:Arial'><span style='mso-list:Ignore'>3.<span
style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]><span
style='font-size:10.0pt;font-family:Arial'>The workspace listener and
validation strategy used in the Change framework is maintained, since the
timing of the notifications was critical.<span style='mso-spacerun:yes'> 
</span>Additional integration work could be done to use the operations history
listeners for the same purpose, or to change the validation strategy as more
workspace operations are supported outside of refactoring.<o:p></o:p></span></p>

<p class=MsoNormal style='margin-left:39.0pt;text-indent:-.25in;mso-list:l5 level1 lfo16;
tab-stops:list 39.0pt'><![if !supportLists]><span style='font-size:10.0pt;
font-family:Arial;mso-fareast-font-family:Arial'><span style='mso-list:Ignore'>4.<span
style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]><span
style='font-size:10.0pt;font-family:Arial'>When a refactoring change is
executed, an operation is “opened” in the operations history.<span
style='mso-spacerun:yes'>  </span>Subsequent operations added to the history
are considered part of the open operation, and their contexts are assigned to
the original operation.<span style='mso-spacerun:yes'>  </span>When the
refactoring change is finished, the operation is closed.<span
style='mso-spacerun:yes'>  </span><o:p></o:p></span></p>

<p class=MsoNormal style='margin-left:39.0pt;text-indent:-.25in;mso-list:l5 level1 lfo16;
tab-stops:list 39.0pt'><![if !supportLists]><span style='font-size:10.0pt;
font-family:Arial;mso-fareast-font-family:Arial'><span style='mso-list:Ignore'>5.<span
style='font:7.0pt "Times New Roman"'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span></span><![endif]><span
style='font-size:10.0pt;font-family:Arial'>Refactoring operations could be
undone and redone from any view or editor that installed the undo and redo
handlers on the workspace context.<o:p></o:p></span></p>

<h3>Text editor example:<span style='mso-spacerun:yes'>  </span>implementing <span
class=SpellE>IUndoableOperation</span> in preexisting commands</h3>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>The <span
class=SpellE>JFace</span> text framework supports undo and redo of text editing
operations.<span style='mso-spacerun:yes'>  </span>This implementation relies
on private undo stacks that are maintained by each editor.<span
style='mso-spacerun:yes'>  </span>The <span class=SpellE>JFace</span> <span
class=SpellE>IUndoManager</span> listens to text changes coming from the
underlying widget, and builds a <span class=SpellE>TextCommand</span> for each
undoable edit.<span style='mso-spacerun:yes'>  </span><o:p></o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'><o:p>&nbsp;</o:p></span></p>

<p class=MsoNormal><span style='font-size:10.0pt;font-family:Arial'>A prototype
integrated the text undo in <span class=SpellE>JFace</span> with the operations
framework as follows:<o:p></o:p></span></p>

<ol style='margin-top:0in' start=1 type=1>
 <li class=MsoNormal style='mso-list:l8 level1 lfo19;tab-stops:list .5in'><span
     style='font-size:10.0pt;font-family:Arial'>The existing <span
     class=SpellE>TextCommand</span> was altered to implement the <span
     class=SpellE>IUndoableOperation</span> interface.<o:p></o:p></span></li>
 <li class=MsoNormal style='mso-list:l8 level1 lfo19;tab-stops:list .5in'><span
     style='font-size:10.0pt;font-family:Arial'>Specialized contexts (one
     instance for each text editor) are assigned to the operations.<o:p></o:p></span></li>
 <li class=MsoNormal style='mso-list:l8 level1 lfo19;tab-stops:list .5in'><span
     style='font-size:10.0pt;font-family:Arial'>The existing <span
     class=SpellE>UndoManager</span> was replaced with an alternate
     implementation that added text commands to the operations history instead
     of a local stack, and used the operation history protocol when handling
     undo and redo commands.<o:p></o:p></span></li>
</ol>

<p class=MsoNormal style='text-align:justify'><span style='font-size:10.0pt;
font-family:Arial'><o:p>&nbsp;</o:p></span></p>

</div>

</body>

</html>