blob: 96c7d453d3937cafecfb63e8a695cf503227c1b5 [file] [log] [blame]
<!DOCTYPE html>
<!--
Copyright (c) 2013 The Chromium Authors. All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<link rel="import" href="/core/filter.html">
<link rel="import" href="/base/utils.html">
<link rel="import" href="/base/ui/overlay.html">
<link rel="import" href="/base/ui/dom_helpers.html">
<link rel="import" href="/base/ui/info_bar_group.html">
<template id="record-selection-dialog-template">
<style>
.categories-column-view {
display: -webkit-flex;
-webkit-flex-direction: column;
font-family: sans-serif;
max-width: 640px;
min-height: 0;
min-width: 0;
opacity: 1;
transition: max-height 1s ease, max-width 1s ease, opacity 1s ease;
will-change: opacity;
}
.categories-column-view-hidden {
max-height: 0;
max-width: 0;
opacity: 0;
overflow: hidden;
}
.categories-selection {
display: -webkit-flex;
-webkit-flex-direction: row;
}
.category-presets {
padding: 4px;
}
.category-description {
color: #aaa;
font-size: small;
max-height: 1em;
opacity: 1;
padding-left: 4px;
padding-right: 4px;
text-align: right;
transition: max-height 1s ease, opacity 1s ease;
will-change: opacity;
}
.category-description-hidden {
max-height: 0;
opacity: 0;
}
.default-enabled-categories,
.default-disabled-categories {
-webkit-flex: 1 1 auto;
display: -webkit-flex;
-webkit-flex-direction: column;
padding: 4px;
width: 300px;
}
.default-enabled-categories > div,
.default-disabled-categories > div {
padding: 4px;
}
.tracing-modes {
-webkit-flex: 1 0 auto;
display: -webkit-flex;
-webkit-flex-direction: reverse;
padding: 4px;
border-bottom: 2px solid #ddd;
border-top: 2px solid #ddd;
}
.default-disabled-categories {
border-left: 2px solid #ddd;
}
.warning-default-disabled-categories {
display: inline-block;
font-weight: bold;
text-align: center;
color: #BD2E2E;
width: 2.0ex;
height: 2.0ex;
border-radius: 2.0ex;
border: 1px solid #BD2E2E;
}
.categories {
font-size: 80%;
padding: 10px;
-webkit-flex: 1 1 auto;
}
.group-selectors {
font-size: 80%;
border-bottom: 1px solid #ddd;
padding-bottom: 6px;
-webkit-flex: 0 0 auto;
}
.group-selectors button {
padding: 1px;
}
</style>
<div class="record-selection-dialog">
<tr-b-ui-info-bar-group></tr-b-ui-info-bar-group>
<div class="category-presets">
</div>
<div class="category-description"></div>
<div class="categories-column-view">
<div class="tracing-modes"></div>
<div class="categories-selection">
<div class="default-enabled-categories">
<div>Record&nbsp;Categories</div>
<div class="group-selectors">
Select
<button class="all-btn">All</button>
<button class="none-btn">None</button>
</div>
<div class="categories"></div>
</div>
<div class="default-disabled-categories">
<div>Disabled&nbsp;by&nbsp;Default&nbsp;Categories
<a class="warning-default-disabled-categories">!</a>
</div>
<div class="group-selectors">
Select
<button class="all-btn">All</button>
<button class="none-btn">None</button>
</div>
<div class="categories"></div>
</div>
</div>
</div>
</div>
</template>
<script>
'use strict';
/**
* @fileoverview RecordSelectionDialog presents the available categories
* to be enabled/disabled during tr.c.
*/
tr.exportTo('tr.e.about_tracing', function() {
var THIS_DOC = document.currentScript.ownerDocument;
var RecordSelectionDialog = tr.b.ui.define('div');
var DEFAULT_PRESETS = [
{title: 'Web developer',
categoryFilter: ['blink', 'cc', 'netlog', 'renderer.scheduler',
'toplevel', 'v8']},
{title: 'Input latency',
categoryFilter: ['benchmark', 'input', 'evdev', 'renderer.scheduler',
'toplevel']},
{title: 'Rendering',
categoryFilter: ['blink', 'cc', 'gpu', 'toplevel']},
{title: 'Javascript and rendering',
categoryFilter: ['blink', 'cc', 'gpu', 'renderer.scheduler', 'v8',
'toplevel']},
{title: 'Frame Viewer',
categoryFilter: ['blink', 'cc', 'gpu', 'renderer.scheduler', 'v8',
'toplevel',
'disabled-by-default-cc.debug',
'disabled-by-default-cc.debug.picture']},
{title: 'Manually select settings',
categoryFilter: []}
];
var RECORDING_MODES = [
{'label': 'Record until full',
'value': 'record-until-full'},
{'label': 'Record continuously',
'value': 'record-continuously'},
{'label': 'Record as much as possible',
'value': 'record-as-much-as-possible'}];
var DEFAULT_RECORD_MODE = 'record-until-full';
var DEFAULT_CONTINUOUS_TRACING = true;
var DEFAULT_SYSTEM_TRACING = false;
var DEFAULT_SAMPLING_TRACING = false;
RecordSelectionDialog.prototype = {
__proto__: tr.b.ui.Overlay.prototype,
decorate: function() {
tr.b.ui.Overlay.prototype.decorate.call(this);
this.title = 'Record a new trace...';
this.classList.add('record-dialog-overlay');
var node = tr.b.instantiateTemplate('#record-selection-dialog-template',
THIS_DOC);
this.appendChild(node);
this.recordButtonEl_ = document.createElement('button');
this.recordButtonEl_.textContent = 'Record';
this.recordButtonEl_.addEventListener(
'click',
this.onRecordButtonClicked_.bind(this));
this.recordButtonEl_.style.fontSize = '110%';
this.buttons.appendChild(this.recordButtonEl_);
this.categoriesView_ = this.querySelector('.categories-column-view');
this.presetsEl_ = this.querySelector('.category-presets');
this.presetsEl_.appendChild(tr.b.ui.createOptionGroup(
this, 'currentlyChosenPreset',
'about_tracing.record_selection_dialog_preset',
DEFAULT_PRESETS[0].categoryFilter,
DEFAULT_PRESETS.map(function(p) {
return { label: p.title, value: p.categoryFilter };
})));
this.tracingRecordModeSltr_ = tr.b.ui.createSelector(
this, 'tracingRecordMode',
'recordSelectionDialog.tracingRecordMode',
DEFAULT_RECORD_MODE, RECORDING_MODES);
this.systemTracingBn_ = tr.b.ui.createCheckBox(
undefined, undefined,
'recordSelectionDialog.useSystemTracing', true,
'System tracing');
this.samplingTracingBn_ = tr.b.ui.createCheckBox(
undefined, undefined,
'recordSelectionDialog.useSampling', false,
'State sampling');
this.tracingModesContainerEl_ = this.querySelector('.tracing-modes');
this.tracingModesContainerEl_.appendChild(this.tracingRecordModeSltr_);
this.tracingModesContainerEl_.appendChild(this.systemTracingBn_);
this.tracingModesContainerEl_.appendChild(this.samplingTracingBn_);
this.enabledCategoriesContainerEl_ =
this.querySelector('.default-enabled-categories .categories');
this.disabledCategoriesContainerEl_ =
this.querySelector('.default-disabled-categories .categories');
this.createGroupSelectButtons_(
this.querySelector('.default-enabled-categories'));
this.createGroupSelectButtons_(
this.querySelector('.default-disabled-categories'));
this.createDefaultDisabledWarningDialog_(
this.querySelector('.warning-default-disabled-categories'));
this.editCategoriesOpened_ = false;
// TODO(chrishenry): When used with tr.b.ui.Overlay (such as in
// chrome://tracing, this does not yet look quite right due to
// the 10px overlay content padding (but it's good enough).
this.infoBarGroup_ = this.querySelector('tr-b-ui-info-bar-group');
this.addEventListener('visibleChange', this.onVisibleChange_.bind(this));
},
set supportsSystemTracing(s) {
if (s) {
this.systemTracingBn_.style.display = undefined;
} else {
this.systemTracingBn_.style.display = 'none';
this.useSystemTracing = false;
}
},
get tracingRecordMode() {
if (this.usingPreset_())
return DEFAULT_RECORD_MODE;
return this.tracingRecordModeSltr_.selectedValue;
},
set tracingRecordMode(value) {
this.tracingRecordMode_ = value;
},
get useSystemTracing() {
if (this.usingPreset_())
return DEFAULT_SYSTEM_TRACING;
return this.systemTracingBn_.checked;
},
set useSystemTracing(value) {
this.systemTracingBn_.checked = !!value;
},
get useSampling() {
if (this.usingPreset_())
return DEFAULT_SAMPLING_TRACING;
return this.samplingTracingBn_.checked;
},
set useSampling(value) {
this.samplingTracingBn_.checked = !!value;
},
set categories(c) {
this.categories_ = c;
for (var i = 0; i < this.categories_.length; i++) {
var split = this.categories_[i].split(',');
this.categories_[i] = split.shift();
if (split.length > 0)
this.categories_ = this.categories_.concat(split);
}
},
set settings_key(k) {
this.settings_key_ = k;
},
set settings(s) {
throw new Error('Dont use this!');
},
usingPreset_: function() {
return this.currentlyChosenPreset_.length > 0 ||
this.isPresetSelected_;
},
get currentlyChosenPreset() {
return this.currentlyChosenPreset_;
},
set currentlyChosenPreset(preset) {
if (!(preset instanceof Array))
throw new Error('RecordSelectionDialog.currentlyChosenPreset:' +
' preset must be an array.');
this.currentlyChosenPreset_ = preset;
this.isPresetSelected_ = false;
if (this.currentlyChosenPreset_.length) {
this.isPresetSelected_ = true;
this.changeEditCategoriesState_(false);
} else {
this.updateCategoryColumnView_(true);
this.changeEditCategoriesState_(true);
}
this.updateManualSelectionView_();
this.updatePresetDescription_();
},
updateManualSelectionView_: function() {
var classList = this.categoriesView_.classList;
if (!this.usingPreset_()) {
classList.remove('categories-column-view-hidden');
} else {
if (this.editCategoriesOpened_)
classList.remove('categories-column-view-hidden');
else
classList.add('categories-column-view-hidden');
}
},
updateCategoryColumnView_: function(shouldReadFromSettings) {
var categorySet = this.querySelectorAll('.categories');
for (var i = 0; i < categorySet.length; ++i) {
var categoryGroup = categorySet[i].children;
for (var j = 0; j < categoryGroup.length; ++j) {
var categoryEl = categoryGroup[j].children[0];
categoryEl.checked = shouldReadFromSettings ?
tr.b.Settings.get(categoryEl.value, false, this.settings_key_) :
false;
}
}
},
onClickEditCategories: function() {
if (!this.usingPreset_())
return;
if (!this.editCategoriesOpened_) {
this.updateCategoryColumnView_(false);
for (var i = 0; i < this.currentlyChosenPreset_.length; ++i) {
var categoryEl = document.getElementById(
this.currentlyChosenPreset_[i]);
if (!categoryEl)
continue;
categoryEl.checked = true;
}
}
this.changeEditCategoriesState_(!this.editCategoriesOpened_);
this.updateManualSelectionView_();
this.recordButtonEl_.focus();
},
changeEditCategoriesState_: function(editCategoriesState) {
var presetOptionsGroup = this.querySelector('.labeled-option-group');
if (!presetOptionsGroup)
return;
this.editCategoriesOpened_ = editCategoriesState;
if (this.editCategoriesOpened_)
presetOptionsGroup.classList.add('categories-expanded');
else
presetOptionsGroup.classList.remove('categories-expanded');
},
updatePresetDescription_: function() {
var description = this.querySelector('.category-description');
if (this.usingPreset_()) {
description.innerText = this.currentlyChosenPreset_;
description.classList.remove('category-description-hidden');
} else {
description.innerText = '';
if (!description.classList.contains('category-description-hidden'))
description.classList.add('category-description-hidden');
}
},
categoryFilter: function() {
if (this.usingPreset_()) {
var categories = [];
var allCategories = this.allCategories_();
for (var category in allCategories) {
var disabled = category.indexOf('disabled-by-default-') == 0;
if (this.currentlyChosenPreset_.indexOf(category) >= 0) {
if (disabled)
categories.push(category);
} else {
if (!disabled)
categories.push('-' + category);
}
}
return categories.join(',');
}
var categories = this.unselectedCategories_();
var categories_length = categories.length;
var negated_categories = [];
for (var i = 0; i < categories_length; ++i) {
// Skip any category with a , as it will cause issues when we negate.
// Both sides should have been added as separate categories, these can
// only come from settings.
if (categories[i].match(/,/))
continue;
negated_categories.push('-' + categories[i]);
}
categories = negated_categories.join(',');
var disabledCategories = this.enabledDisabledByDefaultCategories_();
disabledCategories = disabledCategories.join(',');
var results = [];
if (categories !== '')
results.push(categories);
if (disabledCategories !== '')
results.push(disabledCategories);
return results.join(',');
},
clickRecordButton: function() {
this.recordButtonEl_.click();
},
onRecordButtonClicked_: function() {
this.visible = false;
tr.b.dispatchSimpleEvent(this, 'recordclick');
return false;
},
collectInputs_: function(inputs, isChecked) {
var inputs_length = inputs.length;
var categories = [];
for (var i = 0; i < inputs_length; ++i) {
var input = inputs[i];
if (input.checked === isChecked)
categories.push(input.value);
}
return categories;
},
unselectedCategories_: function() {
var inputs =
this.enabledCategoriesContainerEl_.querySelectorAll('input');
return this.collectInputs_(inputs, false);
},
enabledDisabledByDefaultCategories_: function() {
var inputs =
this.disabledCategoriesContainerEl_.querySelectorAll('input');
return this.collectInputs_(inputs, true);
},
onVisibleChange_: function() {
if (this.visible)
this.updateForm_();
},
buildInputs_: function(inputs, checkedDefault, parent) {
var inputs_length = inputs.length;
for (var i = 0; i < inputs_length; i++) {
var category = inputs[i];
var inputEl = document.createElement('input');
inputEl.type = 'checkbox';
inputEl.id = category;
inputEl.value = category;
inputEl.checked = tr.b.Settings.get(
category, checkedDefault, this.settings_key_);
inputEl.onclick = this.updateSetting_.bind(this);
var labelEl = document.createElement('label');
labelEl.textContent = category.replace('disabled-by-default-', '');
labelEl.setAttribute('for', category);
var divEl = document.createElement('div');
divEl.appendChild(inputEl);
divEl.appendChild(labelEl);
parent.appendChild(divEl);
}
},
allCategories_: function() {
// Dedup the categories. We may have things in settings that are also
// returned when we query the category list.
var categorySet = {};
var allCategories =
this.categories_.concat(tr.b.Settings.keys(this.settings_key_));
var allCategoriesLength = allCategories.length;
for (var i = 0; i < allCategoriesLength; ++i)
categorySet[allCategories[i]] = true;
return categorySet;
},
updateForm_: function() {
this.enabledCategoriesContainerEl_.innerHTML = ''; // Clear old categories
this.disabledCategoriesContainerEl_.innerHTML = '';
this.recordButtonEl_.focus();
var allCategories = this.allCategories_();
var categories = [];
var disabledCategories = [];
for (var category in allCategories) {
if (category.indexOf('disabled-by-default-') == 0)
disabledCategories.push(category);
else
categories.push(category);
}
disabledCategories = disabledCategories.sort();
categories = categories.sort();
if (this.categories_.length == 0) {
this.infoBarGroup_.addMessage(
'No categories found; recording will use default categories.');
}
this.buildInputs_(categories, true, this.enabledCategoriesContainerEl_);
if (disabledCategories.length > 0) {
this.disabledCategoriesContainerEl_.hidden = false;
this.buildInputs_(disabledCategories, false,
this.disabledCategoriesContainerEl_);
}
},
updateSetting_: function(e) {
var checkbox = e.target;
tr.b.Settings.set(checkbox.value, checkbox.checked, this.settings_key_);
// Change the current record mode to 'Manually select settings' from
// preset mode if and only if currently user is in preset record mode
// and user selects/deselects any category in 'Edit Categories' mode.
if (this.usingPreset_()) {
if (checkbox.checked) {
this.currentlyChosenPreset_.push(checkbox.value);
} else {
var pos = this.currentlyChosenPreset_.lastIndexOf(checkbox.value);
this.currentlyChosenPreset_.splice(pos, 1);
}
var categoryEl = document.getElementById(
'category-preset-Manually-select-settings');
categoryEl.checked = true;
var description = this.querySelector('.category-description');
description.innerText = '';
description.classList.add('category-description-hidden');
}
},
createGroupSelectButtons_: function(parent) {
var flipInputs = function(dir) {
var inputs = parent.querySelectorAll('input');
for (var i = 0; i < inputs.length; i++) {
if (inputs[i].checked === dir)
continue;
// click() is used so the settings will be correclty stored. Setting
// checked does not trigger the onclick (or onchange) callback.
inputs[i].click();
}
};
var allBtn = parent.querySelector('.all-btn');
allBtn.onclick = function(evt) {
flipInputs(true);
evt.preventDefault();
};
var noneBtn = parent.querySelector('.none-btn');
noneBtn.onclick = function(evt) {
flipInputs(false);
evt.preventDefault();
};
},
setWarningDialogOverlayText_: function(messages) {
var contentDiv = document.createElement('div');
for (var i = 0; i < messages.length; ++i) {
var messageDiv = document.createElement('div');
messageDiv.textContent = messages[i];
contentDiv.appendChild(messageDiv);
}
this.warningOverlay_.textContent = '';
this.warningOverlay_.appendChild(contentDiv);
},
createDefaultDisabledWarningDialog_: function(warningLink) {
function onClickHandler(evt) {
this.warningOverlay_ = tr.b.ui.Overlay();
this.warningOverlay_.parentEl_ = this;
this.warningOverlay_.title = 'Warning...';
this.warningOverlay_.userCanClose = true;
this.warningOverlay_.visible = true;
this.setWarningDialogOverlayText_([
'Enabling the default disabled categories may have',
'performance and memory impact while tr.c.'
]);
evt.preventDefault();
}
warningLink.onclick = onClickHandler.bind(this);
}
};
return {
RecordSelectionDialog: RecordSelectionDialog
};
});
</script>