Clean up visible test handling (including GTK tests).
This will be used for backgrounding (e.g., for runin).
BUG=None
TEST=Manual
Change-Id: Id5e7988f73285fc62407e2d36f15619421983250
Reviewed-on: https://gerrit.chromium.org/gerrit/26801
Tested-by: Jon Salz <jsalz@chromium.org>
Reviewed-by: Chinyue Chen <chinyue@chromium.org>
Reviewed-by: Jon Salz <jsalz@chromium.org>
Commit-Ready: Jon Salz <jsalz@chromium.org>
diff --git a/py/goofy/goofy.py b/py/goofy/goofy.py
index cebd415..a73d982 100755
--- a/py/goofy/goofy.py
+++ b/py/goofy/goofy.py
@@ -203,6 +203,9 @@
lambda event: self.update_factory(),
Event.Type.STOP:
lambda event: self.stop(),
+ Event.Type.SET_VISIBLE_TEST:
+ lambda event: self.set_visible_test(
+ self.test_list.lookup_path(event.path)),
}
self.exceptions = []
@@ -1030,8 +1033,7 @@
# Already running: just bring to the front if it
# has a UI.
logging.info('Setting visible test to %s', test.path)
- self.event_client.post_event(
- Event(Event.Type.SET_VISIBLE_TEST, path=test.path))
+ self.set_visible_test(test)
return
self.abort_active_tests()
diff --git a/py/goofy/js/goofy.js b/py/goofy/js/goofy.js
index 39fe697..3d9fe9e 100644
--- a/py/goofy/js/goofy.js
+++ b/py/goofy/js/goofy.js
@@ -229,6 +229,10 @@
* @type HTMLIFrameElement
*/
this.iframe = goog.dom.iframe.createBlank(new goog.dom.DomHelper(document));
+ goog.dom.classes.add(this.iframe, 'goofy-test-iframe');
+ goog.dom.classes.enable(this.iframe, 'goofy-test-visible',
+ /** @type boolean */(
+ goofy.pathTestMap[path].state.visible));
document.getElementById('goofy-main').appendChild(this.iframe);
this.iframe.contentWindow.test = this.test;
};
@@ -269,10 +273,22 @@
this.uuid = null;
/**
- * Whether the context menu is currently visible.
- * @type boolean
+ * The currently visible context menu, if any.
+ * @type goog.ui.PopupMenu
*/
- this.contextMenuVisible = false;
+ this.contextMenu = null;
+
+ /**
+ * The last test for which a context menu was displayed.
+ * @type {?string}
+ */
+ this.lastContextMenuPath = null;
+
+ /**
+ * The time at which the last context menu was hidden.
+ * @type {?number}
+ */
+ this.lastContextMenuHideTime = null;
/**
* All tooltips that we have created.
@@ -880,13 +896,30 @@
*/
cros.factory.Goofy.prototype.showTestPopup = function(path, labelElement,
extraItems) {
- this.contextMenuVisible = true;
+ var test = this.pathTestMap[path];
+
+ if (path == this.lastContextMenuPath &&
+ (goog.now() - this.lastContextMenuHideTime <
+ goog.ui.PopupBase.DEBOUNCE_DELAY_MS)) {
+ // We just hid it; don't reshow.
+ return false;
+ }
+
+ // If it's a leaf node, and it's the active but not the visible
+ // test, ask the backend to make it visible.
+ if (test.state.status == 'ACTIVE' &&
+ !/** @type boolean */(test.state.visible) &&
+ !test.subtests.length) {
+ this.sendEvent('goofy:set_visible_test', {'path': path});
+ }
+
// Hide all tooltips so that they don't fight with the context menu.
goog.array.forEach(this.tooltips, function(tooltip) {
tooltip.setVisible(false);
});
- var menu = new goog.ui.PopupMenu();
+ var menu = this.contextMenu = new goog.ui.PopupMenu();
+ this.lastContextMenuPath = path;
if (extraItems && extraItems.length) {
goog.array.forEach(extraItems, function(item) {
@@ -897,7 +930,6 @@
var numLeaves = 0;
var numLeavesByStatus = {};
- var test = this.pathTestMap[path];
var allPaths = [];
function countLeaves(test) {
allPaths.push(test.path);
@@ -975,8 +1007,10 @@
goog.events.listen(menu, goog.ui.Component.EventType.HIDE,
function(event) {
menu.dispose();
- this.contextMenuVisible = false;
+ this.contextMenu = null;
+ this.lastContextMenuHideTime = goog.now();
}, true, this);
+ return true;
};
/**
@@ -994,7 +1028,7 @@
tooltip.setHtml('')
var errorMsg = test.state['error_msg'];
- if (test.state.status != 'FAILED' || this.contextMenuVisible || !errorMsg) {
+ if (test.state.status != 'FAILED' || this.contextMenu || !errorMsg) {
// Don't bother showing it.
event.preventDefault();
} else {
@@ -1063,9 +1097,11 @@
goog.events.listen(
labelElement, goog.events.EventType.MOUSEDOWN,
function(event) {
- this.showTestPopup(path, labelElement);
- event.stopPropagation();
- event.preventDefault();
+ if (event.button == 0) {
+ this.showTestPopup(path, labelElement);
+ event.stopPropagation();
+ event.preventDefault();
+ }
}, true, this);
}, this);
@@ -1081,6 +1117,12 @@
document.getElementById('goofy-title'),
eventType,
function(event) {
+ if (eventType == goog.events.EventType.MOUSEDOWN &&
+ event.button != 0) {
+ // Only process primary button for MOUSEDOWN.
+ return;
+ }
+
var updateItem = new goog.ui.MenuItem(
cros.factory.Content('Update factory software',
'更新工廠軟體'));
@@ -1137,6 +1179,15 @@
}),
'goofy-status-' + state.status.toLowerCase());
+ var visible = /** @type boolean */(state.visible);
+ goog.dom.classes.enable(elt, 'goofy-test-visible', visible);
+ goog.object.forEach(this.invocations, function(invoc, uuid) {
+ if (invoc.path == path) {
+ goog.dom.classes.enable(invoc.iframe,
+ 'goofy-test-visible', visible);
+ }
+ }, this);
+
if (state.status == 'ACTIVE') {
// Automatically show the test if it is running.
node.reveal();
diff --git a/py/goofy/static/goofy.css b/py/goofy/static/goofy.css
index f11a328..d7c9e97 100644
--- a/py/goofy/static/goofy.css
+++ b/py/goofy/static/goofy.css
@@ -76,16 +76,6 @@
#goofy-console {
padding: .5em;
}
-#goofy-main {
- left: 0; top: 0;
- width: 100%; height: 100%;
-}
-#goofy-main iframe {
- position: absolute;
- left: 0; top: 0;
- width: 100%; height: 100%;
- padding: .5em;
-}
/* Overrides for status bar. */
#goofy-status-bar {
@@ -195,6 +185,9 @@
vertical-align: -2px;
width: 16px; height: 16px;
}
+.goofy-test-visible .goog-tree-item-label {
+ background-color: red;
+}
.goofy-status-passed > div > .goofy-test-icon {
background-image: url(images/passed.gif);
}
@@ -267,6 +260,21 @@
font-style: italic;
}
+/* Elements in the main pane. */
+#goofy-main {
+ left: 0; top: 0;
+ width: 100%; height: 100%;
+}
+.goofy-test-iframe {
+ position: absolute;
+ left: 0; top: 0;
+ width: 100%; height: 100%;
+ padding: .5em;
+ display: none;
+}
+.goofy-test-iframe.goofy-test-visible {
+ display: inline;
+}
/* Elements in the console pane. */
.goofy-internal-log {
font-style: italic;
@@ -314,12 +322,17 @@
}
#goofy-control .goog-tree-item-label {
margin-left: 2px;
+ cursor: pointer;
}
#goofy-control .goog-tree-expand-icon {
vertical-align: -1px;
}
-/* Use same color, whether or not it's focused. */
-#goofy-control .selected .goog-tree-item-label {
+/* No background for any tree items in the control pane. */
+#goofy-control .goog-tree-item-label {
+ background-color: transparent;
+}
+/* Add a background for the visible test. */
+#goofy-control .goofy-test-visible .goog-tree-item-label {
background-color: #cddff0;
}
.modal-dialog-bg {
diff --git a/py/test/ui.py b/py/test/ui.py
index a3c4ef7..61d7f14 100755
--- a/py/test/ui.py
+++ b/py/test/ui.py
@@ -501,9 +501,11 @@
def handle_event(event):
if (event.type == Event.Type.STATE_CHANGE and
- test_path and event.path == test_path and
- event.state.visible):
- show_window()
+ test_path and event.path == test_path):
+ if event.state.visible:
+ show_window()
+ else:
+ window.hide()
event_client = EventClient(
callback=handle_event, event_loop=EventClient.EVENT_LOOP_GOBJECT_IO)