Browse Source

Helios: Handle unsaved change

Nicolas Petton 11 years ago
parent
commit
c710be8619
3 changed files with 402 additions and 222 deletions
  1. 137 64
      js/Helios-Browser.deploy.js
  2. 167 89
      js/Helios-Browser.js
  3. 98 69
      st/Helios-Browser.st

+ 137 - 64
js/Helios-Browser.deploy.js

@@ -1,18 +1,5 @@
 smalltalk.addPackage('Helios-Browser');
-smalltalk.addClass('HLBrowser', smalltalk.HLWidget, ['model', 'packagesListWidget', 'classesListWidget', 'protocolsListWidget', 'methodsListWidget', 'sourceWidget'], 'Helios-Browser');
-smalltalk.addMethod(
-smalltalk.method({
-selector: "announcer",
-fn: function (){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=_st(_st(self)._model())._announcer();
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"announcer",{},smalltalk.HLBrowser)})},
-messageSends: ["announcer", "model"]}),
-smalltalk.HLBrowser);
-
+smalltalk.addClass('HLBrowser', smalltalk.HLWidget, ['model', 'packagesListWidget', 'classesListWidget', 'protocolsListWidget', 'methodsListWidget', 'sourceWidget', 'bottomDiv'], 'Helios-Browser');
 smalltalk.addMethod(
 smalltalk.method({
 selector: "canHaveFocus",
@@ -274,6 +261,20 @@ smalltalk.HLBrowser.klass);
 
 
 smalltalk.addClass('HLBrowserListWidget', smalltalk.HLNavigationListWidget, ['model'], 'Helios-Browser');
+smalltalk.addMethod(
+smalltalk.method({
+selector: "activateListItem:",
+fn: function (anItem){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(_st(self)._model())._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
+return smalltalk.HLNavigationListWidget.fn.prototype._activateListItem_.apply(_st(self), [anItem]);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
+return self}, function($ctx1) {$ctx1.fill(self,"activateListItem:",{anItem:anItem},smalltalk.HLBrowserListWidget)})},
+messageSends: ["withChangesDo:", "activateListItem:", "model"]}),
+smalltalk.HLBrowserListWidget);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "commandCategory",
@@ -654,7 +655,10 @@ fn: function (aClass){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1,$2;
-$1=_st(_st(aClass)._package()).__eq(_st(_st(self)._model())._selectedPackage());
+$1=_st(_st(_st(aClass)._package()).__eq(_st(_st(self)._model())._selectedPackage()))._or_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(_st(self)._items())._includes_(aClass);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 if(! smalltalk.assert($1)){
 $2=self;
 return $2;
@@ -662,7 +666,7 @@ return $2;
 _st(self)._setItemsForSelectedPackage();
 _st(self)._refresh();
 return self}, function($ctx1) {$ctx1.fill(self,"onClassAdded:",{aClass:aClass},smalltalk.HLClassesListWidget)})},
-messageSends: ["ifFalse:", "=", "selectedPackage", "model", "package", "setItemsForSelectedPackage", "refresh"]}),
+messageSends: ["ifFalse:", "or:", "includes:", "items", "=", "selectedPackage", "model", "package", "setItemsForSelectedPackage", "refresh"]}),
 smalltalk.HLClassesListWidget);
 
 smalltalk.addMethod(
@@ -806,7 +810,6 @@ return smalltalk.withContext(function($ctx1) {
 var $1,$3,$4,$5,$6,$7,$8,$9,$10,$11,$2;
 $1=_st(html)._div();
 _st($1)._class_("btn-group");
-_st($1)._at_put_("data-toggle","buttons-radio");
 $2=_st($1)._with_((function(){
 return smalltalk.withContext(function($ctx2) {
 $3=_st(html)._button();
@@ -856,7 +859,7 @@ return _st(self)._showComment_(true);
 return $11;
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"renderButtonsOn:",{html:html},smalltalk.HLClassesListWidget)})},
-messageSends: ["class:", "div", "at:put:", "with:", "streamContents:", "nextPutAll:", "ifTrue:", "showInstance", "button", "onClick:", "showInstance:", "showClass", "showComment", "showComment:"]}),
+messageSends: ["class:", "div", "with:", "streamContents:", "nextPutAll:", "ifTrue:", "showInstance", "button", "onClick:", "showInstance:", "showClass", "showComment", "showComment:"]}),
 smalltalk.HLClassesListWidget);
 
 smalltalk.addMethod(
@@ -2247,9 +2250,12 @@ selector: "copyClassTo:",
 fn: function (aClassName){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-_st(_st(self)._environment())._copyClass_to_(_st(_st(self)._selectedClass())._theNonMetaClass(),aClassName);
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(_st(self)._environment())._copyClass_to_(_st(_st(self)._selectedClass())._theNonMetaClass(),aClassName);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"copyClassTo:",{aClassName:aClassName},smalltalk.HLBrowserModel)})},
-messageSends: ["copyClass:to:", "theNonMetaClass", "selectedClass", "environment"]}),
+messageSends: ["withChangesDo:", "copyClass:to:", "theNonMetaClass", "selectedClass", "environment"]}),
 smalltalk.HLBrowserModel);
 
 smalltalk.addMethod(
@@ -2376,9 +2382,12 @@ selector: "moveClassToPackage:",
 fn: function (aPackageName){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-_st(_st(self)._environment())._moveClass_toPackage_(_st(_st(self)._selectedClass())._theNonMetaClass(),aPackageName);
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(_st(self)._environment())._moveClass_toPackage_(_st(_st(self)._selectedClass())._theNonMetaClass(),aPackageName);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"moveClassToPackage:",{aPackageName:aPackageName},smalltalk.HLBrowserModel)})},
-messageSends: ["moveClass:toPackage:", "theNonMetaClass", "selectedClass", "environment"]}),
+messageSends: ["withChangesDo:", "moveClass:toPackage:", "theNonMetaClass", "selectedClass", "environment"]}),
 smalltalk.HLBrowserModel);
 
 smalltalk.addMethod(
@@ -2387,9 +2396,12 @@ selector: "moveMethodToClass:",
 fn: function (aClassName){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-_st(_st(self)._environment())._moveMethod_toClass_(_st(self)._selectedMethod(),aClassName);
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(_st(self)._environment())._moveMethod_toClass_(_st(self)._selectedMethod(),aClassName);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"moveMethodToClass:",{aClassName:aClassName},smalltalk.HLBrowserModel)})},
-messageSends: ["moveMethod:toClass:", "selectedMethod", "environment"]}),
+messageSends: ["withChangesDo:", "moveMethod:toClass:", "selectedMethod", "environment"]}),
 smalltalk.HLBrowserModel);
 
 smalltalk.addMethod(
@@ -2398,9 +2410,12 @@ selector: "moveMethodToProtocol:",
 fn: function (aProtocol){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-_st(_st(self)._environment())._moveMethod_toProtocol_(_st(self)._selectedMethod(),aProtocol);
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(_st(self)._environment())._moveMethod_toProtocol_(_st(self)._selectedMethod(),aProtocol);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"moveMethodToProtocol:",{aProtocol:aProtocol},smalltalk.HLBrowserModel)})},
-messageSends: ["moveMethod:toProtocol:", "selectedMethod", "environment"]}),
+messageSends: ["withChangesDo:", "moveMethod:toProtocol:", "selectedMethod", "environment"]}),
 smalltalk.HLBrowserModel);
 
 smalltalk.addMethod(
@@ -2410,11 +2425,15 @@ fn: function (aString){
 var self=this;
 var class_;
 return smalltalk.withContext(function($ctx1) { 
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
 class_=_st(_st(self)._environment())._classNamed_(aString);
+class_;
 _st(self)._selectedPackage_(_st(class_)._package());
-_st(self)._selectedClass_(class_);
+return _st(self)._selectedClass_(class_);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"openClassNamed:",{aString:aString,class_:class_},smalltalk.HLBrowserModel)})},
-messageSends: ["classNamed:", "environment", "selectedPackage:", "package", "selectedClass:"]}),
+messageSends: ["withChangesDo:", "classNamed:", "environment", "selectedPackage:", "package", "selectedClass:"]}),
 smalltalk.HLBrowserModel);
 
 smalltalk.addMethod(
@@ -2437,12 +2456,15 @@ fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
 $1=_st(_st(self)._manager())._confirm_(_st("Do you REALLY want to remove class ").__comma(_st(_st(self)._selectedClass())._name()));
 if(smalltalk.assert($1)){
-_st(_st(self)._environment())._removeClass_(_st(self)._selectedClass());
+return _st(_st(self)._environment())._removeClass_(_st(self)._selectedClass());
 };
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"removeClass",{},smalltalk.HLBrowserModel)})},
-messageSends: ["ifTrue:", "removeClass:", "selectedClass", "environment", "confirm:", ",", "name", "manager"]}),
+messageSends: ["withChangesDo:", "ifTrue:", "removeClass:", "selectedClass", "environment", "confirm:", ",", "name", "manager"]}),
 smalltalk.HLBrowserModel);
 
 smalltalk.addMethod(
@@ -2452,12 +2474,15 @@ fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
 $1=_st(_st(self)._manager())._confirm_(_st(_st(_st("Do you REALLY want to remove method ").__comma(_st(_st(_st(self)._selectedMethod())._methodClass())._name())).__comma(" >> #")).__comma(_st(_st(self)._selectedMethod())._selector()));
 if(smalltalk.assert($1)){
-_st(_st(self)._environment())._removeMethod_(_st(self)._selectedMethod());
+return _st(_st(self)._environment())._removeMethod_(_st(self)._selectedMethod());
 };
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"removeMethod",{},smalltalk.HLBrowserModel)})},
-messageSends: ["ifTrue:", "removeMethod:", "selectedMethod", "environment", "confirm:", ",", "selector", "name", "methodClass", "manager"]}),
+messageSends: ["withChangesDo:", "ifTrue:", "removeMethod:", "selectedMethod", "environment", "confirm:", ",", "selector", "name", "methodClass", "manager"]}),
 smalltalk.HLBrowserModel);
 
 smalltalk.addMethod(
@@ -2467,12 +2492,15 @@ fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
 $1=_st(_st(self)._manager())._confirm_(_st("Do you REALLY want to remove protocol ").__comma(_st(self)._selectedProtocol()));
 if(smalltalk.assert($1)){
-_st(_st(self)._environment())._removeProtocol_from_(_st(self)._selectedProtocol(),_st(self)._selectedClass());
+return _st(_st(self)._environment())._removeProtocol_from_(_st(self)._selectedProtocol(),_st(self)._selectedClass());
 };
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"removeProtocol",{},smalltalk.HLBrowserModel)})},
-messageSends: ["ifTrue:", "removeProtocol:from:", "selectedProtocol", "selectedClass", "environment", "confirm:", ",", "manager"]}),
+messageSends: ["withChangesDo:", "ifTrue:", "removeProtocol:from:", "selectedProtocol", "selectedClass", "environment", "confirm:", ",", "manager"]}),
 smalltalk.HLBrowserModel);
 
 smalltalk.addMethod(
@@ -2481,9 +2509,12 @@ selector: "renameClassTo:",
 fn: function (aClassName){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-_st(_st(self)._environment())._renameClass_to_(_st(_st(self)._selectedClass())._theNonMetaClass(),aClassName);
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(_st(self)._environment())._renameClass_to_(_st(_st(self)._selectedClass())._theNonMetaClass(),aClassName);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"renameClassTo:",{aClassName:aClassName},smalltalk.HLBrowserModel)})},
-messageSends: ["renameClass:to:", "theNonMetaClass", "selectedClass", "environment"]}),
+messageSends: ["withChangesDo:", "renameClass:to:", "theNonMetaClass", "selectedClass", "environment"]}),
 smalltalk.HLBrowserModel);
 
 smalltalk.addMethod(
@@ -2492,9 +2523,12 @@ selector: "renameProtocolTo:",
 fn: function (aString){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-_st(_st(self)._environment())._renameProtocol_to_in_(_st(self)._selectedProtocol(),aString,_st(self)._selectedClass());
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(_st(self)._environment())._renameProtocol_to_in_(_st(self)._selectedProtocol(),aString,_st(self)._selectedClass());
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"renameProtocolTo:",{aString:aString},smalltalk.HLBrowserModel)})},
-messageSends: ["renameProtocol:to:in:", "selectedProtocol", "selectedClass", "environment"]}),
+messageSends: ["withChangesDo:", "renameProtocol:to:in:", "selectedProtocol", "selectedClass", "environment"]}),
 smalltalk.HLBrowserModel);
 
 smalltalk.addMethod(
@@ -2502,8 +2536,10 @@ smalltalk.method({
 selector: "save:",
 fn: function (aString){
 var self=this;
+function $HLSourceCodeSaved(){return smalltalk.HLSourceCodeSaved||(typeof HLSourceCodeSaved=="undefined"?nil:HLSourceCodeSaved)}
 return smalltalk.withContext(function($ctx1) { 
 var $1;
+_st(_st(self)._announcer())._announce_(_st($HLSourceCodeSaved())._new());
 $1=_st(self)._shouldCompileClassDefinition_(aString);
 if(smalltalk.assert($1)){
 _st(self)._compileClassDefinition_(aString);
@@ -2511,7 +2547,7 @@ _st(self)._compileClassDefinition_(aString);
 _st(self)._compileMethod_(aString);
 };
 return self}, function($ctx1) {$ctx1.fill(self,"save:",{aString:aString},smalltalk.HLBrowserModel)})},
-messageSends: ["ifTrue:ifFalse:", "compileClassDefinition:", "compileMethod:", "shouldCompileClassDefinition:"]}),
+messageSends: ["announce:", "new", "announcer", "ifTrue:ifFalse:", "compileClassDefinition:", "compileMethod:", "shouldCompileClassDefinition:"]}),
 smalltalk.HLBrowserModel);
 
 smalltalk.addMethod(
@@ -2547,15 +2583,17 @@ var self=this;
 function $HLClassSelected(){return smalltalk.HLClassSelected||(typeof HLClassSelected=="undefined"?nil:HLClassSelected)}
 return smalltalk.withContext(function($ctx1) { 
 var $1,$2,$3,$4,$5;
-$1=_st(self["@selectedClass"]).__eq(aClass);
-if(smalltalk.assert($1)){
-$2=aClass;
-if(($receiver = $2) == nil || $receiver == undefined){
-$3=self;
-return $3;
+$1=aClass;
+if(($receiver = $1) == nil || $receiver == undefined){
+$2=self;
+return $2;
 } else {
-$2;
+$1;
 };
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
+$3=_st(self["@selectedClass"]).__eq(aClass);
+if(smalltalk.assert($3)){
 _st(self)._selectedProtocol_(nil);
 };
 $4=aClass;
@@ -2573,9 +2611,10 @@ self["@selectedClass"];
 };
 };
 _st(self)._selectedProtocol_(nil);
-_st(_st(self)._announcer())._announce_(_st($HLClassSelected())._on_(_st(self)._selectedClass()));
+return _st(_st(self)._announcer())._announce_(_st($HLClassSelected())._on_(_st(self)._selectedClass()));
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"selectedClass:",{aClass:aClass},smalltalk.HLBrowserModel)})},
-messageSends: ["ifTrue:", "ifNil:", "selectedProtocol:", "=", "ifNil:ifNotNil:", "ifTrue:ifFalse:", "theNonMetaClass", "theMetaClass", "showInstance", "announce:", "on:", "selectedClass", "announcer"]}),
+messageSends: ["ifNil:", "withChangesDo:", "ifTrue:", "selectedProtocol:", "=", "ifNil:ifNotNil:", "ifTrue:ifFalse:", "theNonMetaClass", "theMetaClass", "showInstance", "announce:", "on:", "selectedClass", "announcer"]}),
 smalltalk.HLBrowserModel);
 
 smalltalk.addMethod(
@@ -2606,28 +2645,26 @@ fn: function (aCompiledMethod){
 var self=this;
 function $HLMethodSelected(){return smalltalk.HLMethodSelected||(typeof HLMethodSelected=="undefined"?nil:HLMethodSelected)}
 return smalltalk.withContext(function($ctx1) { 
-var $1,$2,$3,$4,$5;
+var $1,$2,$3;
 $1=_st(self["@selectedSelector"]).__eq(aCompiledMethod);
 if(smalltalk.assert($1)){
 $2=self;
 return $2;
 };
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
 $3=aCompiledMethod;
 if(($receiver = $3) == nil || $receiver == undefined){
 self["@selectedSelector"]=nil;
 self["@selectedSelector"];
 } else {
-$4=_st(self["@selectedSelector"]).__eq(_st(aCompiledMethod)._selector());
-if(smalltalk.assert($4)){
-$5=self;
-return $5;
-};
 self["@selectedSelector"]=_st(aCompiledMethod)._selector();
 self["@selectedSelector"];
 };
-_st(_st(self)._announcer())._announce_(_st($HLMethodSelected())._on_(aCompiledMethod));
+return _st(_st(self)._announcer())._announce_(_st($HLMethodSelected())._on_(aCompiledMethod));
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"selectedMethod:",{aCompiledMethod:aCompiledMethod},smalltalk.HLBrowserModel)})},
-messageSends: ["ifTrue:", "=", "ifNil:ifNotNil:", "selector", "announce:", "on:", "announcer"]}),
+messageSends: ["ifTrue:", "=", "withChangesDo:", "ifNil:ifNotNil:", "selector", "announce:", "on:", "announcer"]}),
 smalltalk.HLBrowserModel);
 
 smalltalk.addMethod(
@@ -2656,11 +2693,15 @@ if(smalltalk.assert($1)){
 $2=self;
 return $2;
 };
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
 self["@selectedPackage"]=aPackage;
+self["@selectedPackage"];
 _st(self)._selectedClass_(nil);
-_st(_st(self)._announcer())._announce_(_st($HLPackageSelected())._on_(aPackage));
+return _st(_st(self)._announcer())._announce_(_st($HLPackageSelected())._on_(aPackage));
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"selectedPackage:",{aPackage:aPackage},smalltalk.HLBrowserModel)})},
-messageSends: ["ifTrue:", "=", "selectedClass:", "announce:", "on:", "announcer"]}),
+messageSends: ["ifTrue:", "=", "withChangesDo:", "selectedClass:", "announce:", "on:", "announcer"]}),
 smalltalk.HLBrowserModel);
 
 smalltalk.addMethod(
@@ -2689,11 +2730,15 @@ if(smalltalk.assert($1)){
 $2=self;
 return $2;
 };
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
 self["@selectedProtocol"]=aString;
+self["@selectedProtocol"];
 _st(self)._selectedMethod_(nil);
-_st(_st(self)._announcer())._announce_(_st($HLProtocolSelected())._on_(aString));
+return _st(_st(self)._announcer())._announce_(_st($HLProtocolSelected())._on_(aString));
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"selectedProtocol:",{aString:aString},smalltalk.HLBrowserModel)})},
-messageSends: ["ifTrue:", "=", "selectedMethod:", "announce:", "on:", "announcer"]}),
+messageSends: ["ifTrue:", "=", "withChangesDo:", "selectedMethod:", "announce:", "on:", "announcer"]}),
 smalltalk.HLBrowserModel);
 
 smalltalk.addMethod(
@@ -2737,10 +2782,14 @@ fn: function (aBoolean){
 var self=this;
 function $HLShowCommentToggled(){return smalltalk.HLShowCommentToggled||(typeof HLShowCommentToggled=="undefined"?nil:HLShowCommentToggled)}
 return smalltalk.withContext(function($ctx1) { 
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
 self["@showComment"]=aBoolean;
-_st(_st(self)._announcer())._announce_(_st($HLShowCommentToggled())._new());
+self["@showComment"];
+return _st(_st(self)._announcer())._announce_(_st($HLShowCommentToggled())._new());
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"showComment:",{aBoolean:aBoolean},smalltalk.HLBrowserModel)})},
-messageSends: ["announce:", "new", "announcer"]}),
+messageSends: ["withChangesDo:", "announce:", "new", "announcer"]}),
 smalltalk.HLBrowserModel);
 
 smalltalk.addMethod(
@@ -2769,8 +2818,12 @@ var self=this;
 function $HLShowInstanceToggled(){return smalltalk.HLShowInstanceToggled||(typeof HLShowInstanceToggled=="undefined"?nil:HLShowInstanceToggled)}
 return smalltalk.withContext(function($ctx1) { 
 var $1,$2,$4,$3;
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
 self["@showInstance"]=aBoolean;
+self["@showInstance"];
 self["@showComment"]=false;
+self["@showComment"];
 $1=_st(self)._selectedClass();
 if(($receiver = $1) == nil || $receiver == undefined){
 $1;
@@ -2784,9 +2837,10 @@ $3=_st(_st(self)._selectedClass())._theMetaClass();
 };
 _st($2)._selectedClass_($3);
 };
-_st(_st(self)._announcer())._announce_(_st($HLShowInstanceToggled())._new());
+return _st(_st(self)._announcer())._announce_(_st($HLShowInstanceToggled())._new());
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"showInstance:",{aBoolean:aBoolean},smalltalk.HLBrowserModel)})},
-messageSends: ["ifNotNil:", "selectedClass:", "ifTrue:ifFalse:", "theNonMetaClass", "selectedClass", "theMetaClass", "announce:", "new", "announcer"]}),
+messageSends: ["withChangesDo:", "ifNotNil:", "selectedClass:", "ifTrue:ifFalse:", "theNonMetaClass", "selectedClass", "theMetaClass", "announce:", "new", "announcer"]}),
 smalltalk.HLBrowserModel);
 
 smalltalk.addMethod(
@@ -2800,6 +2854,25 @@ return "as yet unclassified";
 messageSends: []}),
 smalltalk.HLBrowserModel);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "withChangesDo:",
+fn: function (aBlock){
+var self=this;
+function $HLChangeForbidden(){return smalltalk.HLChangeForbidden||(typeof HLChangeForbidden=="undefined"?nil:HLChangeForbidden)}
+function $HLAboutToChange(){return smalltalk.HLAboutToChange||(typeof HLAboutToChange=="undefined"?nil:HLAboutToChange)}
+return smalltalk.withContext(function($ctx1) { 
+_st((function(){
+return smalltalk.withContext(function($ctx2) {
+_st(_st(self)._announcer())._announce_(_st($HLAboutToChange())._new());
+return _st(aBlock)._value();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}))._on_do_($HLChangeForbidden(),(function(ex){
+return smalltalk.withContext(function($ctx2) {
+}, function($ctx2) {$ctx2.fillBlock({ex:ex},$ctx1)})}));
+return self}, function($ctx1) {$ctx1.fill(self,"withChangesDo:",{aBlock:aBlock},smalltalk.HLBrowserModel)})},
+messageSends: ["on:do:", "announce:", "new", "announcer", "value"]}),
+smalltalk.HLBrowserModel);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "withCompileErrorHandling:",

+ 167 - 89
js/Helios-Browser.js

@@ -1,23 +1,5 @@
 smalltalk.addPackage('Helios-Browser');
-smalltalk.addClass('HLBrowser', smalltalk.HLWidget, ['model', 'packagesListWidget', 'classesListWidget', 'protocolsListWidget', 'methodsListWidget', 'sourceWidget'], 'Helios-Browser');
-smalltalk.addMethod(
-smalltalk.method({
-selector: "announcer",
-category: 'accessing',
-fn: function (){
-var self=this;
-return smalltalk.withContext(function($ctx1) { 
-var $1;
-$1=_st(_st(self)._model())._announcer();
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"announcer",{},smalltalk.HLBrowser)})},
-args: [],
-source: "announcer\x0a\x09^ self model announcer",
-messageSends: ["announcer", "model"],
-referencedClasses: []
-}),
-smalltalk.HLBrowser);
-
+smalltalk.addClass('HLBrowser', smalltalk.HLWidget, ['model', 'packagesListWidget', 'classesListWidget', 'protocolsListWidget', 'methodsListWidget', 'sourceWidget', 'bottomDiv'], 'Helios-Browser');
 smalltalk.addMethod(
 smalltalk.method({
 selector: "canHaveFocus",
@@ -359,6 +341,25 @@ smalltalk.HLBrowser.klass);
 
 
 smalltalk.addClass('HLBrowserListWidget', smalltalk.HLNavigationListWidget, ['model'], 'Helios-Browser');
+smalltalk.addMethod(
+smalltalk.method({
+selector: "activateListItem:",
+category: 'actions',
+fn: function (anItem){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(_st(self)._model())._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
+return smalltalk.HLNavigationListWidget.fn.prototype._activateListItem_.apply(_st(self), [anItem]);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
+return self}, function($ctx1) {$ctx1.fill(self,"activateListItem:",{anItem:anItem},smalltalk.HLBrowserListWidget)})},
+args: ["anItem"],
+source: "activateListItem: anItem\x0a\x09self model withChangesDo: [ super activateListItem: anItem ]",
+messageSends: ["withChangesDo:", "activateListItem:", "model"],
+referencedClasses: []
+}),
+smalltalk.HLBrowserListWidget);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "commandCategory",
@@ -845,7 +846,10 @@ fn: function (aClass){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1,$2;
-$1=_st(_st(aClass)._package()).__eq(_st(_st(self)._model())._selectedPackage());
+$1=_st(_st(_st(aClass)._package()).__eq(_st(_st(self)._model())._selectedPackage()))._or_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(_st(self)._items())._includes_(aClass);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 if(! smalltalk.assert($1)){
 $2=self;
 return $2;
@@ -854,8 +858,8 @@ _st(self)._setItemsForSelectedPackage();
 _st(self)._refresh();
 return self}, function($ctx1) {$ctx1.fill(self,"onClassAdded:",{aClass:aClass},smalltalk.HLClassesListWidget)})},
 args: ["aClass"],
-source: "onClassAdded: aClass\x0a\x09aClass package = self model selectedPackage ifFalse: [ ^ self ].\x0a    \x0a    self setItemsForSelectedPackage.\x0a    self refresh",
-messageSends: ["ifFalse:", "=", "selectedPackage", "model", "package", "setItemsForSelectedPackage", "refresh"],
+source: "onClassAdded: aClass\x0a\x09(aClass package = self model selectedPackage or: [\x0a\x09\x09self items includes: aClass ]) ifFalse: [ ^ self ].\x0a    \x0a    self setItemsForSelectedPackage.\x0a    self refresh",
+messageSends: ["ifFalse:", "or:", "includes:", "items", "=", "selectedPackage", "model", "package", "setItemsForSelectedPackage", "refresh"],
 referencedClasses: []
 }),
 smalltalk.HLClassesListWidget);
@@ -1037,7 +1041,6 @@ return smalltalk.withContext(function($ctx1) {
 var $1,$3,$4,$5,$6,$7,$8,$9,$10,$11,$2;
 $1=_st(html)._div();
 _st($1)._class_("btn-group");
-_st($1)._at_put_("data-toggle","buttons-radio");
 $2=_st($1)._with_((function(){
 return smalltalk.withContext(function($ctx2) {
 $3=_st(html)._button();
@@ -1088,8 +1091,8 @@ return $11;
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"renderButtonsOn:",{html:html},smalltalk.HLClassesListWidget)})},
 args: ["html"],
-source: "renderButtonsOn: html\x0a\x09html div \x0a        class: 'btn-group';\x0a\x09\x09at: 'data-toggle' put: 'buttons-radio';\x0a\x09\x09with: [ \x0a           \x09html button \x0a                class: (String streamContents: [ :str |\x0a                \x09str nextPutAll: 'btn'.\x0a                    self showInstance ifTrue: [ \x0a                    \x09str nextPutAll: ' active' ] ]);\x0a  \x09\x09\x09\x09with: 'Instance';\x0a                onClick: [ self showInstance: true ].\x0a  \x09\x09\x09html button\x0a  \x09\x09\x09\x09class: (String streamContents: [ :str |\x0a                \x09str nextPutAll: 'btn'.\x0a                    self showClass ifTrue: [ \x0a                    \x09str nextPutAll: ' active' ] ]);\x0a  \x09\x09\x09\x09with: 'Class';\x0a\x09\x09\x09\x09onClick: [ self showInstance: false ].\x0a\x09\x09\x09html button\x0a  \x09\x09\x09\x09class: (String streamContents: [ :str |\x0a                \x09str nextPutAll: 'btn'.\x0a                    self showComment ifTrue: [ \x0a                    \x09str nextPutAll: ' active' ] ]);\x0a  \x09\x09\x09\x09with: 'Doc';\x0a\x09\x09\x09\x09onClick: [ self showComment: true ] ]",
-messageSends: ["class:", "div", "at:put:", "with:", "streamContents:", "nextPutAll:", "ifTrue:", "showInstance", "button", "onClick:", "showInstance:", "showClass", "showComment", "showComment:"],
+source: "renderButtonsOn: html\x0a\x09html div \x0a        class: 'btn-group';\x0a\x09\x09with: [ \x0a           \x09html button \x0a                class: (String streamContents: [ :str |\x0a                \x09str nextPutAll: 'btn'.\x0a                    self showInstance ifTrue: [ \x0a                    \x09str nextPutAll: ' active' ] ]);\x0a  \x09\x09\x09\x09with: 'Instance';\x0a                onClick: [ self showInstance: true ].\x0a  \x09\x09\x09html button\x0a  \x09\x09\x09\x09class: (String streamContents: [ :str |\x0a                \x09str nextPutAll: 'btn'.\x0a                    self showClass ifTrue: [ \x0a                    \x09str nextPutAll: ' active' ] ]);\x0a  \x09\x09\x09\x09with: 'Class';\x0a\x09\x09\x09\x09onClick: [ self showInstance: false ].\x0a\x09\x09\x09html button\x0a  \x09\x09\x09\x09class: (String streamContents: [ :str |\x0a                \x09str nextPutAll: 'btn'.\x0a                    self showComment ifTrue: [ \x0a                    \x09str nextPutAll: ' active' ] ]);\x0a  \x09\x09\x09\x09with: 'Doc';\x0a\x09\x09\x09\x09onClick: [ self showComment: true ] ]",
+messageSends: ["class:", "div", "with:", "streamContents:", "nextPutAll:", "ifTrue:", "showInstance", "button", "onClick:", "showInstance:", "showClass", "showComment", "showComment:"],
 referencedClasses: ["String"]
 }),
 smalltalk.HLClassesListWidget);
@@ -2878,11 +2881,14 @@ category: 'commands actions',
 fn: function (aClassName){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-_st(_st(self)._environment())._copyClass_to_(_st(_st(self)._selectedClass())._theNonMetaClass(),aClassName);
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(_st(self)._environment())._copyClass_to_(_st(_st(self)._selectedClass())._theNonMetaClass(),aClassName);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"copyClassTo:",{aClassName:aClassName},smalltalk.HLBrowserModel)})},
 args: ["aClassName"],
-source: "copyClassTo: aClassName\x0a\x09self environment \x0a\x09\x09copyClass: self selectedClass theNonMetaClass\x0a\x09\x09to: aClassName",
-messageSends: ["copyClass:to:", "theNonMetaClass", "selectedClass", "environment"],
+source: "copyClassTo: aClassName\x0a\x09self withChangesDo: [ \x0a\x09\x09self environment \x0a\x09\x09\x09copyClass: self selectedClass theNonMetaClass\x0a\x09\x09\x09to: aClassName ]",
+messageSends: ["withChangesDo:", "copyClass:to:", "theNonMetaClass", "selectedClass", "environment"],
 referencedClasses: []
 }),
 smalltalk.HLBrowserModel);
@@ -3052,11 +3058,14 @@ category: 'commands actions',
 fn: function (aPackageName){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-_st(_st(self)._environment())._moveClass_toPackage_(_st(_st(self)._selectedClass())._theNonMetaClass(),aPackageName);
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(_st(self)._environment())._moveClass_toPackage_(_st(_st(self)._selectedClass())._theNonMetaClass(),aPackageName);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"moveClassToPackage:",{aPackageName:aPackageName},smalltalk.HLBrowserModel)})},
 args: ["aPackageName"],
-source: "moveClassToPackage: aPackageName\x0a\x09self environment \x0a\x09\x09moveClass: self selectedClass theNonMetaClass\x0a\x09\x09toPackage: aPackageName",
-messageSends: ["moveClass:toPackage:", "theNonMetaClass", "selectedClass", "environment"],
+source: "moveClassToPackage: aPackageName\x0a\x09self withChangesDo: [\x0a\x09\x09self environment \x0a\x09\x09\x09moveClass: self selectedClass theNonMetaClass\x0a\x09\x09\x09toPackage: aPackageName ]",
+messageSends: ["withChangesDo:", "moveClass:toPackage:", "theNonMetaClass", "selectedClass", "environment"],
 referencedClasses: []
 }),
 smalltalk.HLBrowserModel);
@@ -3068,11 +3077,14 @@ category: 'commands actions',
 fn: function (aClassName){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-_st(_st(self)._environment())._moveMethod_toClass_(_st(self)._selectedMethod(),aClassName);
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(_st(self)._environment())._moveMethod_toClass_(_st(self)._selectedMethod(),aClassName);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"moveMethodToClass:",{aClassName:aClassName},smalltalk.HLBrowserModel)})},
 args: ["aClassName"],
-source: "moveMethodToClass: aClassName\x0a\x09self environment \x0a\x09\x09moveMethod: self selectedMethod \x0a\x09\x09toClass: aClassName",
-messageSends: ["moveMethod:toClass:", "selectedMethod", "environment"],
+source: "moveMethodToClass: aClassName\x0a\x09self withChangesDo: [\x0a\x09\x09self environment \x0a\x09\x09\x09moveMethod: self selectedMethod \x0a\x09\x09\x09toClass: aClassName ]",
+messageSends: ["withChangesDo:", "moveMethod:toClass:", "selectedMethod", "environment"],
 referencedClasses: []
 }),
 smalltalk.HLBrowserModel);
@@ -3084,11 +3096,14 @@ category: 'commands actions',
 fn: function (aProtocol){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-_st(_st(self)._environment())._moveMethod_toProtocol_(_st(self)._selectedMethod(),aProtocol);
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(_st(self)._environment())._moveMethod_toProtocol_(_st(self)._selectedMethod(),aProtocol);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"moveMethodToProtocol:",{aProtocol:aProtocol},smalltalk.HLBrowserModel)})},
 args: ["aProtocol"],
-source: "moveMethodToProtocol: aProtocol\x0a\x09self environment moveMethod: self selectedMethod toProtocol: aProtocol",
-messageSends: ["moveMethod:toProtocol:", "selectedMethod", "environment"],
+source: "moveMethodToProtocol: aProtocol\x0a\x09self withChangesDo: [\x0a\x09\x09self environment \x0a\x09\x09\x09moveMethod: self selectedMethod \x0a\x09\x09\x09toProtocol: aProtocol ]",
+messageSends: ["withChangesDo:", "moveMethod:toProtocol:", "selectedMethod", "environment"],
 referencedClasses: []
 }),
 smalltalk.HLBrowserModel);
@@ -3101,13 +3116,17 @@ fn: function (aString){
 var self=this;
 var class_;
 return smalltalk.withContext(function($ctx1) { 
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
 class_=_st(_st(self)._environment())._classNamed_(aString);
+class_;
 _st(self)._selectedPackage_(_st(class_)._package());
-_st(self)._selectedClass_(class_);
+return _st(self)._selectedClass_(class_);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"openClassNamed:",{aString:aString,class_:class_},smalltalk.HLBrowserModel)})},
 args: ["aString"],
-source: "openClassNamed: aString\x0a\x09| class |\x0a\x09\x0a\x09class := self environment classNamed: aString.\x0a\x09self selectedPackage: class package.\x0a\x09self selectedClass: class",
-messageSends: ["classNamed:", "environment", "selectedPackage:", "package", "selectedClass:"],
+source: "openClassNamed: aString\x0a\x09| class |\x0a\x09\x0a\x09self withChangesDo: [\x0a\x09\x09class := self environment classNamed: aString.\x0a\x09\x09self selectedPackage: class package.\x0a\x09\x09self selectedClass: class ]",
+messageSends: ["withChangesDo:", "classNamed:", "environment", "selectedPackage:", "package", "selectedClass:"],
 referencedClasses: []
 }),
 smalltalk.HLBrowserModel);
@@ -3138,14 +3157,17 @@ fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
 $1=_st(_st(self)._manager())._confirm_(_st("Do you REALLY want to remove class ").__comma(_st(_st(self)._selectedClass())._name()));
 if(smalltalk.assert($1)){
-_st(_st(self)._environment())._removeClass_(_st(self)._selectedClass());
+return _st(_st(self)._environment())._removeClass_(_st(self)._selectedClass());
 };
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"removeClass",{},smalltalk.HLBrowserModel)})},
 args: [],
-source: "removeClass\x0a\x09(self manager confirm: 'Do you REALLY want to remove class ', self selectedClass name)\x0a\x09\x09ifTrue: [ self environment removeClass: self selectedClass ]",
-messageSends: ["ifTrue:", "removeClass:", "selectedClass", "environment", "confirm:", ",", "name", "manager"],
+source: "removeClass\x0a\x09self withChangesDo: [\x0a\x09\x09(self manager confirm: 'Do you REALLY want to remove class ', self selectedClass name)\x0a\x09\x09\x09ifTrue: [ self environment removeClass: self selectedClass ] ]",
+messageSends: ["withChangesDo:", "ifTrue:", "removeClass:", "selectedClass", "environment", "confirm:", ",", "name", "manager"],
 referencedClasses: []
 }),
 smalltalk.HLBrowserModel);
@@ -3158,14 +3180,17 @@ fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
 $1=_st(_st(self)._manager())._confirm_(_st(_st(_st("Do you REALLY want to remove method ").__comma(_st(_st(_st(self)._selectedMethod())._methodClass())._name())).__comma(" >> #")).__comma(_st(_st(self)._selectedMethod())._selector()));
 if(smalltalk.assert($1)){
-_st(_st(self)._environment())._removeMethod_(_st(self)._selectedMethod());
+return _st(_st(self)._environment())._removeMethod_(_st(self)._selectedMethod());
 };
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"removeMethod",{},smalltalk.HLBrowserModel)})},
 args: [],
-source: "removeMethod\x0a\x09(self manager confirm: 'Do you REALLY want to remove method ', self selectedMethod methodClass name,' >> #', self selectedMethod selector)\x0a\x09\x09ifTrue: [ self environment removeMethod: self selectedMethod ]",
-messageSends: ["ifTrue:", "removeMethod:", "selectedMethod", "environment", "confirm:", ",", "selector", "name", "methodClass", "manager"],
+source: "removeMethod\x0a\x09self withChangesDo: [\x0a\x09\x09(self manager confirm: 'Do you REALLY want to remove method ', self selectedMethod methodClass name,' >> #', self selectedMethod selector)\x0a\x09\x09\x09ifTrue: [ self environment removeMethod: self selectedMethod ] ]",
+messageSends: ["withChangesDo:", "ifTrue:", "removeMethod:", "selectedMethod", "environment", "confirm:", ",", "selector", "name", "methodClass", "manager"],
 referencedClasses: []
 }),
 smalltalk.HLBrowserModel);
@@ -3178,14 +3203,17 @@ fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
 $1=_st(_st(self)._manager())._confirm_(_st("Do you REALLY want to remove protocol ").__comma(_st(self)._selectedProtocol()));
 if(smalltalk.assert($1)){
-_st(_st(self)._environment())._removeProtocol_from_(_st(self)._selectedProtocol(),_st(self)._selectedClass());
+return _st(_st(self)._environment())._removeProtocol_from_(_st(self)._selectedProtocol(),_st(self)._selectedClass());
 };
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"removeProtocol",{},smalltalk.HLBrowserModel)})},
 args: [],
-source: "removeProtocol\x0a\x09(self manager confirm: 'Do you REALLY want to remove protocol ', self selectedProtocol)\x0a\x09\x09ifTrue: [ self environment \x0a\x09\x09\x09removeProtocol: self selectedProtocol \x0a\x09\x09\x09from: self selectedClass ]",
-messageSends: ["ifTrue:", "removeProtocol:from:", "selectedProtocol", "selectedClass", "environment", "confirm:", ",", "manager"],
+source: "removeProtocol\x0a\x09self withChangesDo: [\x0a\x09\x09(self manager confirm: 'Do you REALLY want to remove protocol ', self selectedProtocol)\x0a\x09\x09\x09ifTrue: [ self environment \x0a\x09\x09\x09\x09removeProtocol: self selectedProtocol \x0a\x09\x09\x09\x09from: self selectedClass ] ]",
+messageSends: ["withChangesDo:", "ifTrue:", "removeProtocol:from:", "selectedProtocol", "selectedClass", "environment", "confirm:", ",", "manager"],
 referencedClasses: []
 }),
 smalltalk.HLBrowserModel);
@@ -3197,11 +3225,14 @@ category: 'commands actions',
 fn: function (aClassName){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-_st(_st(self)._environment())._renameClass_to_(_st(_st(self)._selectedClass())._theNonMetaClass(),aClassName);
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(_st(self)._environment())._renameClass_to_(_st(_st(self)._selectedClass())._theNonMetaClass(),aClassName);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"renameClassTo:",{aClassName:aClassName},smalltalk.HLBrowserModel)})},
 args: ["aClassName"],
-source: "renameClassTo: aClassName\x0a\x09self environment \x0a\x09\x09renameClass: self selectedClass theNonMetaClass\x0a\x09\x09to: aClassName",
-messageSends: ["renameClass:to:", "theNonMetaClass", "selectedClass", "environment"],
+source: "renameClassTo: aClassName\x0a\x09self withChangesDo: [\x0a\x09\x09self environment \x0a\x09\x09\x09renameClass: self selectedClass theNonMetaClass\x0a\x09\x09\x09to: aClassName ]",
+messageSends: ["withChangesDo:", "renameClass:to:", "theNonMetaClass", "selectedClass", "environment"],
 referencedClasses: []
 }),
 smalltalk.HLBrowserModel);
@@ -3213,11 +3244,14 @@ category: 'commands actions',
 fn: function (aString){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-_st(_st(self)._environment())._renameProtocol_to_in_(_st(self)._selectedProtocol(),aString,_st(self)._selectedClass());
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
+return _st(_st(self)._environment())._renameProtocol_to_in_(_st(self)._selectedProtocol(),aString,_st(self)._selectedClass());
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"renameProtocolTo:",{aString:aString},smalltalk.HLBrowserModel)})},
 args: ["aString"],
-source: "renameProtocolTo: aString\x0a\x09self environment \x0a\x09\x09renameProtocol: self selectedProtocol\x0a\x09\x09to: aString\x0a\x09\x09in: self selectedClass",
-messageSends: ["renameProtocol:to:in:", "selectedProtocol", "selectedClass", "environment"],
+source: "renameProtocolTo: aString\x0a\x09self withChangesDo: [\x0a\x09\x09self environment \x0a\x09\x09\x09renameProtocol: self selectedProtocol\x0a\x09\x09\x09to: aString\x0a\x09\x09\x09in: self selectedClass ]",
+messageSends: ["withChangesDo:", "renameProtocol:to:in:", "selectedProtocol", "selectedClass", "environment"],
 referencedClasses: []
 }),
 smalltalk.HLBrowserModel);
@@ -3228,8 +3262,10 @@ selector: "save:",
 category: 'actions',
 fn: function (aString){
 var self=this;
+function $HLSourceCodeSaved(){return smalltalk.HLSourceCodeSaved||(typeof HLSourceCodeSaved=="undefined"?nil:HLSourceCodeSaved)}
 return smalltalk.withContext(function($ctx1) { 
 var $1;
+_st(_st(self)._announcer())._announce_(_st($HLSourceCodeSaved())._new());
 $1=_st(self)._shouldCompileClassDefinition_(aString);
 if(smalltalk.assert($1)){
 _st(self)._compileClassDefinition_(aString);
@@ -3238,9 +3274,9 @@ _st(self)._compileMethod_(aString);
 };
 return self}, function($ctx1) {$ctx1.fill(self,"save:",{aString:aString},smalltalk.HLBrowserModel)})},
 args: ["aString"],
-source: "save: aString\x0a\x09(self shouldCompileClassDefinition: aString)\x0a\x09\x09ifTrue: [ self compileClassDefinition: aString ]\x0a\x09\x09ifFalse: [ self compileMethod: aString ]",
-messageSends: ["ifTrue:ifFalse:", "compileClassDefinition:", "compileMethod:", "shouldCompileClassDefinition:"],
-referencedClasses: []
+source: "save: aString\x0a\x09self announcer announce: HLSourceCodeSaved new.\x0a\x09\x0a\x09(self shouldCompileClassDefinition: aString)\x0a\x09\x09ifTrue: [ self compileClassDefinition: aString ]\x0a\x09\x09ifFalse: [ self compileMethod: aString ]",
+messageSends: ["announce:", "new", "announcer", "ifTrue:ifFalse:", "compileClassDefinition:", "compileMethod:", "shouldCompileClassDefinition:"],
+referencedClasses: ["HLSourceCodeSaved"]
 }),
 smalltalk.HLBrowserModel);
 
@@ -3288,15 +3324,17 @@ var self=this;
 function $HLClassSelected(){return smalltalk.HLClassSelected||(typeof HLClassSelected=="undefined"?nil:HLClassSelected)}
 return smalltalk.withContext(function($ctx1) { 
 var $1,$2,$3,$4,$5;
-$1=_st(self["@selectedClass"]).__eq(aClass);
-if(smalltalk.assert($1)){
-$2=aClass;
-if(($receiver = $2) == nil || $receiver == undefined){
-$3=self;
-return $3;
+$1=aClass;
+if(($receiver = $1) == nil || $receiver == undefined){
+$2=self;
+return $2;
 } else {
-$2;
+$1;
 };
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
+$3=_st(self["@selectedClass"]).__eq(aClass);
+if(smalltalk.assert($3)){
 _st(self)._selectedProtocol_(nil);
 };
 $4=aClass;
@@ -3314,11 +3352,12 @@ self["@selectedClass"];
 };
 };
 _st(self)._selectedProtocol_(nil);
-_st(_st(self)._announcer())._announce_(_st($HLClassSelected())._on_(_st(self)._selectedClass()));
+return _st(_st(self)._announcer())._announce_(_st($HLClassSelected())._on_(_st(self)._selectedClass()));
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"selectedClass:",{aClass:aClass},smalltalk.HLBrowserModel)})},
 args: ["aClass"],
-source: "selectedClass: aClass\x0a\x09selectedClass = aClass ifTrue: [ \x0a\x09\x09aClass ifNil: [ ^ self ].\x0a\x09\x09self selectedProtocol: nil ].\x0a    \x0a\x09aClass \x0a   \x09\x09ifNil: [ selectedClass := nil ]\x0a    \x09ifNotNil: [\x0a\x09\x09\x09self showInstance \x0a   \x09\x09\x09\x09ifTrue: [ selectedClass := aClass theNonMetaClass ]\x0a     \x09\x09\x09ifFalse: [ selectedClass := aClass theMetaClass ] ].\x0a\x09self selectedProtocol: nil.\x0a\x09self announcer announce: (HLClassSelected on: self selectedClass)",
-messageSends: ["ifTrue:", "ifNil:", "selectedProtocol:", "=", "ifNil:ifNotNil:", "ifTrue:ifFalse:", "theNonMetaClass", "theMetaClass", "showInstance", "announce:", "on:", "selectedClass", "announcer"],
+source: "selectedClass: aClass\x0a\x09aClass ifNil: [ ^ self ].\x0a\x09\x0a\x09self withChangesDo: [\x0a\x09\x09selectedClass = aClass ifTrue: [ \x0a\x09\x09\x09self selectedProtocol: nil ].\x0a    \x0a\x09\x09aClass \x0a   \x09\x09\x09ifNil: [ selectedClass := nil ]\x0a    \x09\x09ifNotNil: [\x0a\x09\x09\x09\x09self showInstance \x0a   \x09\x09\x09\x09\x09ifTrue: [ selectedClass := aClass theNonMetaClass ]\x0a     \x09\x09\x09\x09ifFalse: [ selectedClass := aClass theMetaClass ] ].\x0a\x09\x09self selectedProtocol: nil.\x0a\x09\x09self announcer announce: (HLClassSelected on: self selectedClass) ]",
+messageSends: ["ifNil:", "withChangesDo:", "ifTrue:", "selectedProtocol:", "=", "ifNil:ifNotNil:", "ifTrue:ifFalse:", "theNonMetaClass", "theMetaClass", "showInstance", "announce:", "on:", "selectedClass", "announcer"],
 referencedClasses: ["HLClassSelected"]
 }),
 smalltalk.HLBrowserModel);
@@ -3357,30 +3396,28 @@ fn: function (aCompiledMethod){
 var self=this;
 function $HLMethodSelected(){return smalltalk.HLMethodSelected||(typeof HLMethodSelected=="undefined"?nil:HLMethodSelected)}
 return smalltalk.withContext(function($ctx1) { 
-var $1,$2,$3,$4,$5;
+var $1,$2,$3;
 $1=_st(self["@selectedSelector"]).__eq(aCompiledMethod);
 if(smalltalk.assert($1)){
 $2=self;
 return $2;
 };
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
 $3=aCompiledMethod;
 if(($receiver = $3) == nil || $receiver == undefined){
 self["@selectedSelector"]=nil;
 self["@selectedSelector"];
 } else {
-$4=_st(self["@selectedSelector"]).__eq(_st(aCompiledMethod)._selector());
-if(smalltalk.assert($4)){
-$5=self;
-return $5;
-};
 self["@selectedSelector"]=_st(aCompiledMethod)._selector();
 self["@selectedSelector"];
 };
-_st(_st(self)._announcer())._announce_(_st($HLMethodSelected())._on_(aCompiledMethod));
+return _st(_st(self)._announcer())._announce_(_st($HLMethodSelected())._on_(aCompiledMethod));
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"selectedMethod:",{aCompiledMethod:aCompiledMethod},smalltalk.HLBrowserModel)})},
 args: ["aCompiledMethod"],
-source: "selectedMethod: aCompiledMethod\x0a\x09selectedSelector = aCompiledMethod ifTrue: [ ^ self ].\x0a    \x0a    aCompiledMethod\x0a    \x09ifNil: [ selectedSelector := nil ]\x0a      \x09ifNotNil: [\x0a\x09\x09\x09selectedSelector = aCompiledMethod selector ifTrue: [ ^ self ].\x0a\x09\x09\x09selectedSelector := aCompiledMethod selector ].\x0a\x0a    self announcer announce: (HLMethodSelected on: aCompiledMethod)",
-messageSends: ["ifTrue:", "=", "ifNil:ifNotNil:", "selector", "announce:", "on:", "announcer"],
+source: "selectedMethod: aCompiledMethod\x0a\x09selectedSelector = aCompiledMethod ifTrue: [ ^ self ].\x0a    \x0a    self withChangesDo: [\x0a\x09\x09aCompiledMethod\x0a    \x09\x09ifNil: [ selectedSelector := nil ]\x0a      \x09\x09ifNotNil: [\x0a\x09\x09\x09\x09selectedSelector := aCompiledMethod selector ].\x0a\x0a\x09\x09self announcer announce: (HLMethodSelected on: aCompiledMethod) ]",
+messageSends: ["ifTrue:", "=", "withChangesDo:", "ifNil:ifNotNil:", "selector", "announce:", "on:", "announcer"],
 referencedClasses: ["HLMethodSelected"]
 }),
 smalltalk.HLBrowserModel);
@@ -3417,13 +3454,17 @@ if(smalltalk.assert($1)){
 $2=self;
 return $2;
 };
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
 self["@selectedPackage"]=aPackage;
+self["@selectedPackage"];
 _st(self)._selectedClass_(nil);
-_st(_st(self)._announcer())._announce_(_st($HLPackageSelected())._on_(aPackage));
+return _st(_st(self)._announcer())._announce_(_st($HLPackageSelected())._on_(aPackage));
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"selectedPackage:",{aPackage:aPackage},smalltalk.HLBrowserModel)})},
 args: ["aPackage"],
-source: "selectedPackage: aPackage\x0a\x09selectedPackage = aPackage ifTrue: [ ^ self ].\x0a    \x0a\x09selectedPackage := aPackage.\x0a\x09self selectedClass: nil.\x0a    self announcer announce: (HLPackageSelected on: aPackage)",
-messageSends: ["ifTrue:", "=", "selectedClass:", "announce:", "on:", "announcer"],
+source: "selectedPackage: aPackage\x0a\x09selectedPackage = aPackage ifTrue: [ ^ self ].\x0a    \x0a\x09self withChangesDo: [\x0a\x09\x09selectedPackage := aPackage.\x0a\x09\x09self selectedClass: nil.\x0a\x09\x09self announcer announce: (HLPackageSelected on: aPackage) ]",
+messageSends: ["ifTrue:", "=", "withChangesDo:", "selectedClass:", "announce:", "on:", "announcer"],
 referencedClasses: ["HLPackageSelected"]
 }),
 smalltalk.HLBrowserModel);
@@ -3460,13 +3501,17 @@ if(smalltalk.assert($1)){
 $2=self;
 return $2;
 };
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
 self["@selectedProtocol"]=aString;
+self["@selectedProtocol"];
 _st(self)._selectedMethod_(nil);
-_st(_st(self)._announcer())._announce_(_st($HLProtocolSelected())._on_(aString));
+return _st(_st(self)._announcer())._announce_(_st($HLProtocolSelected())._on_(aString));
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"selectedProtocol:",{aString:aString},smalltalk.HLBrowserModel)})},
 args: ["aString"],
-source: "selectedProtocol: aString\x0a\x09selectedProtocol = aString ifTrue: [ ^ self ].\x0a    \x0a\x09selectedProtocol := aString.\x0a    self selectedMethod: nil.\x0a    self announcer announce: (HLProtocolSelected on: aString)",
-messageSends: ["ifTrue:", "=", "selectedMethod:", "announce:", "on:", "announcer"],
+source: "selectedProtocol: aString\x0a\x09selectedProtocol = aString ifTrue: [ ^ self ].\x0a\x0a\x09self withChangesDo: [\x0a\x09\x09selectedProtocol := aString.\x0a\x09\x09self selectedMethod: nil.\x0a\x09\x09self announcer announce: (HLProtocolSelected on: aString) ]",
+messageSends: ["ifTrue:", "=", "withChangesDo:", "selectedMethod:", "announce:", "on:", "announcer"],
 referencedClasses: ["HLProtocolSelected"]
 }),
 smalltalk.HLBrowserModel);
@@ -3523,12 +3568,16 @@ fn: function (aBoolean){
 var self=this;
 function $HLShowCommentToggled(){return smalltalk.HLShowCommentToggled||(typeof HLShowCommentToggled=="undefined"?nil:HLShowCommentToggled)}
 return smalltalk.withContext(function($ctx1) { 
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
 self["@showComment"]=aBoolean;
-_st(_st(self)._announcer())._announce_(_st($HLShowCommentToggled())._new());
+self["@showComment"];
+return _st(_st(self)._announcer())._announce_(_st($HLShowCommentToggled())._new());
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"showComment:",{aBoolean:aBoolean},smalltalk.HLBrowserModel)})},
 args: ["aBoolean"],
-source: "showComment: aBoolean\x0a\x09showComment := aBoolean.\x0a\x0a    self announcer announce: HLShowCommentToggled new",
-messageSends: ["announce:", "new", "announcer"],
+source: "showComment: aBoolean\x0a\x09self withChangesDo: [\x0a\x09\x09showComment := aBoolean.\x0a\x09\x09self announcer announce: HLShowCommentToggled new ]",
+messageSends: ["withChangesDo:", "announce:", "new", "announcer"],
 referencedClasses: ["HLShowCommentToggled"]
 }),
 smalltalk.HLBrowserModel);
@@ -3565,8 +3614,12 @@ var self=this;
 function $HLShowInstanceToggled(){return smalltalk.HLShowInstanceToggled||(typeof HLShowInstanceToggled=="undefined"?nil:HLShowInstanceToggled)}
 return smalltalk.withContext(function($ctx1) { 
 var $1,$2,$4,$3;
+_st(self)._withChangesDo_((function(){
+return smalltalk.withContext(function($ctx2) {
 self["@showInstance"]=aBoolean;
+self["@showInstance"];
 self["@showComment"]=false;
+self["@showComment"];
 $1=_st(self)._selectedClass();
 if(($receiver = $1) == nil || $receiver == undefined){
 $1;
@@ -3580,11 +3633,12 @@ $3=_st(_st(self)._selectedClass())._theMetaClass();
 };
 _st($2)._selectedClass_($3);
 };
-_st(_st(self)._announcer())._announce_(_st($HLShowInstanceToggled())._new());
+return _st(_st(self)._announcer())._announce_(_st($HLShowInstanceToggled())._new());
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"showInstance:",{aBoolean:aBoolean},smalltalk.HLBrowserModel)})},
 args: ["aBoolean"],
-source: "showInstance: aBoolean\x0a\x09showInstance := aBoolean.\x0a\x09showComment := false.\x0a\x0a    self selectedClass ifNotNil: [\x0a    \x09self selectedClass: (aBoolean\x0a    \x09\x09ifTrue: [self selectedClass theNonMetaClass ]\x0a    \x09  \x09ifFalse: [ self selectedClass theMetaClass ]) ].\x0a    \x0a    self announcer announce: HLShowInstanceToggled new",
-messageSends: ["ifNotNil:", "selectedClass:", "ifTrue:ifFalse:", "theNonMetaClass", "selectedClass", "theMetaClass", "announce:", "new", "announcer"],
+source: "showInstance: aBoolean\x0a\x0a\x09self withChangesDo: [\x0a\x09\x09showInstance := aBoolean.\x0a\x09\x09showComment := false.\x0a\x0a    \x09self selectedClass ifNotNil: [\x0a    \x09\x09self selectedClass: (aBoolean\x0a    \x09\x09\x09ifTrue: [self selectedClass theNonMetaClass ]\x0a\x09    \x09  \x09ifFalse: [ self selectedClass theMetaClass ]) ].\x0a    \x0a\x09\x09self announcer announce: HLShowInstanceToggled new ] ",
+messageSends: ["withChangesDo:", "ifNotNil:", "selectedClass:", "ifTrue:ifFalse:", "theNonMetaClass", "selectedClass", "theMetaClass", "announce:", "new", "announcer"],
 referencedClasses: ["HLShowInstanceToggled"]
 }),
 smalltalk.HLBrowserModel);
@@ -3605,6 +3659,30 @@ referencedClasses: []
 }),
 smalltalk.HLBrowserModel);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "withChangesDo:",
+category: 'error handling',
+fn: function (aBlock){
+var self=this;
+function $HLChangeForbidden(){return smalltalk.HLChangeForbidden||(typeof HLChangeForbidden=="undefined"?nil:HLChangeForbidden)}
+function $HLAboutToChange(){return smalltalk.HLAboutToChange||(typeof HLAboutToChange=="undefined"?nil:HLAboutToChange)}
+return smalltalk.withContext(function($ctx1) { 
+_st((function(){
+return smalltalk.withContext(function($ctx2) {
+_st(_st(self)._announcer())._announce_(_st($HLAboutToChange())._new());
+return _st(aBlock)._value();
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1)})}))._on_do_($HLChangeForbidden(),(function(ex){
+return smalltalk.withContext(function($ctx2) {
+}, function($ctx2) {$ctx2.fillBlock({ex:ex},$ctx1)})}));
+return self}, function($ctx1) {$ctx1.fill(self,"withChangesDo:",{aBlock:aBlock},smalltalk.HLBrowserModel)})},
+args: ["aBlock"],
+source: "withChangesDo: aBlock\x0a\x09[ \x0a\x09\x09self announcer announce: HLAboutToChange new.\x0a\x09\x09aBlock value\x0a\x09]\x0a\x09\x09on: HLChangeForbidden \x0a\x09\x09do: [ :ex | ]",
+messageSends: ["on:do:", "announce:", "new", "announcer", "value"],
+referencedClasses: ["HLChangeForbidden", "HLAboutToChange"]
+}),
+smalltalk.HLBrowserModel);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "withCompileErrorHandling:",

+ 98 - 69
st/Helios-Browser.st

@@ -1,14 +1,10 @@
 Smalltalk current createPackage: 'Helios-Browser'!
 HLWidget subclass: #HLBrowser
-	instanceVariableNames: 'model packagesListWidget classesListWidget protocolsListWidget methodsListWidget sourceWidget'
+	instanceVariableNames: 'model packagesListWidget classesListWidget protocolsListWidget methodsListWidget sourceWidget bottomDiv'
 	package: 'Helios-Browser'!
 
 !HLBrowser methodsFor: 'accessing'!
 
-announcer
-	^ self model announcer
-!
-
 environment
 	^ self model environment
 !
@@ -158,6 +154,10 @@ selectedItem: anItem
 
 !HLBrowserListWidget methodsFor: 'actions'!
 
+activateListItem: anItem
+	self model withChangesDo: [ super activateListItem: anItem ]
+!
+
 observeModel
 !
 
@@ -316,7 +316,8 @@ setItemsForSelectedPackage
 !HLClassesListWidget methodsFor: 'reactions'!
 
 onClassAdded: aClass
-	aClass package = self model selectedPackage ifFalse: [ ^ self ].
+	(aClass package = self model selectedPackage or: [
+		self items includes: aClass ]) ifFalse: [ ^ self ].
     
     self setItemsForSelectedPackage.
     self refresh
@@ -385,7 +386,6 @@ onShowInstanceToggled
 renderButtonsOn: html
 	html div 
         class: 'btn-group';
-		at: 'data-toggle' put: 'buttons-radio';
 		with: [ 
            	html button 
                 class: (String streamContents: [ :str |
@@ -912,18 +912,20 @@ selectedClass
 !
 
 selectedClass: aClass
-	selectedClass = aClass ifTrue: [ 
-		aClass ifNil: [ ^ self ].
-		self selectedProtocol: nil ].
+	aClass ifNil: [ ^ self ].
+	
+	self withChangesDo: [
+		selectedClass = aClass ifTrue: [ 
+			self selectedProtocol: nil ].
     
-	aClass 
-   		ifNil: [ selectedClass := nil ]
-    	ifNotNil: [
-			self showInstance 
-   				ifTrue: [ selectedClass := aClass theNonMetaClass ]
-     			ifFalse: [ selectedClass := aClass theMetaClass ] ].
-	self selectedProtocol: nil.
-	self announcer announce: (HLClassSelected on: self selectedClass)
+		aClass 
+   			ifNil: [ selectedClass := nil ]
+    		ifNotNil: [
+				self showInstance 
+   					ifTrue: [ selectedClass := aClass theNonMetaClass ]
+     				ifFalse: [ selectedClass := aClass theMetaClass ] ].
+		self selectedProtocol: nil.
+		self announcer announce: (HLClassSelected on: self selectedClass) ]
 !
 
 selectedMethod
@@ -936,13 +938,13 @@ selectedMethod
 selectedMethod: aCompiledMethod
 	selectedSelector = aCompiledMethod ifTrue: [ ^ self ].
     
-    aCompiledMethod
-    	ifNil: [ selectedSelector := nil ]
-      	ifNotNil: [
-			selectedSelector = aCompiledMethod selector ifTrue: [ ^ self ].
-			selectedSelector := aCompiledMethod selector ].
+    self withChangesDo: [
+		aCompiledMethod
+    		ifNil: [ selectedSelector := nil ]
+      		ifNotNil: [
+				selectedSelector := aCompiledMethod selector ].
 
-    self announcer announce: (HLMethodSelected on: aCompiledMethod)
+		self announcer announce: (HLMethodSelected on: aCompiledMethod) ]
 !
 
 selectedPackage
@@ -952,9 +954,10 @@ selectedPackage
 selectedPackage: aPackage
 	selectedPackage = aPackage ifTrue: [ ^ self ].
     
-	selectedPackage := aPackage.
-	self selectedClass: nil.
-    self announcer announce: (HLPackageSelected on: aPackage)
+	self withChangesDo: [
+		selectedPackage := aPackage.
+		self selectedClass: nil.
+		self announcer announce: (HLPackageSelected on: aPackage) ]
 !
 
 selectedProtocol
@@ -963,10 +966,11 @@ selectedProtocol
 
 selectedProtocol: aString
 	selectedProtocol = aString ifTrue: [ ^ self ].
-    
-	selectedProtocol := aString.
-    self selectedMethod: nil.
-    self announcer announce: (HLProtocolSelected on: aString)
+
+	self withChangesDo: [
+		selectedProtocol := aString.
+		self selectedMethod: nil.
+		self announcer announce: (HLProtocolSelected on: aString) ]
 !
 
 showComment
@@ -974,9 +978,9 @@ showComment
 !
 
 showComment: aBoolean
-	showComment := aBoolean.
-
-    self announcer announce: HLShowCommentToggled new
+	self withChangesDo: [
+		showComment := aBoolean.
+		self announcer announce: HLShowCommentToggled new ]
 !
 
 showInstance
@@ -984,15 +988,17 @@ showInstance
 !
 
 showInstance: aBoolean
-	showInstance := aBoolean.
-	showComment := false.
 
-    self selectedClass ifNotNil: [
-    	self selectedClass: (aBoolean
-    		ifTrue: [self selectedClass theNonMetaClass ]
-    	  	ifFalse: [ self selectedClass theMetaClass ]) ].
+	self withChangesDo: [
+		showInstance := aBoolean.
+		showComment := false.
+
+    	self selectedClass ifNotNil: [
+    		self selectedClass: (aBoolean
+    			ifTrue: [self selectedClass theNonMetaClass ]
+	    	  	ifFalse: [ self selectedClass theMetaClass ]) ].
     
-    self announcer announce: HLShowInstanceToggled new
+		self announcer announce: HLShowInstanceToggled new ]
 ! !
 
 !HLBrowserModel methodsFor: 'actions'!
@@ -1026,6 +1032,8 @@ focusOnSourceCode
 !
 
 save: aString
+	self announcer announce: HLSourceCodeSaved new.
+	
 	(self shouldCompileClassDefinition: aString)
 		ifTrue: [ self compileClassDefinition: aString ]
 		ifFalse: [ self compileMethod: aString ]
@@ -1044,63 +1052,75 @@ commitPackage
 !
 
 copyClassTo: aClassName
-	self environment 
-		copyClass: self selectedClass theNonMetaClass
-		to: aClassName
+	self withChangesDo: [ 
+		self environment 
+			copyClass: self selectedClass theNonMetaClass
+			to: aClassName ]
 !
 
 moveClassToPackage: aPackageName
-	self environment 
-		moveClass: self selectedClass theNonMetaClass
-		toPackage: aPackageName
+	self withChangesDo: [
+		self environment 
+			moveClass: self selectedClass theNonMetaClass
+			toPackage: aPackageName ]
 !
 
 moveMethodToClass: aClassName
-	self environment 
-		moveMethod: self selectedMethod 
-		toClass: aClassName
+	self withChangesDo: [
+		self environment 
+			moveMethod: self selectedMethod 
+			toClass: aClassName ]
 !
 
 moveMethodToProtocol: aProtocol
-	self environment moveMethod: self selectedMethod toProtocol: aProtocol
+	self withChangesDo: [
+		self environment 
+			moveMethod: self selectedMethod 
+			toProtocol: aProtocol ]
 !
 
 openClassNamed: aString
 	| class |
 	
-	class := self environment classNamed: aString.
-	self selectedPackage: class package.
-	self selectedClass: class
+	self withChangesDo: [
+		class := self environment classNamed: aString.
+		self selectedPackage: class package.
+		self selectedClass: class ]
 !
 
 removeClass
-	(self manager confirm: 'Do you REALLY want to remove class ', self selectedClass name)
-		ifTrue: [ self environment removeClass: self selectedClass ]
+	self withChangesDo: [
+		(self manager confirm: 'Do you REALLY want to remove class ', self selectedClass name)
+			ifTrue: [ self environment removeClass: self selectedClass ] ]
 !
 
 removeMethod
-	(self manager confirm: 'Do you REALLY want to remove method ', self selectedMethod methodClass name,' >> #', self selectedMethod selector)
-		ifTrue: [ self environment removeMethod: self selectedMethod ]
+	self withChangesDo: [
+		(self manager confirm: 'Do you REALLY want to remove method ', self selectedMethod methodClass name,' >> #', self selectedMethod selector)
+			ifTrue: [ self environment removeMethod: self selectedMethod ] ]
 !
 
 removeProtocol
-	(self manager confirm: 'Do you REALLY want to remove protocol ', self selectedProtocol)
-		ifTrue: [ self environment 
-			removeProtocol: self selectedProtocol 
-			from: self selectedClass ]
+	self withChangesDo: [
+		(self manager confirm: 'Do you REALLY want to remove protocol ', self selectedProtocol)
+			ifTrue: [ self environment 
+				removeProtocol: self selectedProtocol 
+				from: self selectedClass ] ]
 !
 
 renameClassTo: aClassName
-	self environment 
-		renameClass: self selectedClass theNonMetaClass
-		to: aClassName
+	self withChangesDo: [
+		self environment 
+			renameClass: self selectedClass theNonMetaClass
+			to: aClassName ]
 !
 
 renameProtocolTo: aString
-	self environment 
-		renameProtocol: self selectedProtocol
-		to: aString
-		in: self selectedClass
+	self withChangesDo: [
+		self environment 
+			renameProtocol: self selectedProtocol
+			to: aString
+			in: self selectedClass ]
 ! !
 
 !HLBrowserModel methodsFor: 'compiling'!
@@ -1166,6 +1186,15 @@ handleParseError: anError
 		yourself)
 !
 
+withChangesDo: aBlock
+	[ 
+		self announcer announce: HLAboutToChange new.
+		aBlock value
+	]
+		on: HLChangeForbidden 
+		do: [ :ex | ]
+!
+
 withCompileErrorHandling: aBlock
 	[
 		[