summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/inspector/front-end/ProfilesPanel.js
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/inspector/front-end/ProfilesPanel.js')
-rw-r--r--Source/WebCore/inspector/front-end/ProfilesPanel.js723
1 files changed, 723 insertions, 0 deletions
diff --git a/Source/WebCore/inspector/front-end/ProfilesPanel.js b/Source/WebCore/inspector/front-end/ProfilesPanel.js
new file mode 100644
index 0000000..bff5be7
--- /dev/null
+++ b/Source/WebCore/inspector/front-end/ProfilesPanel.js
@@ -0,0 +1,723 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+const UserInitiatedProfileName = "org.webkit.profiles.user-initiated";
+
+WebInspector.ProfileType = function(id, name)
+{
+ this._id = id;
+ this._name = name;
+}
+
+WebInspector.ProfileType.URLRegExp = /webkit-profile:\/\/(.+)\/(.+)#([0-9]+)/;
+
+WebInspector.ProfileType.prototype = {
+ get buttonTooltip()
+ {
+ return "";
+ },
+
+ get buttonStyle()
+ {
+ return undefined;
+ },
+
+ get buttonCaption()
+ {
+ return this.name;
+ },
+
+ get id()
+ {
+ return this._id;
+ },
+
+ get name()
+ {
+ return this._name;
+ },
+
+ buttonClicked: function()
+ {
+ },
+
+ viewForProfile: function(profile)
+ {
+ if (!profile._profileView)
+ profile._profileView = this.createView(profile);
+ return profile._profileView;
+ },
+
+ get welcomeMessage()
+ {
+ return "";
+ },
+
+ // Must be implemented by subclasses.
+ createView: function(profile)
+ {
+ throw new Error("Needs implemented.");
+ },
+
+ // Must be implemented by subclasses.
+ createSidebarTreeElementForProfile: function(profile)
+ {
+ throw new Error("Needs implemented.");
+ }
+}
+
+WebInspector.ProfilesPanel = function()
+{
+ WebInspector.Panel.call(this, "profiles");
+
+ this.createSidebar();
+
+ this._profileTypesByIdMap = {};
+ this._profileTypeButtonsByIdMap = {};
+
+ var panelEnablerHeading = WebInspector.UIString("You need to enable profiling before you can use the Profiles panel.");
+ var panelEnablerDisclaimer = WebInspector.UIString("Enabling profiling will make scripts run slower.");
+ var panelEnablerButton = WebInspector.UIString("Enable Profiling");
+ this.panelEnablerView = new WebInspector.PanelEnablerView("profiles", panelEnablerHeading, panelEnablerDisclaimer, panelEnablerButton);
+ this.panelEnablerView.addEventListener("enable clicked", this._enableProfiling, this);
+
+ this.element.appendChild(this.panelEnablerView.element);
+
+ this.profileViews = document.createElement("div");
+ this.profileViews.id = "profile-views";
+ this.element.appendChild(this.profileViews);
+
+ this.enableToggleButton = new WebInspector.StatusBarButton("", "enable-toggle-status-bar-item");
+ this.enableToggleButton.addEventListener("click", this._toggleProfiling.bind(this), false);
+
+ this.clearResultsButton = new WebInspector.StatusBarButton(WebInspector.UIString("Clear CPU profiles."), "clear-status-bar-item");
+ this.clearResultsButton.addEventListener("click", this._clearProfiles.bind(this), false);
+
+ this.profileViewStatusBarItemsContainer = document.createElement("div");
+ this.profileViewStatusBarItemsContainer.className = "status-bar-items";
+
+ this.welcomeView = new WebInspector.WelcomeView("profiles", WebInspector.UIString("Welcome to the Profiles panel"));
+ this.element.appendChild(this.welcomeView.element);
+
+ this._profiles = [];
+ this._profilerEnabled = Preferences.profilerAlwaysEnabled;
+ this._reset();
+ InspectorBackend.registerDomainDispatcher("Profiler", this);
+}
+
+WebInspector.ProfilesPanel.prototype = {
+ get toolbarItemLabel()
+ {
+ return WebInspector.UIString("Profiles");
+ },
+
+ get statusBarItems()
+ {
+ function clickHandler(profileType, buttonElement)
+ {
+ profileType.buttonClicked.call(profileType);
+ this.updateProfileTypeButtons();
+ }
+
+ var items = [this.enableToggleButton.element];
+ // FIXME: Generate a single "combo-button".
+ for (var typeId in this._profileTypesByIdMap) {
+ var profileType = this.getProfileType(typeId);
+ if (profileType.buttonStyle) {
+ var button = new WebInspector.StatusBarButton(profileType.buttonTooltip, profileType.buttonStyle, profileType.buttonCaption);
+ this._profileTypeButtonsByIdMap[typeId] = button.element;
+ button.element.addEventListener("click", clickHandler.bind(this, profileType, button.element), false);
+ items.push(button.element);
+ }
+ }
+ items.push(this.clearResultsButton.element, this.profileViewStatusBarItemsContainer);
+ return items;
+ },
+
+ show: function()
+ {
+ WebInspector.Panel.prototype.show.call(this);
+ this._populateProfiles();
+ },
+
+ profilerWasEnabled: function()
+ {
+ if (this._profilerEnabled)
+ return;
+
+ this._profilerEnabled = true;
+
+ this._reset();
+ if (this.visible)
+ this._populateProfiles();
+ },
+
+ profilerWasDisabled: function()
+ {
+ if (!this._profilerEnabled)
+ return;
+
+ this._profilerEnabled = false;
+ this._reset();
+ },
+
+ resetProfiles: function()
+ {
+ this._reset();
+ },
+
+ _reset: function()
+ {
+ for (var i = 0; i < this._profiles.length; ++i)
+ delete this._profiles[i]._profileView;
+ delete this.visibleView;
+
+ delete this.currentQuery;
+ this.searchCanceled();
+
+ this._profiles = [];
+ this._profilesIdMap = {};
+ this._profileGroups = {};
+ this._profileGroupsForLinks = {}
+ this._profilesWereRequested = false;
+
+ this.sidebarTreeElement.removeStyleClass("some-expandable");
+
+ for (var typeId in this._profileTypesByIdMap)
+ this.getProfileType(typeId).treeElement.removeChildren();
+
+ this.profileViews.removeChildren();
+
+ this.profileViewStatusBarItemsContainer.removeChildren();
+
+ this.removeAllListeners();
+
+ this._updateInterface();
+ this.welcomeView.show();
+ },
+
+ _clearProfiles: function()
+ {
+ InspectorBackend.clearProfiles();
+ this._reset();
+ },
+
+ registerProfileType: function(profileType)
+ {
+ this._profileTypesByIdMap[profileType.id] = profileType;
+ profileType.treeElement = new WebInspector.SidebarSectionTreeElement(profileType.name, null, true);
+ this.sidebarTree.appendChild(profileType.treeElement);
+ profileType.treeElement.expand();
+ this._addWelcomeMessage(profileType);
+ },
+
+ _addWelcomeMessage: function(profileType)
+ {
+ var message = profileType.welcomeMessage;
+ // Message text is supposed to have a '%s' substring as a placeholder
+ // for a status bar button. If it is there, we split the message in two
+ // parts, and insert the button between them.
+ var buttonPos = message.indexOf("%s");
+ if (buttonPos > -1) {
+ var container = document.createDocumentFragment();
+ var part1 = document.createElement("span");
+ part1.innerHTML = message.substr(0, buttonPos);
+ container.appendChild(part1);
+
+ var button = new WebInspector.StatusBarButton(profileType.buttonTooltip, profileType.buttonStyle, profileType.buttonCaption);
+ container.appendChild(button.element);
+
+ var part2 = document.createElement("span");
+ part2.innerHTML = message.substr(buttonPos + 2);
+ container.appendChild(part2);
+ this.welcomeView.addMessage(container);
+ } else
+ this.welcomeView.addMessage(message);
+ },
+
+ _makeKey: function(text, profileTypeId)
+ {
+ return escape(text) + '/' + escape(profileTypeId);
+ },
+
+ addProfileHeader: function(profile)
+ {
+ var typeId = profile.typeId;
+ var profileType = this.getProfileType(typeId);
+ var sidebarParent = profileType.treeElement;
+ var small = false;
+ var alternateTitle;
+
+ profile.__profilesPanelProfileType = profileType;
+ this._profiles.push(profile);
+ this._profilesIdMap[this._makeKey(profile.uid, typeId)] = profile;
+
+ if (profile.title.indexOf(UserInitiatedProfileName) !== 0) {
+ var profileTitleKey = this._makeKey(profile.title, typeId);
+ if (!(profileTitleKey in this._profileGroups))
+ this._profileGroups[profileTitleKey] = [];
+
+ var group = this._profileGroups[profileTitleKey];
+ group.push(profile);
+
+ if (group.length === 2) {
+ // Make a group TreeElement now that there are 2 profiles.
+ group._profilesTreeElement = new WebInspector.ProfileGroupSidebarTreeElement(profile.title);
+
+ // Insert at the same index for the first profile of the group.
+ var index = sidebarParent.children.indexOf(group[0]._profilesTreeElement);
+ sidebarParent.insertChild(group._profilesTreeElement, index);
+
+ // Move the first profile to the group.
+ var selected = group[0]._profilesTreeElement.selected;
+ sidebarParent.removeChild(group[0]._profilesTreeElement);
+ group._profilesTreeElement.appendChild(group[0]._profilesTreeElement);
+ if (selected) {
+ group[0]._profilesTreeElement.select();
+ group[0]._profilesTreeElement.reveal();
+ }
+
+ group[0]._profilesTreeElement.small = true;
+ group[0]._profilesTreeElement.mainTitle = WebInspector.UIString("Run %d", 1);
+
+ this.sidebarTreeElement.addStyleClass("some-expandable");
+ }
+
+ if (group.length >= 2) {
+ sidebarParent = group._profilesTreeElement;
+ alternateTitle = WebInspector.UIString("Run %d", group.length);
+ small = true;
+ }
+ }
+
+ var profileTreeElement = profileType.createSidebarTreeElementForProfile(profile);
+ profileTreeElement.small = small;
+ if (alternateTitle)
+ profileTreeElement.mainTitle = alternateTitle;
+ profile._profilesTreeElement = profileTreeElement;
+
+ sidebarParent.appendChild(profileTreeElement);
+ if (!profile.isTemporary) {
+ this.welcomeView.hide();
+ if (!this.visibleView)
+ this.showProfile(profile);
+ this.dispatchEventToListeners("profile added");
+ }
+ },
+
+ removeProfileHeader: function(profile)
+ {
+ var typeId = profile.typeId;
+ var profileType = this.getProfileType(typeId);
+ var sidebarParent = profileType.treeElement;
+
+ for (var i = 0; i < this._profiles.length; ++i) {
+ if (this._profiles[i].uid === profile.uid) {
+ profile = this._profiles[i];
+ this._profiles.splice(i, 1);
+ break;
+ }
+ }
+ delete this._profilesIdMap[this._makeKey(profile.uid, typeId)];
+
+ var profileTitleKey = this._makeKey(profile.title, typeId);
+ delete this._profileGroups[profileTitleKey];
+
+ sidebarParent.removeChild(profile._profilesTreeElement);
+
+ if (!profile.isTemporary)
+ InspectorBackend.removeProfile(profile.typeId, profile.uid);
+
+ // No other item will be selected if there aren't any other profiles, so
+ // make sure that view gets cleared when the last profile is removed.
+ if (!this._profiles.length)
+ this.closeVisibleView();
+ },
+
+ showProfile: function(profile)
+ {
+ if (!profile || profile.isTemporary)
+ return;
+
+ this.closeVisibleView();
+
+ var view = profile.__profilesPanelProfileType.viewForProfile(profile);
+
+ view.show(this.profileViews);
+
+ profile._profilesTreeElement.select(true);
+ profile._profilesTreeElement.reveal();
+
+ this.visibleView = view;
+
+ this.profileViewStatusBarItemsContainer.removeChildren();
+
+ var statusBarItems = view.statusBarItems;
+ for (var i = 0; i < statusBarItems.length; ++i)
+ this.profileViewStatusBarItemsContainer.appendChild(statusBarItems[i]);
+ },
+
+ getProfiles: function(typeId)
+ {
+ var result = [];
+ var profilesCount = this._profiles.length;
+ for (var i = 0; i < profilesCount; ++i)
+ if (this._profiles[i].typeId === typeId)
+ result.push(this._profiles[i]);
+ return result;
+ },
+
+ hasTemporaryProfile: function(typeId)
+ {
+ var profilesCount = this._profiles.length;
+ for (var i = 0; i < profilesCount; ++i)
+ if (this._profiles[i].typeId === typeId && this._profiles[i].isTemporary)
+ return true;
+ return false;
+ },
+
+ hasProfile: function(profile)
+ {
+ return !!this._profilesIdMap[this._makeKey(profile.uid, profile.typeId)];
+ },
+
+ updateProfile: function(profile)
+ {
+ var profilesCount = this._profiles.length;
+ for (var i = 0; i < profilesCount; ++i)
+ if (this._profiles[i].typeId === profile.typeId
+ && this._profiles[i].uid === profile.uid) {
+ this._profiles[i] = profile;
+ break;
+ }
+ },
+
+ loadHeapSnapshot: function(uid, callback)
+ {
+ var profile = this._profilesIdMap[this._makeKey(uid, WebInspector.HeapSnapshotProfileType.TypeId)];
+ if (!profile)
+ return;
+
+ if (profile._loaded)
+ callback(profile);
+ else if (profile._is_loading)
+ profile._callbacks.push(callback);
+ else {
+ profile._is_loading = true;
+ profile._callbacks = [callback];
+ profile._json = "";
+ InspectorBackend.getProfile(profile.typeId, profile.uid);
+ }
+ },
+
+ addHeapSnapshotChunk: function(uid, chunk)
+ {
+ var profile = this._profilesIdMap[this._makeKey(uid, WebInspector.HeapSnapshotProfileType.TypeId)];
+ if (!profile || profile._loaded || !profile._is_loading)
+ return;
+
+ profile._json += chunk;
+ },
+
+ finishHeapSnapshot: function(uid)
+ {
+ var profile = this._profilesIdMap[this._makeKey(uid, WebInspector.HeapSnapshotProfileType.TypeId)];
+ if (!profile || profile._loaded || !profile._is_loading)
+ return;
+
+ var callbacks = profile._callbacks;
+ delete profile._callbacks;
+ var loadedSnapshot = JSON.parse(profile._json);
+ delete profile._json;
+ delete profile._is_loading;
+ profile._loaded = true;
+ WebInspector.HeapSnapshotView.prototype.processLoadedSnapshot(profile, loadedSnapshot);
+ for (var i = 0; i < callbacks.length; ++i)
+ callbacks[i](profile);
+ },
+
+ showView: function(view)
+ {
+ this.showProfile(view.profile);
+ },
+
+ getProfileType: function(typeId)
+ {
+ return this._profileTypesByIdMap[typeId];
+ },
+
+ showProfileForURL: function(url)
+ {
+ var match = url.match(WebInspector.ProfileType.URLRegExp);
+ if (!match)
+ return;
+ this.showProfile(this._profilesIdMap[this._makeKey(match[3], match[1])]);
+ },
+
+ updateProfileTypeButtons: function()
+ {
+ for (var typeId in this._profileTypeButtonsByIdMap) {
+ var buttonElement = this._profileTypeButtonsByIdMap[typeId];
+ var profileType = this.getProfileType(typeId);
+ buttonElement.className = profileType.buttonStyle;
+ buttonElement.title = profileType.buttonTooltip;
+ // FIXME: Apply profileType.buttonCaption once captions are added to button controls.
+ }
+ },
+
+ closeVisibleView: function()
+ {
+ if (this.visibleView)
+ this.visibleView.hide();
+ delete this.visibleView;
+ },
+
+ displayTitleForProfileLink: function(title, typeId)
+ {
+ title = unescape(title);
+ if (title.indexOf(UserInitiatedProfileName) === 0) {
+ title = WebInspector.UIString("Profile %d", title.substring(UserInitiatedProfileName.length + 1));
+ } else {
+ var titleKey = this._makeKey(title, typeId);
+ if (!(titleKey in this._profileGroupsForLinks))
+ this._profileGroupsForLinks[titleKey] = 0;
+
+ var groupNumber = ++this._profileGroupsForLinks[titleKey];
+
+ if (groupNumber > 2)
+ // The title is used in the console message announcing that a profile has started so it gets
+ // incremented twice as often as it's displayed
+ title += " " + WebInspector.UIString("Run %d", (groupNumber + 1) / 2);
+ }
+
+ return title;
+ },
+
+ get searchableViews()
+ {
+ var views = [];
+
+ const visibleView = this.visibleView;
+ if (visibleView && visibleView.performSearch)
+ views.push(visibleView);
+
+ var profilesLength = this._profiles.length;
+ for (var i = 0; i < profilesLength; ++i) {
+ var profile = this._profiles[i];
+ var view = profile.__profilesPanelProfileType.viewForProfile(profile);
+ if (!view.performSearch || view === visibleView)
+ continue;
+ views.push(view);
+ }
+
+ return views;
+ },
+
+ searchMatchFound: function(view, matches)
+ {
+ view.profile._profilesTreeElement.searchMatches = matches;
+ },
+
+ searchCanceled: function(startingNewSearch)
+ {
+ WebInspector.Panel.prototype.searchCanceled.call(this, startingNewSearch);
+
+ if (!this._profiles)
+ return;
+
+ for (var i = 0; i < this._profiles.length; ++i) {
+ var profile = this._profiles[i];
+ profile._profilesTreeElement.searchMatches = 0;
+ }
+ },
+
+ _updateInterface: function()
+ {
+ // FIXME: Replace ProfileType-specific button visibility changes by a single ProfileType-agnostic "combo-button" visibility change.
+ if (this._profilerEnabled) {
+ this.enableToggleButton.title = WebInspector.UIString("Profiling enabled. Click to disable.");
+ this.enableToggleButton.toggled = true;
+ for (var typeId in this._profileTypeButtonsByIdMap)
+ this._profileTypeButtonsByIdMap[typeId].removeStyleClass("hidden");
+ this.profileViewStatusBarItemsContainer.removeStyleClass("hidden");
+ this.clearResultsButton.element.removeStyleClass("hidden");
+ this.panelEnablerView.visible = false;
+ } else {
+ this.enableToggleButton.title = WebInspector.UIString("Profiling disabled. Click to enable.");
+ this.enableToggleButton.toggled = false;
+ for (var typeId in this._profileTypeButtonsByIdMap)
+ this._profileTypeButtonsByIdMap[typeId].addStyleClass("hidden");
+ this.profileViewStatusBarItemsContainer.addStyleClass("hidden");
+ this.clearResultsButton.element.addStyleClass("hidden");
+ this.panelEnablerView.visible = true;
+ }
+ },
+
+ _enableProfiling: function()
+ {
+ if (this._profilerEnabled)
+ return;
+ this._toggleProfiling(this.panelEnablerView.alwaysEnabled);
+ },
+
+ _toggleProfiling: function(optionalAlways)
+ {
+ if (this._profilerEnabled)
+ InspectorBackend.disableProfiler(true);
+ else
+ InspectorBackend.enableProfiler(!!optionalAlways);
+ },
+
+ _populateProfiles: function()
+ {
+ if (!this._profilerEnabled || this._profilesWereRequested)
+ return;
+
+ function populateCallback(profileHeaders) {
+ profileHeaders.sort(function(a, b) { return a.uid - b.uid; });
+ var profileHeadersLength = profileHeaders.length;
+ for (var i = 0; i < profileHeadersLength; ++i)
+ if (!this.hasProfile(profileHeaders[i]))
+ WebInspector.panels.profiles.addProfileHeader(profileHeaders[i]);
+ }
+
+ InspectorBackend.getProfileHeaders(populateCallback.bind(this));
+
+ this._profilesWereRequested = true;
+ },
+
+ updateMainViewWidth: function(width)
+ {
+ this.welcomeView.element.style.left = width + "px";
+ this.profileViews.style.left = width + "px";
+ this.profileViewStatusBarItemsContainer.style.left = Math.max(155, width) + "px";
+ this.resize();
+ },
+
+ setRecordingProfile: function(isProfiling)
+ {
+ this.getProfileType(WebInspector.CPUProfileType.TypeId).setRecordingProfile(isProfiling);
+ if (this.hasTemporaryProfile(WebInspector.CPUProfileType.TypeId) !== isProfiling) {
+ if (!this._temporaryRecordingProfile) {
+ this._temporaryRecordingProfile = {
+ typeId: WebInspector.CPUProfileType.TypeId,
+ title: WebInspector.UIString("Recording"),
+ uid: -1,
+ isTemporary: true
+ };
+ }
+ if (isProfiling)
+ this.addProfileHeader(this._temporaryRecordingProfile);
+ else
+ this.removeProfileHeader(this._temporaryRecordingProfile);
+ }
+ this.updateProfileTypeButtons();
+ }
+}
+
+WebInspector.ProfilesPanel.prototype.__proto__ = WebInspector.Panel.prototype;
+
+WebInspector.ProfileSidebarTreeElement = function(profile, titleFormat, className)
+{
+ this.profile = profile;
+ this._titleFormat = titleFormat;
+
+ if (this.profile.title.indexOf(UserInitiatedProfileName) === 0)
+ this._profileNumber = this.profile.title.substring(UserInitiatedProfileName.length + 1);
+
+ WebInspector.SidebarTreeElement.call(this, className, "", "", profile, false);
+
+ this.refreshTitles();
+}
+
+WebInspector.ProfileSidebarTreeElement.prototype = {
+ onselect: function()
+ {
+ this.treeOutline.panel.showProfile(this.profile);
+ },
+
+ ondelete: function()
+ {
+ this.treeOutline.panel.removeProfileHeader(this.profile);
+ return true;
+ },
+
+ get mainTitle()
+ {
+ if (this._mainTitle)
+ return this._mainTitle;
+ if (this.profile.title.indexOf(UserInitiatedProfileName) === 0)
+ return WebInspector.UIString(this._titleFormat, this._profileNumber);
+ return this.profile.title;
+ },
+
+ set mainTitle(x)
+ {
+ this._mainTitle = x;
+ this.refreshTitles();
+ },
+
+ get subtitle()
+ {
+ // There is no subtitle.
+ },
+
+ set subtitle(x)
+ {
+ // Can't change subtitle.
+ },
+
+ set searchMatches(matches)
+ {
+ if (!matches) {
+ if (!this.bubbleElement)
+ return;
+ this.bubbleElement.removeStyleClass("search-matches");
+ this.bubbleText = "";
+ return;
+ }
+
+ this.bubbleText = matches;
+ this.bubbleElement.addStyleClass("search-matches");
+ }
+}
+
+WebInspector.ProfileSidebarTreeElement.prototype.__proto__ = WebInspector.SidebarTreeElement.prototype;
+
+WebInspector.ProfileGroupSidebarTreeElement = function(title, subtitle)
+{
+ WebInspector.SidebarTreeElement.call(this, "profile-group-sidebar-tree-item", title, subtitle, null, true);
+}
+
+WebInspector.ProfileGroupSidebarTreeElement.prototype = {
+ onselect: function()
+ {
+ if (this.children.length > 0)
+ WebInspector.panels.profiles.showProfile(this.children[this.children.length - 1].profile);
+ }
+}
+
+WebInspector.ProfileGroupSidebarTreeElement.prototype.__proto__ = WebInspector.SidebarTreeElement.prototype;
+