Browse Source

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 years ago
parent
commit
24e60995af
6 changed files with 713 additions and 66 deletions
  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