ProfilesPanel.js 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435
  1. /*
  2. * Copyright (C) 2008 Apple Inc. All Rights Reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. * 1. Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * 2. Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. *
  13. * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
  14. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  16. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
  17. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  20. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  21. * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  23. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. const UserInitiatedProfileName = "org.webkit.profiles.user-initiated";
  26. /**
  27. * @constructor
  28. * @extends {WebInspector.Object}
  29. * @param {string} id
  30. * @param {string} name
  31. */
  32. WebInspector.ProfileType = function(id, name)
  33. {
  34. this._id = id;
  35. this._name = name;
  36. /** @type {!Array.<!WebInspector.ProfileHeader>} */
  37. this._profiles = [];
  38. this._profilesIdMap = {};
  39. /** @type {WebInspector.SidebarSectionTreeElement} */
  40. this.treeElement = null;
  41. }
  42. WebInspector.ProfileType.Events = {
  43. AddProfileHeader: "add-profile-header",
  44. RemoveProfileHeader: "remove-profile-header",
  45. ProgressUpdated: "progress-updated",
  46. ViewUpdated: "view-updated"
  47. }
  48. WebInspector.ProfileType.prototype = {
  49. statusBarItems: function()
  50. {
  51. return [];
  52. },
  53. get buttonTooltip()
  54. {
  55. return "";
  56. },
  57. get id()
  58. {
  59. return this._id;
  60. },
  61. get treeItemTitle()
  62. {
  63. return this._name;
  64. },
  65. get name()
  66. {
  67. return this._name;
  68. },
  69. /**
  70. * @return {boolean}
  71. */
  72. buttonClicked: function()
  73. {
  74. return false;
  75. },
  76. get description()
  77. {
  78. return "";
  79. },
  80. /**
  81. * @return {boolean}
  82. */
  83. isInstantProfile: function()
  84. {
  85. return false;
  86. },
  87. /**
  88. * @return {!Array.<!WebInspector.ProfileHeader>}
  89. */
  90. getProfiles: function()
  91. {
  92. return this._profiles.filter(function(profile) { return !profile.isTemporary; });
  93. },
  94. /**
  95. * @return {Element}
  96. */
  97. decorationElement: function()
  98. {
  99. return null;
  100. },
  101. /**
  102. * @nosideeffects
  103. * @param {number} uid
  104. * @return {WebInspector.ProfileHeader}
  105. */
  106. getProfile: function(uid)
  107. {
  108. return this._profilesIdMap[this._makeKey(uid)];
  109. },
  110. // Must be implemented by subclasses.
  111. /**
  112. * @param {string=} title
  113. * @return {!WebInspector.ProfileHeader}
  114. */
  115. createTemporaryProfile: function(title)
  116. {
  117. throw new Error("Needs implemented.");
  118. },
  119. /**
  120. * @param {ProfilerAgent.ProfileHeader} profile
  121. * @return {!WebInspector.ProfileHeader}
  122. */
  123. createProfile: function(profile)
  124. {
  125. throw new Error("Not supported for " + this._name + " profiles.");
  126. },
  127. /**
  128. * @nosideeffects
  129. * @param {number} id
  130. * @return {string}
  131. */
  132. _makeKey: function(id)
  133. {
  134. return id + '/' + escape(this.id);
  135. },
  136. /**
  137. * @param {!WebInspector.ProfileHeader} profile
  138. */
  139. addProfile: function(profile)
  140. {
  141. this._profiles.push(profile);
  142. // FIXME: uid only based key should be enough.
  143. this._profilesIdMap[this._makeKey(profile.uid)] = profile;
  144. this.dispatchEventToListeners(WebInspector.ProfileType.Events.AddProfileHeader, profile);
  145. },
  146. /**
  147. * @param {!WebInspector.ProfileHeader} profile
  148. */
  149. removeProfile: function(profile)
  150. {
  151. for (var i = 0; i < this._profiles.length; ++i) {
  152. if (this._profiles[i].uid === profile.uid) {
  153. this._profiles.splice(i, 1);
  154. break;
  155. }
  156. }
  157. delete this._profilesIdMap[this._makeKey(profile.uid)];
  158. },
  159. /**
  160. * @nosideeffects
  161. * @return {WebInspector.ProfileHeader}
  162. */
  163. findTemporaryProfile: function()
  164. {
  165. for (var i = 0; i < this._profiles.length; ++i) {
  166. if (this._profiles[i].isTemporary)
  167. return this._profiles[i];
  168. }
  169. return null;
  170. },
  171. _reset: function()
  172. {
  173. var profiles = this._profiles.slice(0);
  174. for (var i = 0; i < profiles.length; ++i) {
  175. var profile = profiles[i];
  176. var view = profile.existingView();
  177. if (view) {
  178. view.detach();
  179. if ("dispose" in view)
  180. view.dispose();
  181. }
  182. this.dispatchEventToListeners(WebInspector.ProfileType.Events.RemoveProfileHeader, profile);
  183. }
  184. this.treeElement.removeChildren();
  185. this._profiles = [];
  186. this._profilesIdMap = {};
  187. },
  188. /**
  189. * @param {function(this:WebInspector.ProfileType, ?string, !Array.<!ProfilerAgent.ProfileHeader>)} populateCallback
  190. */
  191. _requestProfilesFromBackend: function(populateCallback)
  192. {
  193. },
  194. _populateProfiles: function()
  195. {
  196. /**
  197. * @param {?string} error
  198. * @param {!Array.<!ProfilerAgent.ProfileHeader>} profileHeaders
  199. */
  200. function populateCallback(error, profileHeaders) {
  201. if (error)
  202. return;
  203. profileHeaders.sort(function(a, b) { return a.uid - b.uid; });
  204. var count = profileHeaders.length;
  205. for (var i = 0; i < count; ++i)
  206. this.addProfile(this.createProfile(profileHeaders[i]));
  207. }
  208. this._requestProfilesFromBackend(populateCallback.bind(this));
  209. },
  210. __proto__: WebInspector.Object.prototype
  211. }
  212. /**
  213. * @constructor
  214. * @param {!WebInspector.ProfileType} profileType
  215. * @param {string} title
  216. * @param {number=} uid
  217. */
  218. WebInspector.ProfileHeader = function(profileType, title, uid)
  219. {
  220. this._profileType = profileType;
  221. this.title = title;
  222. this.isTemporary = uid === undefined;
  223. this.uid = this.isTemporary ? -1 : uid;
  224. this._fromFile = false;
  225. }
  226. WebInspector.ProfileHeader.prototype = {
  227. /**
  228. * @return {!WebInspector.ProfileType}
  229. */
  230. profileType: function()
  231. {
  232. return this._profileType;
  233. },
  234. /**
  235. * Must be implemented by subclasses.
  236. * @return {WebInspector.ProfileSidebarTreeElement}
  237. */
  238. createSidebarTreeElement: function()
  239. {
  240. throw new Error("Needs implemented.");
  241. },
  242. /**
  243. * @return {?WebInspector.View}
  244. */
  245. existingView: function()
  246. {
  247. return this._view;
  248. },
  249. /**
  250. * @param {!WebInspector.ProfilesPanel} panel
  251. * @return {!WebInspector.View}
  252. */
  253. view: function(panel)
  254. {
  255. if (!this._view)
  256. this._view = this.createView(panel);
  257. return this._view;
  258. },
  259. /**
  260. * @param {!WebInspector.ProfilesPanel} panel
  261. * @return {!WebInspector.View}
  262. */
  263. createView: function(panel)
  264. {
  265. throw new Error("Not implemented.");
  266. },
  267. dispose: function()
  268. {
  269. },
  270. /**
  271. * @param {Function} callback
  272. */
  273. load: function(callback)
  274. {
  275. },
  276. /**
  277. * @return {boolean}
  278. */
  279. canSaveToFile: function()
  280. {
  281. return false;
  282. },
  283. saveToFile: function()
  284. {
  285. throw new Error("Needs implemented");
  286. },
  287. /**
  288. * @param {File} file
  289. */
  290. loadFromFile: function(file)
  291. {
  292. throw new Error("Needs implemented");
  293. },
  294. /**
  295. * @return {boolean}
  296. */
  297. fromFile: function()
  298. {
  299. return this._fromFile;
  300. }
  301. }
  302. /**
  303. * @constructor
  304. * @extends {WebInspector.Panel}
  305. * @implements {WebInspector.ContextMenu.Provider}
  306. * @param {string=} name
  307. * @param {WebInspector.ProfileType=} type
  308. */
  309. WebInspector.ProfilesPanel = function(name, type)
  310. {
  311. // If the name is not specified the ProfilesPanel works in multi-profile mode.
  312. var singleProfileMode = typeof name !== "undefined";
  313. name = name || "profiles";
  314. WebInspector.Panel.call(this, name);
  315. this.registerRequiredCSS("panelEnablerView.css");
  316. this.registerRequiredCSS("heapProfiler.css");
  317. this.registerRequiredCSS("profilesPanel.css");
  318. this.createSidebarViewWithTree();
  319. this.profilesItemTreeElement = new WebInspector.ProfilesSidebarTreeElement(this);
  320. this.sidebarTree.appendChild(this.profilesItemTreeElement);
  321. this._singleProfileMode = singleProfileMode;
  322. this._profileTypesByIdMap = {};
  323. var panelEnablerHeading = WebInspector.UIString("You need to enable profiling before you can use the Profiles panel.");
  324. var panelEnablerDisclaimer = WebInspector.UIString("Enabling profiling will make scripts run slower.");
  325. var panelEnablerButton = WebInspector.UIString("Enable Profiling");
  326. this.panelEnablerView = new WebInspector.PanelEnablerView(name, panelEnablerHeading, panelEnablerDisclaimer, panelEnablerButton);
  327. this.panelEnablerView.addEventListener("enable clicked", this.enableProfiler, this);
  328. this.profileViews = document.createElement("div");
  329. this.profileViews.id = "profile-views";
  330. this.splitView.mainElement.appendChild(this.profileViews);
  331. this._statusBarButtons = [];
  332. this.enableToggleButton = new WebInspector.StatusBarButton("", "enable-toggle-status-bar-item");
  333. if (Capabilities.profilerCausesRecompilation) {
  334. this._statusBarButtons.push(this.enableToggleButton);
  335. this.enableToggleButton.addEventListener("click", this._onToggleProfiling, this);
  336. }
  337. this.recordButton = new WebInspector.StatusBarButton("", "record-profile-status-bar-item");
  338. this.recordButton.addEventListener("click", this.toggleRecordButton, this);
  339. this._statusBarButtons.push(this.recordButton);
  340. this.clearResultsButton = new WebInspector.StatusBarButton(WebInspector.UIString("Clear all profiles."), "clear-status-bar-item");
  341. this.clearResultsButton.addEventListener("click", this._clearProfiles, this);
  342. this._statusBarButtons.push(this.clearResultsButton);
  343. this._profileTypeStatusBarItemsContainer = document.createElement("div");
  344. this._profileTypeStatusBarItemsContainer.className = "status-bar-items";
  345. this._profileViewStatusBarItemsContainer = document.createElement("div");
  346. this._profileViewStatusBarItemsContainer.className = "status-bar-items";
  347. this._profilerEnabled = !Capabilities.profilerCausesRecompilation;
  348. if (singleProfileMode) {
  349. this._launcherView = this._createLauncherView();
  350. this._registerProfileType(/** @type {!WebInspector.ProfileType} */ (type));
  351. this._selectedProfileType = type;
  352. this._updateProfileTypeSpecificUI();
  353. } else {
  354. this._launcherView = new WebInspector.MultiProfileLauncherView(this);
  355. this._launcherView.addEventListener(WebInspector.MultiProfileLauncherView.EventTypes.ProfileTypeSelected, this._onProfileTypeSelected, this);
  356. this._registerProfileType(new WebInspector.CPUProfileType());
  357. if (!WebInspector.WorkerManager.isWorkerFrontend())
  358. this._registerProfileType(new WebInspector.CSSSelectorProfileType());
  359. if (Capabilities.heapProfilerPresent)
  360. this._registerProfileType(new WebInspector.HeapSnapshotProfileType());
  361. if (!WebInspector.WorkerManager.isWorkerFrontend() && WebInspector.experimentsSettings.canvasInspection.isEnabled())
  362. this._registerProfileType(new WebInspector.CanvasProfileType());
  363. }
  364. this._reset();
  365. this._createFileSelectorElement();
  366. this.element.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true);
  367. WebInspector.ContextMenu.registerProvider(this);
  368. }
  369. WebInspector.ProfilesPanel.prototype = {
  370. _createFileSelectorElement: function()
  371. {
  372. if (this._fileSelectorElement)
  373. this.element.removeChild(this._fileSelectorElement);
  374. this._fileSelectorElement = WebInspector.createFileSelectorElement(this._loadFromFile.bind(this));
  375. this.element.appendChild(this._fileSelectorElement);
  376. },
  377. /**
  378. * @return {!WebInspector.ProfileLauncherView}
  379. */
  380. _createLauncherView: function()
  381. {
  382. return new WebInspector.ProfileLauncherView(this);
  383. },
  384. /**
  385. * @param {!File} file
  386. */
  387. _loadFromFile: function(file)
  388. {
  389. if (!file.name.endsWith(".heapsnapshot")) {
  390. WebInspector.log(WebInspector.UIString("Only heap snapshots from files with extension '.heapsnapshot' can be loaded."));
  391. return;
  392. }
  393. var profileType = this.getProfileType(WebInspector.HeapSnapshotProfileType.TypeId);
  394. if (!!profileType.findTemporaryProfile()) {
  395. WebInspector.log(WebInspector.UIString("Can't load profile when other profile is recording."));
  396. return;
  397. }
  398. var temporaryProfile = profileType.createTemporaryProfile(WebInspector.ProfilesPanelDescriptor.UserInitiatedProfileName + "." + file.name);
  399. profileType.addProfile(temporaryProfile);
  400. temporaryProfile._fromFile = true;
  401. temporaryProfile.loadFromFile(file);
  402. this._createFileSelectorElement();
  403. },
  404. statusBarItems: function()
  405. {
  406. return this._statusBarButtons.select("element").concat(this._profileTypeStatusBarItemsContainer, this._profileViewStatusBarItemsContainer);
  407. },
  408. toggleRecordButton: function()
  409. {
  410. var isProfiling = this._selectedProfileType.buttonClicked();
  411. this.setRecordingProfile(this._selectedProfileType.id, isProfiling);
  412. },
  413. _populateAllProfiles: function()
  414. {
  415. if (!this._profilerEnabled || this._profilesWereRequested)
  416. return;
  417. this._profilesWereRequested = true;
  418. for (var typeId in this._profileTypesByIdMap)
  419. this._profileTypesByIdMap[typeId]._populateProfiles();
  420. },
  421. wasShown: function()
  422. {
  423. WebInspector.Panel.prototype.wasShown.call(this);
  424. this._populateAllProfiles();
  425. },
  426. _profilerWasEnabled: function()
  427. {
  428. if (this._profilerEnabled)
  429. return;
  430. this._profilerEnabled = true;
  431. this._reset();
  432. if (this.isShowing())
  433. this._populateAllProfiles();
  434. },
  435. _profilerWasDisabled: function()
  436. {
  437. if (!this._profilerEnabled)
  438. return;
  439. this._profilerEnabled = false;
  440. this._reset();
  441. },
  442. /**
  443. * @param {WebInspector.Event} event
  444. */
  445. _onProfileTypeSelected: function(event)
  446. {
  447. this._selectedProfileType = /** @type {!WebInspector.ProfileType} */ (event.data);
  448. this._updateProfileTypeSpecificUI();
  449. },
  450. _updateProfileTypeSpecificUI: function()
  451. {
  452. this.recordButton.title = this._selectedProfileType.buttonTooltip;
  453. this._profileTypeStatusBarItemsContainer.removeChildren();
  454. var statusBarItems = this._selectedProfileType.statusBarItems();
  455. if (statusBarItems) {
  456. for (var i = 0; i < statusBarItems.length; ++i)
  457. this._profileTypeStatusBarItemsContainer.appendChild(statusBarItems[i]);
  458. }
  459. this._resize(this.splitView.sidebarWidth());
  460. },
  461. _reset: function()
  462. {
  463. WebInspector.Panel.prototype.reset.call(this);
  464. for (var typeId in this._profileTypesByIdMap)
  465. this._profileTypesByIdMap[typeId]._reset();
  466. delete this.visibleView;
  467. delete this.currentQuery;
  468. this.searchCanceled();
  469. this._profileGroups = {};
  470. this._profilesWereRequested = false;
  471. this.recordButton.toggled = false;
  472. if (this._selectedProfileType)
  473. this.recordButton.title = this._selectedProfileType.buttonTooltip;
  474. this._launcherView.profileFinished();
  475. this.sidebarTreeElement.removeStyleClass("some-expandable");
  476. this.profileViews.removeChildren();
  477. this._profileViewStatusBarItemsContainer.removeChildren();
  478. this.removeAllListeners();
  479. this._updateInterface();
  480. this.profilesItemTreeElement.select();
  481. this._showLauncherView();
  482. },
  483. _showLauncherView: function()
  484. {
  485. this.closeVisibleView();
  486. this._profileViewStatusBarItemsContainer.removeChildren();
  487. this._launcherView.show(this.splitView.mainElement);
  488. this.visibleView = this._launcherView;
  489. },
  490. _clearProfiles: function()
  491. {
  492. ProfilerAgent.clearProfiles();
  493. HeapProfilerAgent.clearProfiles();
  494. this._reset();
  495. },
  496. _garbageCollectButtonClicked: function()
  497. {
  498. HeapProfilerAgent.collectGarbage();
  499. },
  500. /**
  501. * @param {!WebInspector.ProfileType} profileType
  502. */
  503. _registerProfileType: function(profileType)
  504. {
  505. this._profileTypesByIdMap[profileType.id] = profileType;
  506. this._launcherView.addProfileType(profileType);
  507. profileType.treeElement = new WebInspector.SidebarSectionTreeElement(profileType.treeItemTitle, null, true);
  508. profileType.treeElement.hidden = !this._singleProfileMode;
  509. this.sidebarTree.appendChild(profileType.treeElement);
  510. profileType.treeElement.childrenListElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true);
  511. function onAddProfileHeader(event)
  512. {
  513. this._addProfileHeader(event.data);
  514. }
  515. function onRemoveProfileHeader(event)
  516. {
  517. this._removeProfileHeader(event.data);
  518. }
  519. function onProgressUpdated(event)
  520. {
  521. this._reportProfileProgress(event.data.profile, event.data.done, event.data.total);
  522. }
  523. profileType.addEventListener(WebInspector.ProfileType.Events.ViewUpdated, this._updateProfileTypeSpecificUI, this);
  524. profileType.addEventListener(WebInspector.ProfileType.Events.AddProfileHeader, onAddProfileHeader, this);
  525. profileType.addEventListener(WebInspector.ProfileType.Events.RemoveProfileHeader, onRemoveProfileHeader, this);
  526. profileType.addEventListener(WebInspector.ProfileType.Events.ProgressUpdated, onProgressUpdated, this);
  527. },
  528. /**
  529. * @param {Event} event
  530. */
  531. _handleContextMenuEvent: function(event)
  532. {
  533. var element = event.srcElement;
  534. while (element && !element.treeElement && element !== this.element)
  535. element = element.parentElement;
  536. if (!element)
  537. return;
  538. if (element.treeElement && element.treeElement.handleContextMenuEvent) {
  539. element.treeElement.handleContextMenuEvent(event, this);
  540. return;
  541. }
  542. if (element !== this.element || event.srcElement === this.sidebarElement) {
  543. var contextMenu = new WebInspector.ContextMenu(event);
  544. if (this.visibleView instanceof WebInspector.HeapSnapshotView)
  545. this.visibleView.populateContextMenu(contextMenu, event);
  546. contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Load heap snapshot\u2026" : "Load Heap Snapshot\u2026"), this._fileSelectorElement.click.bind(this._fileSelectorElement));
  547. contextMenu.show();
  548. }
  549. },
  550. /**
  551. * @nosideeffects
  552. * @param {string} text
  553. * @param {string} profileTypeId
  554. * @return {string}
  555. */
  556. _makeTitleKey: function(text, profileTypeId)
  557. {
  558. return escape(text) + '/' + escape(profileTypeId);
  559. },
  560. /**
  561. * @param {!WebInspector.ProfileHeader} profile
  562. */
  563. _addProfileHeader: function(profile)
  564. {
  565. if (!profile.isTemporary)
  566. this._removeTemporaryProfile(profile.profileType().id);
  567. var profileType = profile.profileType();
  568. var typeId = profileType.id;
  569. var sidebarParent = profileType.treeElement;
  570. sidebarParent.hidden = false;
  571. var small = false;
  572. var alternateTitle;
  573. if (!WebInspector.ProfilesPanelDescriptor.isUserInitiatedProfile(profile.title) && !profile.isTemporary) {
  574. var profileTitleKey = this._makeTitleKey(profile.title, typeId);
  575. if (!(profileTitleKey in this._profileGroups))
  576. this._profileGroups[profileTitleKey] = [];
  577. var group = this._profileGroups[profileTitleKey];
  578. group.push(profile);
  579. if (group.length === 2) {
  580. // Make a group TreeElement now that there are 2 profiles.
  581. group._profilesTreeElement = new WebInspector.ProfileGroupSidebarTreeElement(this, profile.title);
  582. // Insert at the same index for the first profile of the group.
  583. var index = sidebarParent.children.indexOf(group[0]._profilesTreeElement);
  584. sidebarParent.insertChild(group._profilesTreeElement, index);
  585. // Move the first profile to the group.
  586. var selected = group[0]._profilesTreeElement.selected;
  587. sidebarParent.removeChild(group[0]._profilesTreeElement);
  588. group._profilesTreeElement.appendChild(group[0]._profilesTreeElement);
  589. if (selected)
  590. group[0]._profilesTreeElement.revealAndSelect();
  591. group[0]._profilesTreeElement.small = true;
  592. group[0]._profilesTreeElement.mainTitle = WebInspector.UIString("Run %d", 1);
  593. this.sidebarTreeElement.addStyleClass("some-expandable");
  594. }
  595. if (group.length >= 2) {
  596. sidebarParent = group._profilesTreeElement;
  597. alternateTitle = WebInspector.UIString("Run %d", group.length);
  598. small = true;
  599. }
  600. }
  601. var profileTreeElement = profile.createSidebarTreeElement();
  602. profile.sidebarElement = profileTreeElement;
  603. profileTreeElement.small = small;
  604. if (alternateTitle)
  605. profileTreeElement.mainTitle = alternateTitle;
  606. profile._profilesTreeElement = profileTreeElement;
  607. sidebarParent.appendChild(profileTreeElement);
  608. if (!profile.isTemporary) {
  609. if (!this.visibleView)
  610. this._showProfile(profile);
  611. this.dispatchEventToListeners("profile added", {
  612. type: typeId
  613. });
  614. }
  615. },
  616. /**
  617. * @param {!WebInspector.ProfileHeader} profile
  618. */
  619. _removeProfileHeader: function(profile)
  620. {
  621. profile.dispose();
  622. profile.profileType().removeProfile(profile);
  623. var sidebarParent = profile.profileType().treeElement;
  624. var profileTitleKey = this._makeTitleKey(profile.title, profile.profileType().id);
  625. var group = this._profileGroups[profileTitleKey];
  626. if (group) {
  627. group.splice(group.indexOf(profile), 1);
  628. if (group.length === 1) {
  629. // Move the last profile out of its group and remove the group.
  630. var index = sidebarParent.children.indexOf(group._profilesTreeElement);
  631. sidebarParent.insertChild(group[0]._profilesTreeElement, index);
  632. group[0]._profilesTreeElement.small = false;
  633. group[0]._profilesTreeElement.mainTitle = group[0].title;
  634. sidebarParent.removeChild(group._profilesTreeElement);
  635. }
  636. if (group.length !== 0)
  637. sidebarParent = group._profilesTreeElement;
  638. else
  639. delete this._profileGroups[profileTitleKey];
  640. }
  641. sidebarParent.removeChild(profile._profilesTreeElement);
  642. // No other item will be selected if there aren't any other profiles, so
  643. // make sure that view gets cleared when the last profile is removed.
  644. if (!sidebarParent.children.length) {
  645. this.profilesItemTreeElement.select();
  646. this._showLauncherView();
  647. sidebarParent.hidden = !this._singleProfileMode;
  648. }
  649. },
  650. /**
  651. * @param {!WebInspector.ProfileHeader} profile
  652. */
  653. _showProfile: function(profile)
  654. {
  655. if (!profile || profile.isTemporary)
  656. return;
  657. var view = profile.view(this);
  658. if (view === this.visibleView)
  659. return;
  660. this.closeVisibleView();
  661. view.show(this.profileViews);
  662. profile._profilesTreeElement._suppressOnSelect = true;
  663. profile._profilesTreeElement.revealAndSelect();
  664. delete profile._profilesTreeElement._suppressOnSelect;
  665. this.visibleView = view;
  666. this._profileViewStatusBarItemsContainer.removeChildren();
  667. var statusBarItems = view.statusBarItems();
  668. if (statusBarItems)
  669. for (var i = 0; i < statusBarItems.length; ++i)
  670. this._profileViewStatusBarItemsContainer.appendChild(statusBarItems[i]);
  671. },
  672. /**
  673. * @param {HeapProfilerAgent.HeapSnapshotObjectId} snapshotObjectId
  674. * @param {string} viewName
  675. */
  676. showObject: function(snapshotObjectId, viewName)
  677. {
  678. var heapProfiles = this.getProfileType(WebInspector.HeapSnapshotProfileType.TypeId).getProfiles();
  679. for (var i = 0; i < heapProfiles.length; i++) {
  680. var profile = heapProfiles[i];
  681. // FIXME: allow to choose snapshot if there are several options.
  682. if (profile.maxJSObjectId >= snapshotObjectId) {
  683. this._showProfile(profile);
  684. var view = profile.view(this);
  685. view.changeView(viewName, function() {
  686. view.dataGrid.highlightObjectByHeapSnapshotId(snapshotObjectId);
  687. });
  688. break;
  689. }
  690. }
  691. },
  692. /**
  693. * @param {string} typeId
  694. */
  695. _createTemporaryProfile: function(typeId)
  696. {
  697. var type = this.getProfileType(typeId);
  698. if (!type.findTemporaryProfile())
  699. type.addProfile(type.createTemporaryProfile());
  700. },
  701. /**
  702. * @param {string} typeId
  703. */
  704. _removeTemporaryProfile: function(typeId)
  705. {
  706. var temporaryProfile = this.getProfileType(typeId).findTemporaryProfile();
  707. if (!!temporaryProfile)
  708. this._removeProfileHeader(temporaryProfile);
  709. },
  710. /**
  711. * @param {string} typeId
  712. * @param {number} uid
  713. */
  714. getProfile: function(typeId, uid)
  715. {
  716. return this.getProfileType(typeId).getProfile(uid);
  717. },
  718. /**
  719. * @param {WebInspector.View} view
  720. */
  721. showView: function(view)
  722. {
  723. this._showProfile(view.profile);
  724. },
  725. /**
  726. * @param {string} typeId
  727. */
  728. getProfileType: function(typeId)
  729. {
  730. return this._profileTypesByIdMap[typeId];
  731. },
  732. /**
  733. * @param {string} typeId
  734. * @param {string} uid
  735. */
  736. showProfile: function(typeId, uid)
  737. {
  738. this._showProfile(this.getProfile(typeId, Number(uid)));
  739. },
  740. closeVisibleView: function()
  741. {
  742. if (this.visibleView)
  743. this.visibleView.detach();
  744. delete this.visibleView;
  745. },
  746. /**
  747. * @param {string} query
  748. */
  749. performSearch: function(query)
  750. {
  751. this.searchCanceled();
  752. var searchableViews = this._searchableViews();
  753. if (!searchableViews || !searchableViews.length)
  754. return;
  755. var visibleView = this.visibleView;
  756. var matchesCountUpdateTimeout = null;
  757. function updateMatchesCount()
  758. {
  759. WebInspector.searchController.updateSearchMatchesCount(this._totalSearchMatches, this);
  760. WebInspector.searchController.updateCurrentMatchIndex(this._currentSearchResultIndex, this);
  761. matchesCountUpdateTimeout = null;
  762. }
  763. function updateMatchesCountSoon()
  764. {
  765. if (matchesCountUpdateTimeout)
  766. return;
  767. // Update the matches count every half-second so it doesn't feel twitchy.
  768. matchesCountUpdateTimeout = setTimeout(updateMatchesCount.bind(this), 500);
  769. }
  770. function finishedCallback(view, searchMatches)
  771. {
  772. if (!searchMatches)
  773. return;
  774. this._totalSearchMatches += searchMatches;
  775. this._searchResults.push(view);
  776. if (this.searchMatchFound)
  777. this.searchMatchFound(view, searchMatches);
  778. updateMatchesCountSoon.call(this);
  779. if (view === visibleView)
  780. view.jumpToFirstSearchResult();
  781. }
  782. var i = 0;
  783. var panel = this;
  784. var boundFinishedCallback = finishedCallback.bind(this);
  785. var chunkIntervalIdentifier = null;
  786. // Split up the work into chunks so we don't block the
  787. // UI thread while processing.
  788. function processChunk()
  789. {
  790. var view = searchableViews[i];
  791. if (++i >= searchableViews.length) {
  792. if (panel._currentSearchChunkIntervalIdentifier === chunkIntervalIdentifier)
  793. delete panel._currentSearchChunkIntervalIdentifier;
  794. clearInterval(chunkIntervalIdentifier);
  795. }
  796. if (!view)
  797. return;
  798. view.currentQuery = query;
  799. view.performSearch(query, boundFinishedCallback);
  800. }
  801. processChunk();
  802. chunkIntervalIdentifier = setInterval(processChunk, 25);
  803. this._currentSearchChunkIntervalIdentifier = chunkIntervalIdentifier;
  804. },
  805. jumpToNextSearchResult: function()
  806. {
  807. if (!this.showView || !this._searchResults || !this._searchResults.length)
  808. return;
  809. var showFirstResult = false;
  810. this._currentSearchResultIndex = this._searchResults.indexOf(this.visibleView);
  811. if (this._currentSearchResultIndex === -1) {
  812. this._currentSearchResultIndex = 0;
  813. showFirstResult = true;
  814. }
  815. var currentView = this._searchResults[this._currentSearchResultIndex];
  816. if (currentView.showingLastSearchResult()) {
  817. if (++this._currentSearchResultIndex >= this._searchResults.length)
  818. this._currentSearchResultIndex = 0;
  819. currentView = this._searchResults[this._currentSearchResultIndex];
  820. showFirstResult = true;
  821. }
  822. WebInspector.searchController.updateCurrentMatchIndex(this._currentSearchResultIndex, this);
  823. if (currentView !== this.visibleView) {
  824. this.showView(currentView);
  825. WebInspector.searchController.showSearchField();
  826. }
  827. if (showFirstResult)
  828. currentView.jumpToFirstSearchResult();
  829. else
  830. currentView.jumpToNextSearchResult();
  831. },
  832. jumpToPreviousSearchResult: function()
  833. {
  834. if (!this.showView || !this._searchResults || !this._searchResults.length)
  835. return;
  836. var showLastResult = false;
  837. this._currentSearchResultIndex = this._searchResults.indexOf(this.visibleView);
  838. if (this._currentSearchResultIndex === -1) {
  839. this._currentSearchResultIndex = 0;
  840. showLastResult = true;
  841. }
  842. var currentView = this._searchResults[this._currentSearchResultIndex];
  843. if (currentView.showingFirstSearchResult()) {
  844. if (--this._currentSearchResultIndex < 0)
  845. this._currentSearchResultIndex = (this._searchResults.length - 1);
  846. currentView = this._searchResults[this._currentSearchResultIndex];
  847. showLastResult = true;
  848. }
  849. WebInspector.searchController.updateCurrentMatchIndex(this._currentSearchResultIndex, this);
  850. if (currentView !== this.visibleView) {
  851. this.showView(currentView);
  852. WebInspector.searchController.showSearchField();
  853. }
  854. if (showLastResult)
  855. currentView.jumpToLastSearchResult();
  856. else
  857. currentView.jumpToPreviousSearchResult();
  858. },
  859. /**
  860. * @return {!Array.<!WebInspector.ProfileHeader>}
  861. */
  862. _getAllProfiles: function()
  863. {
  864. var profiles = [];
  865. for (var typeId in this._profileTypesByIdMap)
  866. profiles = profiles.concat(this._profileTypesByIdMap[typeId].getProfiles());
  867. return profiles;
  868. },
  869. /**
  870. * @return {!Array.<!WebInspector.View>}
  871. */
  872. _searchableViews: function()
  873. {
  874. var profiles = this._getAllProfiles();
  875. var searchableViews = [];
  876. for (var i = 0; i < profiles.length; ++i) {
  877. var view = profiles[i].view(this);
  878. if (view.performSearch)
  879. searchableViews.push(view)
  880. }
  881. var index = searchableViews.indexOf(this.visibleView);
  882. if (index > 0) {
  883. // Move visibleView to the first position.
  884. searchableViews[index] = searchableViews[0];
  885. searchableViews[0] = this.visibleView;
  886. }
  887. return searchableViews;
  888. },
  889. searchMatchFound: function(view, matches)
  890. {
  891. view.profile._profilesTreeElement.searchMatches = matches;
  892. },
  893. searchCanceled: function()
  894. {
  895. if (this._searchResults) {
  896. for (var i = 0; i < this._searchResults.length; ++i) {
  897. var view = this._searchResults[i];
  898. if (view.searchCanceled)
  899. view.searchCanceled();
  900. delete view.currentQuery;
  901. }
  902. }
  903. WebInspector.Panel.prototype.searchCanceled.call(this);
  904. if (this._currentSearchChunkIntervalIdentifier) {
  905. clearInterval(this._currentSearchChunkIntervalIdentifier);
  906. delete this._currentSearchChunkIntervalIdentifier;
  907. }
  908. this._totalSearchMatches = 0;
  909. this._currentSearchResultIndex = 0;
  910. this._searchResults = [];
  911. var profiles = this._getAllProfiles();
  912. for (var i = 0; i < profiles.length; ++i)
  913. profiles[i]._profilesTreeElement.searchMatches = 0;
  914. },
  915. _updateInterface: function()
  916. {
  917. // FIXME: Replace ProfileType-specific button visibility changes by a single ProfileType-agnostic "combo-button" visibility change.
  918. if (this._profilerEnabled) {
  919. this.enableToggleButton.title = WebInspector.UIString("Profiling enabled. Click to disable.");
  920. this.enableToggleButton.toggled = true;
  921. this.recordButton.visible = true;
  922. this._profileViewStatusBarItemsContainer.removeStyleClass("hidden");
  923. this.clearResultsButton.element.removeStyleClass("hidden");
  924. this.panelEnablerView.detach();
  925. } else {
  926. this.enableToggleButton.title = WebInspector.UIString("Profiling disabled. Click to enable.");
  927. this.enableToggleButton.toggled = false;
  928. this.recordButton.visible = false;
  929. this._profileViewStatusBarItemsContainer.addStyleClass("hidden");
  930. this.clearResultsButton.element.addStyleClass("hidden");
  931. this.panelEnablerView.show(this.element);
  932. }
  933. },
  934. get profilerEnabled()
  935. {
  936. return this._profilerEnabled;
  937. },
  938. enableProfiler: function()
  939. {
  940. if (this._profilerEnabled)
  941. return;
  942. this._toggleProfiling(this.panelEnablerView.alwaysEnabled);
  943. },
  944. disableProfiler: function()
  945. {
  946. if (!this._profilerEnabled)
  947. return;
  948. this._toggleProfiling(this.panelEnablerView.alwaysEnabled);
  949. },
  950. /**
  951. * @param {WebInspector.Event} event
  952. */
  953. _onToggleProfiling: function(event) {
  954. this._toggleProfiling(true);
  955. },
  956. /**
  957. * @param {boolean} always
  958. */
  959. _toggleProfiling: function(always)
  960. {
  961. if (this._profilerEnabled) {
  962. WebInspector.settings.profilerEnabled.set(false);
  963. ProfilerAgent.disable(this._profilerWasDisabled.bind(this));
  964. } else {
  965. WebInspector.settings.profilerEnabled.set(always);
  966. ProfilerAgent.enable(this._profilerWasEnabled.bind(this));
  967. }
  968. },
  969. /**
  970. * @param {!WebInspector.Event} event
  971. */
  972. sidebarResized: function(event)
  973. {
  974. var sidebarWidth = /** @type {number} */ (event.data);
  975. this._resize(sidebarWidth);
  976. },
  977. onResize: function()
  978. {
  979. this._resize(this.splitView.sidebarWidth());
  980. },
  981. /**
  982. * @param {number} sidebarWidth
  983. */
  984. _resize: function(sidebarWidth)
  985. {
  986. var lastItemElement = this._statusBarButtons[this._statusBarButtons.length - 1].element;
  987. var left = lastItemElement.totalOffsetLeft() + lastItemElement.offsetWidth;
  988. this._profileTypeStatusBarItemsContainer.style.left = left + "px";
  989. left += this._profileTypeStatusBarItemsContainer.offsetWidth - 1;
  990. this._profileViewStatusBarItemsContainer.style.left = Math.max(left, sidebarWidth) + "px";
  991. },
  992. /**
  993. * @param {string} profileType
  994. * @param {boolean} isProfiling
  995. */
  996. setRecordingProfile: function(profileType, isProfiling)
  997. {
  998. var profileTypeObject = this.getProfileType(profileType);
  999. this.recordButton.toggled = isProfiling;
  1000. this.recordButton.title = profileTypeObject.buttonTooltip;
  1001. if (isProfiling) {
  1002. this._launcherView.profileStarted();
  1003. this._createTemporaryProfile(profileType);
  1004. } else
  1005. this._launcherView.profileFinished();
  1006. },
  1007. /**
  1008. * @param {!WebInspector.ProfileHeader} profile
  1009. * @param {number} done
  1010. * @param {number} total
  1011. */
  1012. _reportProfileProgress: function(profile, done, total)
  1013. {
  1014. profile.sidebarElement.subtitle = WebInspector.UIString("%.0f%", (done / total) * 100);
  1015. profile.sidebarElement.wait = true;
  1016. },
  1017. /**
  1018. * @param {WebInspector.ContextMenu} contextMenu
  1019. * @param {Object} target
  1020. */
  1021. appendApplicableItems: function(event, contextMenu, target)
  1022. {
  1023. if (WebInspector.inspectorView.currentPanel() !== this)
  1024. return;
  1025. var object = /** @type {WebInspector.RemoteObject} */ (target);
  1026. var objectId = object.objectId;
  1027. if (!objectId)
  1028. return;
  1029. var heapProfiles = this.getProfileType(WebInspector.HeapSnapshotProfileType.TypeId).getProfiles();
  1030. if (!heapProfiles.length)
  1031. return;
  1032. function revealInView(viewName)
  1033. {
  1034. HeapProfilerAgent.getHeapObjectId(objectId, didReceiveHeapObjectId.bind(this, viewName));
  1035. }
  1036. function didReceiveHeapObjectId(viewName, error, result)
  1037. {
  1038. if (WebInspector.inspectorView.currentPanel() !== this)
  1039. return;
  1040. if (!error)
  1041. this.showObject(result, viewName);
  1042. }
  1043. contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Reveal in Dominators view" : "Reveal in Dominators View"), revealInView.bind(this, "Dominators"));
  1044. contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Reveal in Summary view" : "Reveal in Summary View"), revealInView.bind(this, "Summary"));
  1045. },
  1046. __proto__: WebInspector.Panel.prototype
  1047. }
  1048. /**
  1049. * @constructor
  1050. * @extends {WebInspector.SidebarTreeElement}
  1051. * @param {!WebInspector.ProfileHeader} profile
  1052. * @param {string} titleFormat
  1053. * @param {string} className
  1054. */
  1055. WebInspector.ProfileSidebarTreeElement = function(profile, titleFormat, className)
  1056. {
  1057. this.profile = profile;
  1058. this._titleFormat = titleFormat;
  1059. if (WebInspector.ProfilesPanelDescriptor.isUserInitiatedProfile(this.profile.title))
  1060. this._profileNumber = WebInspector.ProfilesPanelDescriptor.userInitiatedProfileIndex(this.profile.title);
  1061. WebInspector.SidebarTreeElement.call(this, className, "", "", profile, false);
  1062. this.refreshTitles();
  1063. }
  1064. WebInspector.ProfileSidebarTreeElement.prototype = {
  1065. onselect: function()
  1066. {
  1067. if (!this._suppressOnSelect)
  1068. this.treeOutline.panel._showProfile(this.profile);
  1069. },
  1070. ondelete: function()
  1071. {
  1072. this.treeOutline.panel._removeProfileHeader(this.profile);
  1073. return true;
  1074. },
  1075. get mainTitle()
  1076. {
  1077. if (this._mainTitle)
  1078. return this._mainTitle;
  1079. if (WebInspector.ProfilesPanelDescriptor.isUserInitiatedProfile(this.profile.title))
  1080. return WebInspector.UIString(this._titleFormat, this._profileNumber);
  1081. return this.profile.title;
  1082. },
  1083. set mainTitle(x)
  1084. {
  1085. this._mainTitle = x;
  1086. this.refreshTitles();
  1087. },
  1088. set searchMatches(matches)
  1089. {
  1090. if (!matches) {
  1091. if (!this.bubbleElement)
  1092. return;
  1093. this.bubbleElement.removeStyleClass("search-matches");
  1094. this.bubbleText = "";
  1095. return;
  1096. }
  1097. this.bubbleText = matches;
  1098. this.bubbleElement.addStyleClass("search-matches");
  1099. },
  1100. /**
  1101. * @param {!Event} event
  1102. * @param {!WebInspector.ProfilesPanel} panel
  1103. */
  1104. handleContextMenuEvent: function(event, panel)
  1105. {
  1106. var profile = this.profile;
  1107. var contextMenu = new WebInspector.ContextMenu(event);
  1108. // FIXME: use context menu provider
  1109. if (profile.canSaveToFile()) {
  1110. contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Save heap snapshot\u2026" : "Save Heap Snapshot\u2026"), profile.saveToFile.bind(profile));
  1111. contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Load heap snapshot\u2026" : "Load Heap Snapshot\u2026"), panel._fileSelectorElement.click.bind(panel._fileSelectorElement));
  1112. contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Delete heap snapshot" : "Delete Heap Snapshot"), this.ondelete.bind(this));
  1113. } else {
  1114. contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Load heap snapshot\u2026" : "Load Heap Snapshot\u2026"), panel._fileSelectorElement.click.bind(panel._fileSelectorElement));
  1115. contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Delete profile" : "Delete Profile"), this.ondelete.bind(this));
  1116. }
  1117. contextMenu.show();
  1118. },
  1119. __proto__: WebInspector.SidebarTreeElement.prototype
  1120. }
  1121. /**
  1122. * @constructor
  1123. * @extends {WebInspector.SidebarTreeElement}
  1124. * @param {WebInspector.ProfilesPanel} panel
  1125. * @param {string} title
  1126. * @param {string=} subtitle
  1127. */
  1128. WebInspector.ProfileGroupSidebarTreeElement = function(panel, title, subtitle)
  1129. {
  1130. WebInspector.SidebarTreeElement.call(this, "profile-group-sidebar-tree-item", title, subtitle, null, true);
  1131. this._panel = panel;
  1132. }
  1133. WebInspector.ProfileGroupSidebarTreeElement.prototype = {
  1134. onselect: function()
  1135. {
  1136. if (this.children.length > 0)
  1137. this._panel._showProfile(this.children[this.children.length - 1].profile);
  1138. },
  1139. __proto__: WebInspector.SidebarTreeElement.prototype
  1140. }
  1141. /**
  1142. * @constructor
  1143. * @extends {WebInspector.SidebarTreeElement}
  1144. * @param {!WebInspector.ProfilesPanel} panel
  1145. */
  1146. WebInspector.ProfilesSidebarTreeElement = function(panel)
  1147. {
  1148. this._panel = panel;
  1149. this.small = false;
  1150. WebInspector.SidebarTreeElement.call(this, "profile-launcher-view-tree-item", WebInspector.UIString("Profiles"), "", null, false);
  1151. }
  1152. WebInspector.ProfilesSidebarTreeElement.prototype = {
  1153. onselect: function()
  1154. {
  1155. this._panel._showLauncherView();
  1156. },
  1157. get selectable()
  1158. {
  1159. return true;
  1160. },
  1161. __proto__: WebInspector.SidebarTreeElement.prototype
  1162. }
  1163. /**
  1164. * @constructor
  1165. * @extends {WebInspector.ProfilesPanel}
  1166. */
  1167. WebInspector.CPUProfilerPanel = function()
  1168. {
  1169. WebInspector.ProfilesPanel.call(this, "cpu-profiler", new WebInspector.CPUProfileType());
  1170. }
  1171. WebInspector.CPUProfilerPanel.prototype = {
  1172. __proto__: WebInspector.ProfilesPanel.prototype
  1173. }
  1174. /**
  1175. * @constructor
  1176. * @extends {WebInspector.ProfilesPanel}
  1177. */
  1178. WebInspector.CSSSelectorProfilerPanel = function()
  1179. {
  1180. WebInspector.ProfilesPanel.call(this, "css-profiler", new WebInspector.CSSSelectorProfileType());
  1181. }
  1182. WebInspector.CSSSelectorProfilerPanel.prototype = {
  1183. __proto__: WebInspector.ProfilesPanel.prototype
  1184. }
  1185. /**
  1186. * @constructor
  1187. * @extends {WebInspector.ProfilesPanel}
  1188. */
  1189. WebInspector.HeapProfilerPanel = function()
  1190. {
  1191. WebInspector.ProfilesPanel.call(this, "heap-profiler", new WebInspector.HeapSnapshotProfileType());
  1192. }
  1193. WebInspector.HeapProfilerPanel.prototype = {
  1194. __proto__: WebInspector.ProfilesPanel.prototype
  1195. }
  1196. /**
  1197. * @constructor
  1198. * @extends {WebInspector.ProfilesPanel}
  1199. */
  1200. WebInspector.CanvasProfilerPanel = function()
  1201. {
  1202. WebInspector.ProfilesPanel.call(this, "canvas-profiler", new WebInspector.CanvasProfileType());
  1203. }
  1204. WebInspector.CanvasProfilerPanel.prototype = {
  1205. __proto__: WebInspector.ProfilesPanel.prototype
  1206. }
  1207. importScript("ProfileDataGridTree.js");
  1208. importScript("BottomUpProfileDataGridTree.js");
  1209. importScript("CPUProfileView.js");
  1210. importScript("CSSSelectorProfileView.js");
  1211. importScript("FlameChart.js");
  1212. importScript("HeapSnapshot.js");
  1213. importScript("HeapSnapshotDataGrids.js");
  1214. importScript("HeapSnapshotGridNodes.js");
  1215. importScript("HeapSnapshotLoader.js");
  1216. importScript("HeapSnapshotProxy.js");
  1217. importScript("HeapSnapshotView.js");
  1218. importScript("HeapSnapshotWorkerDispatcher.js");
  1219. importScript("JSHeapSnapshot.js");
  1220. importScript("NativeHeapSnapshot.js");
  1221. importScript("ProfileLauncherView.js");
  1222. importScript("TopDownProfileDataGridTree.js");
  1223. importScript("CanvasProfileView.js");