1
0
فهرست منبع

Add Helios SUnit commands for
1. Select all classes
2. Invert selected classes
3. Invert selected packages

Speed up display of select all by just adding / removing classes on
list items instead of redrawing the whole list.

Rename privateSelectedClasses to more descriptive unfilteredSelectedClasses

Ryan Simmons 11 سال پیش
والد
کامیت
24e60995af
6فایلهای تغییر یافته به همراه713 افزوده شده و 66 حذف شده
  1. 284 0
      src/Helios-Commands-SUnit.js
  2. 126 0
      src/Helios-Commands-SUnit.st
  3. 108 0
      src/Helios-SUnit-Tests.js
  4. 28 0
      src/Helios-SUnit-Tests.st
  5. 127 50
      src/Helios-SUnit.js
  6. 40 16
      src/Helios-SUnit.st

+ 284 - 0
src/Helios-Commands-SUnit.js

@@ -3,6 +3,7 @@ smalltalk.addPackage('Helios-Commands-SUnit');
 smalltalk.packages["Helios-Commands-SUnit"].transport = {"type":"amd","amdNamespace":"helios"};
 
 smalltalk.addClass('HLSUnitCommand', globals.HLToolCommand, [], 'Helios-Commands-SUnit');
+globals.HLSUnitCommand.comment="I group the commands pertaining to Helios-SUnit (`HLSUnitModel`)";
 
 smalltalk.addMethod(
 smalltalk.method({
@@ -24,7 +25,205 @@ referencedClasses: ["HLSUnitModel"]
 globals.HLSUnitCommand.klass);
 
 
+smalltalk.addClass('HLSUnitInvertSelectedCommand', globals.HLSUnitCommand, [], 'Helios-Commands-SUnit');
+globals.HLSUnitInvertSelectedCommand.comment="I group the commands that invert selections";
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "key",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "i";
+},
+args: [],
+source: "key\x0a\x09^ 'i'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLSUnitInvertSelectedCommand.klass);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "label",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "Invert selection";
+},
+args: [],
+source: "label\x0a\x09^'Invert selection'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLSUnitInvertSelectedCommand.klass);
+
+
+smalltalk.addClass('HLSUnitInvertSelectedClassesCommand', globals.HLSUnitInvertSelectedCommand, [], 'Helios-Commands-SUnit');
+globals.HLSUnitInvertSelectedClassesCommand.comment="Invert the currently selected classes on a `HLSUnitModel`";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "category",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "Classes";
+},
+args: [],
+source: "category\x0a\x09^'Classes'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLSUnitInvertSelectedClassesCommand);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "execute",
+protocol: 'executing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._model())._invertSelectedClasses();
+return self}, function($ctx1) {$ctx1.fill(self,"execute",{},globals.HLSUnitInvertSelectedClassesCommand)})},
+args: [],
+source: "execute\x0a\x09self model invertSelectedClasses",
+messageSends: ["invertSelectedClasses", "model"],
+referencedClasses: []
+}),
+globals.HLSUnitInvertSelectedClassesCommand);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "isActive",
+protocol: 'testing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(_st(self["@model"])._selectedPackages())._notEmpty();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"isActive",{},globals.HLSUnitInvertSelectedClassesCommand)})},
+args: [],
+source: "isActive\x0a\x09^model selectedPackages notEmpty",
+messageSends: ["notEmpty", "selectedPackages"],
+referencedClasses: []
+}),
+globals.HLSUnitInvertSelectedClassesCommand);
+
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "key",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "c";
+},
+args: [],
+source: "key\x0a\x09^ 'c'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLSUnitInvertSelectedClassesCommand.klass);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "label",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "Invert selected classes";
+},
+args: [],
+source: "label\x0a\x09^ 'Invert selected classes'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLSUnitInvertSelectedClassesCommand.klass);
+
+
+smalltalk.addClass('HLSUnitInvertSelectedPackagesCommand', globals.HLSUnitInvertSelectedCommand, [], 'Helios-Commands-SUnit');
+globals.HLSUnitInvertSelectedPackagesCommand.comment="Invert the currently selected packages on a `HLSUnitModel`";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "category",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "Packages";
+},
+args: [],
+source: "category\x0a\x09^'Packages'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLSUnitInvertSelectedPackagesCommand);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "execute",
+protocol: 'executing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._model())._invertSelectedPackages();
+return self}, function($ctx1) {$ctx1.fill(self,"execute",{},globals.HLSUnitInvertSelectedPackagesCommand)})},
+args: [],
+source: "execute\x0a\x09self model invertSelectedPackages",
+messageSends: ["invertSelectedPackages", "model"],
+referencedClasses: []
+}),
+globals.HLSUnitInvertSelectedPackagesCommand);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "isActive",
+protocol: 'testing',
+fn: function (){
+var self=this;
+return true;
+},
+args: [],
+source: "isActive\x0a\x09^true",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLSUnitInvertSelectedPackagesCommand);
+
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "key",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "p";
+},
+args: [],
+source: "key\x0a\x09^ 'p'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLSUnitInvertSelectedPackagesCommand.klass);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "label",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "Invert selected packages";
+},
+args: [],
+source: "label\x0a\x09^ 'Invert selected packages'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLSUnitInvertSelectedPackagesCommand.klass);
+
+
 smalltalk.addClass('HLSUnitRunTests', globals.HLSUnitCommand, [], 'Helios-Commands-SUnit');
+globals.HLSUnitRunTests.comment="Run the test cases in the currently selected classes on a `HLSUnitModel`";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "execute",
@@ -89,6 +288,7 @@ globals.HLSUnitRunTests.klass);
 
 
 smalltalk.addClass('HLSUnitSelectAllCommand', globals.HLSUnitCommand, [], 'Helios-Commands-SUnit');
+globals.HLSUnitSelectAllCommand.comment="I group the select all commands";
 
 smalltalk.addMethod(
 smalltalk.method({
@@ -121,7 +321,91 @@ referencedClasses: []
 globals.HLSUnitSelectAllCommand.klass);
 
 
+smalltalk.addClass('HLSUnitSelectAllClassesCommand', globals.HLSUnitSelectAllCommand, [], 'Helios-Commands-SUnit');
+globals.HLSUnitSelectAllClassesCommand.comment="Select all available test classes based on what packages are selected on a `HLSUnitModel`";
+smalltalk.addMethod(
+smalltalk.method({
+selector: "category",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "Classes";
+},
+args: [],
+source: "category\x0a\x09^'Classes'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLSUnitSelectAllClassesCommand);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "execute",
+protocol: 'executing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._model())._selectAllClasses();
+return self}, function($ctx1) {$ctx1.fill(self,"execute",{},globals.HLSUnitSelectAllClassesCommand)})},
+args: [],
+source: "execute\x0a\x09self model selectAllClasses",
+messageSends: ["selectAllClasses", "model"],
+referencedClasses: []
+}),
+globals.HLSUnitSelectAllClassesCommand);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "isActive",
+protocol: 'testing',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1;
+$1=_st(_st(self["@model"])._selectedPackages())._notEmpty();
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"isActive",{},globals.HLSUnitSelectAllClassesCommand)})},
+args: [],
+source: "isActive\x0a\x09^model selectedPackages notEmpty",
+messageSends: ["notEmpty", "selectedPackages"],
+referencedClasses: []
+}),
+globals.HLSUnitSelectAllClassesCommand);
+
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "key",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "c";
+},
+args: [],
+source: "key\x0a\x09^ 'c'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLSUnitSelectAllClassesCommand.klass);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "label",
+protocol: 'accessing',
+fn: function (){
+var self=this;
+return "Select all classes";
+},
+args: [],
+source: "label\x0a\x09^ 'Select all classes'",
+messageSends: [],
+referencedClasses: []
+}),
+globals.HLSUnitSelectAllClassesCommand.klass);
+
+
 smalltalk.addClass('HLSUnitSelectAllPackagesCommand', globals.HLSUnitSelectAllCommand, [], 'Helios-Commands-SUnit');
+globals.HLSUnitSelectAllPackagesCommand.comment="Select all packages with test cases on a `HLSUnitModel`";
 smalltalk.addMethod(
 smalltalk.method({
 selector: "category",

+ 126 - 0
src/Helios-Commands-SUnit.st

@@ -2,6 +2,8 @@ Smalltalk createPackage: 'Helios-Commands-SUnit'!
 HLToolCommand subclass: #HLSUnitCommand
 	instanceVariableNames: ''
 	package: 'Helios-Commands-SUnit'!
+!HLSUnitCommand commentStamp!
+I group the commands pertaining to Helios-SUnit (`HLSUnitModel`)!
 
 !HLSUnitCommand class methodsFor: 'testing'!
 
@@ -9,9 +11,95 @@ isValidFor: aModel
 	^ aModel isKindOf: HLSUnitModel
 ! !
 
+HLSUnitCommand subclass: #HLSUnitInvertSelectedCommand
+	instanceVariableNames: ''
+	package: 'Helios-Commands-SUnit'!
+!HLSUnitInvertSelectedCommand commentStamp!
+I group the commands that invert selections!
+
+!HLSUnitInvertSelectedCommand class methodsFor: 'accessing'!
+
+key
+	^ 'i'
+!
+
+label
+	^'Invert selection'
+! !
+
+HLSUnitInvertSelectedCommand subclass: #HLSUnitInvertSelectedClassesCommand
+	instanceVariableNames: ''
+	package: 'Helios-Commands-SUnit'!
+!HLSUnitInvertSelectedClassesCommand commentStamp!
+Invert the currently selected classes on a `HLSUnitModel`!
+
+!HLSUnitInvertSelectedClassesCommand methodsFor: 'accessing'!
+
+category
+	^'Classes'
+! !
+
+!HLSUnitInvertSelectedClassesCommand methodsFor: 'executing'!
+
+execute
+	self model invertSelectedClasses
+! !
+
+!HLSUnitInvertSelectedClassesCommand methodsFor: 'testing'!
+
+isActive
+	^model selectedPackages notEmpty
+! !
+
+!HLSUnitInvertSelectedClassesCommand class methodsFor: 'accessing'!
+
+key
+	^ 'c'
+!
+
+label
+	^ 'Invert selected classes'
+! !
+
+HLSUnitInvertSelectedCommand subclass: #HLSUnitInvertSelectedPackagesCommand
+	instanceVariableNames: ''
+	package: 'Helios-Commands-SUnit'!
+!HLSUnitInvertSelectedPackagesCommand commentStamp!
+Invert the currently selected packages on a `HLSUnitModel`!
+
+!HLSUnitInvertSelectedPackagesCommand methodsFor: 'accessing'!
+
+category
+	^'Packages'
+! !
+
+!HLSUnitInvertSelectedPackagesCommand methodsFor: 'executing'!
+
+execute
+	self model invertSelectedPackages
+! !
+
+!HLSUnitInvertSelectedPackagesCommand methodsFor: 'testing'!
+
+isActive
+	^true
+! !
+
+!HLSUnitInvertSelectedPackagesCommand class methodsFor: 'accessing'!
+
+key
+	^ 'p'
+!
+
+label
+	^ 'Invert selected packages'
+! !
+
 HLSUnitCommand subclass: #HLSUnitRunTests
 	instanceVariableNames: ''
 	package: 'Helios-Commands-SUnit'!
+!HLSUnitRunTests commentStamp!
+Run the test cases in the currently selected classes on a `HLSUnitModel`!
 
 !HLSUnitRunTests methodsFor: 'executing'!
 
@@ -38,6 +126,8 @@ label
 HLSUnitCommand subclass: #HLSUnitSelectAllCommand
 	instanceVariableNames: ''
 	package: 'Helios-Commands-SUnit'!
+!HLSUnitSelectAllCommand commentStamp!
+I group the select all commands!
 
 !HLSUnitSelectAllCommand class methodsFor: 'accessing'!
 
@@ -49,9 +139,45 @@ label
 	^ 'Select all'
 ! !
 
+HLSUnitSelectAllCommand subclass: #HLSUnitSelectAllClassesCommand
+	instanceVariableNames: ''
+	package: 'Helios-Commands-SUnit'!
+!HLSUnitSelectAllClassesCommand commentStamp!
+Select all available test classes based on what packages are selected on a `HLSUnitModel`!
+
+!HLSUnitSelectAllClassesCommand methodsFor: 'accessing'!
+
+category
+	^'Classes'
+! !
+
+!HLSUnitSelectAllClassesCommand methodsFor: 'executing'!
+
+execute
+	self model selectAllClasses
+! !
+
+!HLSUnitSelectAllClassesCommand methodsFor: 'testing'!
+
+isActive
+	^model selectedPackages notEmpty
+! !
+
+!HLSUnitSelectAllClassesCommand class methodsFor: 'accessing'!
+
+key
+	^ 'c'
+!
+
+label
+	^ 'Select all classes'
+! !
+
 HLSUnitSelectAllCommand subclass: #HLSUnitSelectAllPackagesCommand
 	instanceVariableNames: ''
 	package: 'Helios-Commands-SUnit'!
+!HLSUnitSelectAllPackagesCommand commentStamp!
+Select all packages with test cases on a `HLSUnitModel`!
 
 !HLSUnitSelectAllPackagesCommand methodsFor: 'accessing'!
 

+ 108 - 0
src/Helios-SUnit-Tests.js

@@ -62,6 +62,114 @@ referencedClasses: ["TestResult"]
 }),
 globals.HLSUnitModelTest);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testInvertSelectedClasses",
+protocol: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2,$4,$3,$6,$5,$8,$7,$10,$9;
+_st(self["@model"])._selectAllPackages();
+_st(self["@model"])._selectAllClasses();
+$1=self["@model"];
+$2=self._class();
+$ctx1.sendIdx["class"]=1;
+_st($1)._unselectClass_($2);
+$4=_st(self["@model"])._selectedClasses();
+$ctx1.sendIdx["selectedClasses"]=1;
+$3=_st($4)._notEmpty();
+self._assert_($3);
+$6=_st(self["@model"])._selectedClasses();
+$ctx1.sendIdx["selectedClasses"]=2;
+$5=_st($6)._size();
+$ctx1.sendIdx["size"]=1;
+$8=_st(_st(self["@model"])._testClasses())._size();
+$ctx1.sendIdx["size"]=2;
+$7=_st($8).__minus((1));
+self._assert_equals_($5,$7);
+$ctx1.sendIdx["assert:equals:"]=1;
+_st(self["@model"])._invertSelectedClasses();
+$10=_st(self["@model"])._selectedClasses();
+$ctx1.sendIdx["selectedClasses"]=3;
+$9=_st($10)._size();
+self._assert_equals_($9,(1));
+$ctx1.sendIdx["assert:equals:"]=2;
+self._assert_equals_(_st(_st(self["@model"])._selectedClasses())._anyOne(),self._class());
+return self}, function($ctx1) {$ctx1.fill(self,"testInvertSelectedClasses",{},globals.HLSUnitModelTest)})},
+args: [],
+source: "testInvertSelectedClasses\x0a\x09model selectAllPackages.\x0a\x09model selectAllClasses.\x0a\x09model unselectClass: self class.\x0a\x09self assert: model selectedClasses notEmpty.\x0a\x09self assert: model selectedClasses size equals: model testClasses size - 1.\x0a\x09model invertSelectedClasses.\x0a\x09self assert: model selectedClasses size equals: 1.\x0a\x09self assert: model selectedClasses anyOne equals: self class.",
+messageSends: ["selectAllPackages", "selectAllClasses", "unselectClass:", "class", "assert:", "notEmpty", "selectedClasses", "assert:equals:", "size", "-", "testClasses", "invertSelectedClasses", "anyOne"],
+referencedClasses: []
+}),
+globals.HLSUnitModelTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testInvertSelectedPackages",
+protocol: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $1,$2,$4,$3,$6,$5,$8,$7,$10,$9;
+_st(self["@model"])._selectAllPackages();
+$1=self["@model"];
+$2=self._thisPackage();
+$ctx1.sendIdx["thisPackage"]=1;
+_st($1)._unselectPackage_($2);
+$4=_st(self["@model"])._selectedPackages();
+$ctx1.sendIdx["selectedPackages"]=1;
+$3=_st($4)._notEmpty();
+self._assert_($3);
+$6=_st(self["@model"])._selectedPackages();
+$ctx1.sendIdx["selectedPackages"]=2;
+$5=_st($6)._size();
+$ctx1.sendIdx["size"]=1;
+$8=_st(_st(self["@model"])._testPackages())._size();
+$ctx1.sendIdx["size"]=2;
+$7=_st($8).__minus((1));
+self._assert_equals_($5,$7);
+$ctx1.sendIdx["assert:equals:"]=1;
+_st(self["@model"])._invertSelectedPackages();
+$10=_st(self["@model"])._selectedPackages();
+$ctx1.sendIdx["selectedPackages"]=3;
+$9=_st($10)._size();
+self._assert_equals_($9,(1));
+$ctx1.sendIdx["assert:equals:"]=2;
+self._assert_equals_(_st(_st(self["@model"])._selectedPackages())._anyOne(),self._thisPackage());
+return self}, function($ctx1) {$ctx1.fill(self,"testInvertSelectedPackages",{},globals.HLSUnitModelTest)})},
+args: [],
+source: "testInvertSelectedPackages\x0a\x09model selectAllPackages.\x0a\x09model unselectPackage: self thisPackage.\x0a\x09self assert: model selectedPackages notEmpty.\x0a\x09self assert: model selectedPackages size equals: model testPackages size - 1.\x0a\x09model invertSelectedPackages.\x0a\x09self assert: model selectedPackages size equals: 1.\x0a\x09self assert: model selectedPackages anyOne equals: self thisPackage.",
+messageSends: ["selectAllPackages", "unselectPackage:", "thisPackage", "assert:", "notEmpty", "selectedPackages", "assert:equals:", "size", "-", "testPackages", "invertSelectedPackages", "anyOne"],
+referencedClasses: []
+}),
+globals.HLSUnitModelTest);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "testSelectAllClasses",
+protocol: 'tests',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1,$3;
+_st(self["@model"])._selectAllPackages();
+$2=_st(self["@model"])._testClasses();
+$ctx1.sendIdx["testClasses"]=1;
+$1=_st($2)._notEmpty();
+self._assert_($1);
+_st(self["@model"])._selectAllClasses();
+$3=_st(_st(self["@model"])._selectedClasses())._size();
+$ctx1.sendIdx["size"]=1;
+self._assert_equals_($3,_st(_st(self["@model"])._testClasses())._size());
+return self}, function($ctx1) {$ctx1.fill(self,"testSelectAllClasses",{},globals.HLSUnitModelTest)})},
+args: [],
+source: "testSelectAllClasses\x0a\x09model selectAllPackages.\x0a\x09self assert: model testClasses notEmpty.\x0a\x09model selectAllClasses.\x0a\x09self assert: model selectedClasses size equals: model testClasses size",
+messageSends: ["selectAllPackages", "assert:", "notEmpty", "testClasses", "selectAllClasses", "assert:equals:", "size", "selectedClasses"],
+referencedClasses: []
+}),
+globals.HLSUnitModelTest);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "testSelectAllPackages",

+ 28 - 0
src/Helios-SUnit-Tests.st

@@ -28,6 +28,34 @@ testEmptyTestResults
 	self assert: (model testResult isKindOf: TestResult)
 !
 
+testInvertSelectedClasses
+	model selectAllPackages.
+	model selectAllClasses.
+	model unselectClass: self class.
+	self assert: model selectedClasses notEmpty.
+	self assert: model selectedClasses size equals: model testClasses size - 1.
+	model invertSelectedClasses.
+	self assert: model selectedClasses size equals: 1.
+	self assert: model selectedClasses anyOne equals: self class.
+!
+
+testInvertSelectedPackages
+	model selectAllPackages.
+	model unselectPackage: self thisPackage.
+	self assert: model selectedPackages notEmpty.
+	self assert: model selectedPackages size equals: model testPackages size - 1.
+	model invertSelectedPackages.
+	self assert: model selectedPackages size equals: 1.
+	self assert: model selectedPackages anyOne equals: self thisPackage.
+!
+
+testSelectAllClasses
+	model selectAllPackages.
+	self assert: model testClasses notEmpty.
+	model selectAllClasses.
+	self assert: model selectedClasses size equals: model testClasses size
+!
+
 testSelectAllPackages
 	self assert: model selectedPackages isEmpty.
 	model selectAllPackages.

+ 127 - 50
src/Helios-SUnit.js

@@ -296,7 +296,7 @@ $ctx1.sendIdx["on:send:to:"]=3;
 $2=_st($1)._on_send_to_($HLClassUnselected(),"onClassUnselected:",self);
 return self}, function($ctx1) {$ctx1.fill(self,"observeModel",{},globals.HLSUnitClassesListWidget)})},
 args: [],
-source: "observeModel\x0a    self model announcer \x0a\x09\x09on: HLPackageSelected\x0a\x09\x09send: #onPackageSelected:\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLPackageUnselected\x0a\x09\x09send: #onPackageUnselected:\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLClassSelected\x0a\x09\x09send: #onClassSelected:\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLClassUnselected\x0a\x09\x09send: #onClassUnselected:\x0a\x09\x09to: self",
+source: "observeModel\x0a    self model announcer \x0a\x09\x09on: HLPackageSelected\x0a\x09\x09send: #onPackageSelected:\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLPackageUnselected\x0a\x09\x09send: #onPackageUnselected:\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLClassSelected\x0a\x09\x09send: #onClassSelected:\x0a\x09\x09to: self;\x0a\x09\x09\x0a\x09\x09on: HLClassUnselected\x0a\x09\x09send: #onClassUnselected:\x0a\x09\x09to: self.",
 messageSends: ["on:send:to:", "announcer", "model"],
 referencedClasses: ["HLPackageSelected", "HLPackageUnselected", "HLClassSelected", "HLClassUnselected"]
 }),
@@ -308,12 +308,14 @@ selector: "onClassSelected:",
 protocol: 'reactions',
 fn: function (anAnnouncement){
 var self=this;
+var listItem;
 return smalltalk.withContext(function($ctx1) { 
-self._refresh();
-return self}, function($ctx1) {$ctx1.fill(self,"onClassSelected:",{anAnnouncement:anAnnouncement},globals.HLSUnitClassesListWidget)})},
+listItem=self._findListItemFor_(_st(anAnnouncement)._item());
+_st(listItem)._addClass_("active");
+return self}, function($ctx1) {$ctx1.fill(self,"onClassSelected:",{anAnnouncement:anAnnouncement,listItem:listItem},globals.HLSUnitClassesListWidget)})},
 args: ["anAnnouncement"],
-source: "onClassSelected: anAnnouncement\x0a\x09self refresh",
-messageSends: ["refresh"],
+source: "onClassSelected: anAnnouncement\x0a\x09| listItem |\x0a\x09listItem := self findListItemFor: anAnnouncement item.\x0a\x09listItem addClass: 'active'.",
+messageSends: ["findListItemFor:", "item", "addClass:"],
 referencedClasses: []
 }),
 globals.HLSUnitClassesListWidget);
@@ -324,12 +326,14 @@ selector: "onClassUnselected:",
 protocol: 'reactions',
 fn: function (anAnnouncement){
 var self=this;
+var listItem;
 return smalltalk.withContext(function($ctx1) { 
-self._refresh();
-return self}, function($ctx1) {$ctx1.fill(self,"onClassUnselected:",{anAnnouncement:anAnnouncement},globals.HLSUnitClassesListWidget)})},
+listItem=self._findListItemFor_(_st(anAnnouncement)._item());
+_st(listItem)._removeClass_("active");
+return self}, function($ctx1) {$ctx1.fill(self,"onClassUnselected:",{anAnnouncement:anAnnouncement,listItem:listItem},globals.HLSUnitClassesListWidget)})},
 args: ["anAnnouncement"],
-source: "onClassUnselected: anAnnouncement\x0a\x09self refresh",
-messageSends: ["refresh"],
+source: "onClassUnselected: anAnnouncement\x0a\x09| listItem |\x0a\x09listItem := self findListItemFor: anAnnouncement item.\x0a\x09listItem removeClass: 'active'.",
+messageSends: ["findListItemFor:", "item", "removeClass:"],
 referencedClasses: []
 }),
 globals.HLSUnitClassesListWidget);
@@ -553,12 +557,14 @@ selector: "onPackageSelected:",
 protocol: 'reactions',
 fn: function (anAnnouncement){
 var self=this;
+var listItem;
 return smalltalk.withContext(function($ctx1) { 
-self._refresh();
-return self}, function($ctx1) {$ctx1.fill(self,"onPackageSelected:",{anAnnouncement:anAnnouncement},globals.HLSUnitPackagesListWidget)})},
+listItem=self._findListItemFor_(_st(anAnnouncement)._item());
+_st(listItem)._addClass_("active");
+return self}, function($ctx1) {$ctx1.fill(self,"onPackageSelected:",{anAnnouncement:anAnnouncement,listItem:listItem},globals.HLSUnitPackagesListWidget)})},
 args: ["anAnnouncement"],
-source: "onPackageSelected: anAnnouncement\x0a\x09self refresh",
-messageSends: ["refresh"],
+source: "onPackageSelected: anAnnouncement\x0a\x09| listItem |\x0a\x09listItem := self findListItemFor: anAnnouncement item.\x0a\x09listItem addClass: 'active'.\x0a\x09",
+messageSends: ["findListItemFor:", "item", "addClass:"],
 referencedClasses: []
 }),
 globals.HLSUnitPackagesListWidget);
@@ -569,12 +575,14 @@ selector: "onPackageUnselected:",
 protocol: 'reactions',
 fn: function (anAnnouncement){
 var self=this;
+var listItem;
 return smalltalk.withContext(function($ctx1) { 
-self._refresh();
-return self}, function($ctx1) {$ctx1.fill(self,"onPackageUnselected:",{anAnnouncement:anAnnouncement},globals.HLSUnitPackagesListWidget)})},
+listItem=self._findListItemFor_(_st(anAnnouncement)._item());
+_st(listItem)._removeClass_("active");
+return self}, function($ctx1) {$ctx1.fill(self,"onPackageUnselected:",{anAnnouncement:anAnnouncement,listItem:listItem},globals.HLSUnitPackagesListWidget)})},
 args: ["anAnnouncement"],
-source: "onPackageUnselected: anAnnouncement\x0a\x09self refresh",
-messageSends: ["refresh"],
+source: "onPackageUnselected: anAnnouncement\x0a\x09| listItem |\x0a\x09listItem := self findListItemFor: anAnnouncement item.\x0a\x09listItem removeClass: 'active'.",
+messageSends: ["findListItemFor:", "item", "removeClass:"],
 referencedClasses: []
 }),
 globals.HLSUnitPackagesListWidget);
@@ -939,42 +947,67 @@ globals.HLSUnitModel);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "onResultAnnouncement:",
-protocol: 'reacting',
-fn: function (announcement){
+selector: "invertSelectedClasses",
+protocol: 'actions',
+fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
-_st(self._announcer())._announce_(announcement);
-return self}, function($ctx1) {$ctx1.fill(self,"onResultAnnouncement:",{announcement:announcement},globals.HLSUnitModel)})},
-args: ["announcement"],
-source: "onResultAnnouncement: announcement\x0a\x09\x22Propogate announcement\x22\x0a\x09self announcer announce: announcement.",
-messageSends: ["announce:", "announcer"],
+var $1;
+_st(self._testClasses())._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
+$1=_st(self._unfilteredSelectedClasses())._includes_(each);
+if(smalltalk.assert($1)){
+return self._unselectClass_(each);
+} else {
+return self._selectClass_(each);
+};
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
+return self}, function($ctx1) {$ctx1.fill(self,"invertSelectedClasses",{},globals.HLSUnitModel)})},
+args: [],
+source: "invertSelectedClasses\x0a\x09self testClasses do: [:each | \x0a\x09\x09(self unfilteredSelectedClasses includes: each)\x0a\x09\x09\x09ifTrue: [ self unselectClass: each ]\x0a\x09\x09\x09ifFalse: [ self selectClass: each ]].\x0a\x09",
+messageSends: ["do:", "testClasses", "ifTrue:ifFalse:", "includes:", "unfilteredSelectedClasses", "unselectClass:", "selectClass:"],
 referencedClasses: []
 }),
 globals.HLSUnitModel);
 
 smalltalk.addMethod(
 smalltalk.method({
-selector: "privateSelectedClasses",
-protocol: 'private',
+selector: "invertSelectedPackages",
+protocol: 'actions',
 fn: function (){
 var self=this;
-function $Set(){return globals.Set||(typeof Set=="undefined"?nil:Set)}
 return smalltalk.withContext(function($ctx1) { 
-var $2,$1,$receiver;
-$2=self["@selectedClasses"];
-if(($receiver = $2) == null || $receiver.isNil){
-self["@selectedClasses"]=_st($Set())._new();
-$1=self["@selectedClasses"];
+var $1;
+_st(self._testPackages())._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
+$1=_st(self._selectedPackages())._includes_(each);
+if(smalltalk.assert($1)){
+return self._unselectPackage_(each);
 } else {
-$1=$2;
+return self._selectPackage_(each);
 };
-return $1;
-}, function($ctx1) {$ctx1.fill(self,"privateSelectedClasses",{},globals.HLSUnitModel)})},
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
+return self}, function($ctx1) {$ctx1.fill(self,"invertSelectedPackages",{},globals.HLSUnitModel)})},
 args: [],
-source: "privateSelectedClasses\x0a\x09^ (selectedClasses ifNil: [ selectedClasses := Set new ])",
-messageSends: ["ifNil:", "new"],
-referencedClasses: ["Set"]
+source: "invertSelectedPackages\x0a\x09self testPackages do: [:each | \x0a\x09\x09(self selectedPackages includes: each)\x0a\x09\x09\x09ifTrue: [ self unselectPackage: each ]\x0a\x09\x09\x09ifFalse: [ self selectPackage: each ]].\x0a\x09",
+messageSends: ["do:", "testPackages", "ifTrue:ifFalse:", "includes:", "selectedPackages", "unselectPackage:", "selectPackage:"],
+referencedClasses: []
+}),
+globals.HLSUnitModel);
+
+smalltalk.addMethod(
+smalltalk.method({
+selector: "onResultAnnouncement:",
+protocol: 'reacting',
+fn: function (announcement){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._announcer())._announce_(announcement);
+return self}, function($ctx1) {$ctx1.fill(self,"onResultAnnouncement:",{announcement:announcement},globals.HLSUnitModel)})},
+args: ["announcement"],
+source: "onResultAnnouncement: announcement\x0a\x09\x22Propogate announcement\x22\x0a\x09self announcer announce: announcement.",
+messageSends: ["announce:", "announcer"],
+referencedClasses: []
 }),
 globals.HLSUnitModel);
 
@@ -1002,6 +1035,25 @@ referencedClasses: ["TestSuiteRunner", "HLRunTests"]
 }),
 globals.HLSUnitModel);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "selectAllClasses",
+protocol: 'actions',
+fn: function (){
+var self=this;
+return smalltalk.withContext(function($ctx1) { 
+_st(self._testClasses())._do_((function(each){
+return smalltalk.withContext(function($ctx2) {
+return self._selectClass_(each);
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
+return self}, function($ctx1) {$ctx1.fill(self,"selectAllClasses",{},globals.HLSUnitModel)})},
+args: [],
+source: "selectAllClasses\x0a\x09self testClasses do: [:each | self selectClass: each].\x0a\x09",
+messageSends: ["do:", "testClasses", "selectClass:"],
+referencedClasses: []
+}),
+globals.HLSUnitModel);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "selectAllPackages",
@@ -1015,7 +1067,7 @@ return self._selectPackage_(each);
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
 return self}, function($ctx1) {$ctx1.fill(self,"selectAllPackages",{},globals.HLSUnitModel)})},
 args: [],
-source: "selectAllPackages\x0a\x09self testPackages do: [:each | self selectPackage: each]",
+source: "selectAllPackages\x0a\x09self testPackages do: [:each | self selectPackage: each].",
 messageSends: ["do:", "testPackages", "selectPackage:"],
 referencedClasses: []
 }),
@@ -1029,12 +1081,12 @@ fn: function (aClass){
 var self=this;
 function $HLClassSelected(){return globals.HLClassSelected||(typeof HLClassSelected=="undefined"?nil:HLClassSelected)}
 return smalltalk.withContext(function($ctx1) { 
-_st(self._privateSelectedClasses())._add_(aClass);
+_st(self._unfilteredSelectedClasses())._add_(aClass);
 _st(self._announcer())._announce_(_st($HLClassSelected())._on_(aClass));
 return self}, function($ctx1) {$ctx1.fill(self,"selectClass:",{aClass:aClass},globals.HLSUnitModel)})},
 args: ["aClass"],
-source: "selectClass: aClass\x0a\x09self privateSelectedClasses add: aClass.\x0a\x09self announcer announce: (HLClassSelected on: aClass).",
-messageSends: ["add:", "privateSelectedClasses", "announce:", "announcer", "on:"],
+source: "selectClass: aClass\x0a\x09self unfilteredSelectedClasses add: aClass.\x0a\x09self announcer announce: (HLClassSelected on: aClass).",
+messageSends: ["add:", "unfilteredSelectedClasses", "announce:", "announcer", "on:"],
 referencedClasses: ["HLClassSelected"]
 }),
 globals.HLSUnitModel);
@@ -1065,15 +1117,15 @@ fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 
 var $1;
-$1=_st(self._privateSelectedClasses())._select_((function(each){
+$1=_st(self._unfilteredSelectedClasses())._select_((function(each){
 return smalltalk.withContext(function($ctx2) {
 return _st(self._selectedPackages())._includes_(_st(each)._package());
 }, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)})}));
 return $1;
 }, function($ctx1) {$ctx1.fill(self,"selectedClasses",{},globals.HLSUnitModel)})},
 args: [],
-source: "selectedClasses\x0a\x09^ (self privateSelectedClasses) select: [:each |\x0a\x09\x09self selectedPackages includes: each package]",
-messageSends: ["select:", "privateSelectedClasses", "includes:", "selectedPackages", "package"],
+source: "selectedClasses\x0a\x09^ (self unfilteredSelectedClasses) select: [:each |\x0a\x09\x09self selectedPackages includes: each package]",
+messageSends: ["select:", "unfilteredSelectedClasses", "includes:", "selectedPackages", "package"],
 referencedClasses: []
 }),
 globals.HLSUnitModel);
@@ -1232,6 +1284,31 @@ referencedClasses: ["TestResult"]
 }),
 globals.HLSUnitModel);
 
+smalltalk.addMethod(
+smalltalk.method({
+selector: "unfilteredSelectedClasses",
+protocol: 'private',
+fn: function (){
+var self=this;
+function $Set(){return globals.Set||(typeof Set=="undefined"?nil:Set)}
+return smalltalk.withContext(function($ctx1) { 
+var $2,$1,$receiver;
+$2=self["@selectedClasses"];
+if(($receiver = $2) == null || $receiver.isNil){
+self["@selectedClasses"]=_st($Set())._new();
+$1=self["@selectedClasses"];
+} else {
+$1=$2;
+};
+return $1;
+}, function($ctx1) {$ctx1.fill(self,"unfilteredSelectedClasses",{},globals.HLSUnitModel)})},
+args: [],
+source: "unfilteredSelectedClasses\x0a\x09^ (selectedClasses ifNil: [ selectedClasses := Set new ])",
+messageSends: ["ifNil:", "new"],
+referencedClasses: ["Set"]
+}),
+globals.HLSUnitModel);
+
 smalltalk.addMethod(
 smalltalk.method({
 selector: "unselectClass:",
@@ -1242,7 +1319,7 @@ function $HLClassUnselected(){return globals.HLClassUnselected||(typeof HLClassU
 return smalltalk.withContext(function($ctx1) { 
 var $early={};
 try {
-_st(self._privateSelectedClasses())._remove_ifAbsent_(aClass,(function(){
+_st(self._unfilteredSelectedClasses())._remove_ifAbsent_(aClass,(function(){
 throw $early=[self];
 }));
 _st(self._announcer())._announce_(_st($HLClassUnselected())._on_(aClass));
@@ -1250,8 +1327,8 @@ return self}
 catch(e) {if(e===$early)return e[0]; throw e}
 }, function($ctx1) {$ctx1.fill(self,"unselectClass:",{aClass:aClass},globals.HLSUnitModel)})},
 args: ["aClass"],
-source: "unselectClass: aClass\x0a\x09self privateSelectedClasses remove: aClass ifAbsent: [^self].\x0a\x09self announcer announce: (HLClassUnselected on: aClass).",
-messageSends: ["remove:ifAbsent:", "privateSelectedClasses", "announce:", "announcer", "on:"],
+source: "unselectClass: aClass\x0a\x09self unfilteredSelectedClasses remove: aClass ifAbsent: [^self].\x0a\x09self announcer announce: (HLClassUnselected on: aClass).",
+messageSends: ["remove:ifAbsent:", "unfilteredSelectedClasses", "announce:", "announcer", "on:"],
 referencedClasses: ["HLClassUnselected"]
 }),
 globals.HLSUnitModel);
@@ -1409,7 +1486,7 @@ smalltalk.addClass('HLSUnitFailuresListWidget', globals.HLSUnitResultListWidget,
 smalltalk.addMethod(
 smalltalk.method({
 selector: "items",
-protocol: 'as yet unclassified',
+protocol: 'accessing',
 fn: function (){
 var self=this;
 return smalltalk.withContext(function($ctx1) { 

+ 40 - 16
src/Helios-SUnit.st

@@ -97,7 +97,7 @@ observeModel
 		
 		on: HLClassUnselected
 		send: #onClassUnselected:
-		to: self
+		to: self.
 !
 
 select: anObject
@@ -117,11 +117,15 @@ initializeItems
 !HLSUnitClassesListWidget methodsFor: 'reactions'!
 
 onClassSelected: anAnnouncement
-	self refresh
+	| listItem |
+	listItem := self findListItemFor: anAnnouncement item.
+	listItem addClass: 'active'.
 !
 
 onClassUnselected: anAnnouncement
-	self refresh
+	| listItem |
+	listItem := self findListItemFor: anAnnouncement item.
+	listItem removeClass: 'active'.
 !
 
 onPackageSelected: anAnnouncement
@@ -199,11 +203,15 @@ initializeItems
 !HLSUnitPackagesListWidget methodsFor: 'reactions'!
 
 onPackageSelected: anAnnouncement
-	self refresh
+	| listItem |
+	listItem := self findListItemFor: anAnnouncement item.
+	listItem addClass: 'active'.
 !
 
 onPackageUnselected: anAnnouncement
-	self refresh
+	| listItem |
+	listItem := self findListItemFor: anAnnouncement item.
+	listItem removeClass: 'active'.
 ! !
 
 !HLSUnitPackagesListWidget methodsFor: 'rendering'!
@@ -325,7 +333,7 @@ currentSuite
 !
 
 selectedClasses
-	^ (self privateSelectedClasses) select: [:each |
+	^ (self unfilteredSelectedClasses) select: [:each |
 		self selectedPackages includes: each package]
 !
 
@@ -366,6 +374,20 @@ testResult
 
 !HLSUnitModel methodsFor: 'actions'!
 
+invertSelectedClasses
+	self testClasses do: [:each | 
+		(self unfilteredSelectedClasses includes: each)
+			ifTrue: [ self unselectClass: each ]
+			ifFalse: [ self selectClass: each ]].
+!
+
+invertSelectedPackages
+	self testPackages do: [:each | 
+		(self selectedPackages includes: each)
+			ifTrue: [ self unselectPackage: each ]
+			ifFalse: [ self selectPackage: each ]].
+!
+
 runTests
 	| worker |
 	worker := TestSuiteRunner on: self testCases.
@@ -375,12 +397,16 @@ runTests
 	worker run
 !
 
+selectAllClasses
+	self testClasses do: [:each | self selectClass: each].
+!
+
 selectAllPackages
-	self testPackages do: [:each | self selectPackage: each]
+	self testPackages do: [:each | self selectPackage: each].
 !
 
 selectClass: aClass
-	self privateSelectedClasses add: aClass.
+	self unfilteredSelectedClasses add: aClass.
 	self announcer announce: (HLClassSelected on: aClass).
 !
 
@@ -399,7 +425,7 @@ subscribeToTestSuite: aTestSuiteRunner
 !
 
 unselectClass: aClass
-	self privateSelectedClasses remove: aClass ifAbsent: [^self].
+	self unfilteredSelectedClasses remove: aClass ifAbsent: [^self].
 	self announcer announce: (HLClassUnselected on: aClass).
 !
 
@@ -410,7 +436,7 @@ unselectPackage: aPackage
 
 !HLSUnitModel methodsFor: 'private'!
 
-privateSelectedClasses
+unfilteredSelectedClasses
 	^ (selectedClasses ifNil: [ selectedClasses := Set new ])
 ! !
 
@@ -476,14 +502,12 @@ HLSUnitResultListWidget subclass: #HLSUnitFailuresListWidget
 
 !HLSUnitFailuresListWidget methodsFor: 'accessing'!
 
-label
-	^'Failures'
-! !
-
-!HLSUnitFailuresListWidget methodsFor: 'as yet unclassified'!
-
 items
 	^self model testResult failures
+!
+
+label
+	^'Failures'
 ! !
 
 HLWidget subclass: #HLSUnitResultStatus