Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / BreakpointManager.js
1 /*
2  * Copyright (C) 2011 Google 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 are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 /**
32  * @constructor
33  * @extends {WebInspector.Object}
34  * @param {!WebInspector.Setting} breakpointStorage
35  * @param {!WebInspector.DebuggerModel} debuggerModel
36  * @param {!WebInspector.Workspace} workspace
37  */
38 WebInspector.BreakpointManager = function(breakpointStorage, debuggerModel, workspace)
39 {
40     this._storage = new WebInspector.BreakpointManager.Storage(this, breakpointStorage);
41     this._debuggerModel = debuggerModel;
42     this._workspace = workspace;
43
44     this._breakpointForDebuggerId = {};
45     this._breakpointsForUISourceCode = new Map();
46     this._breakpointsForPrimaryUISourceCode = new Map();
47     this._sourceFilesWithRestoredBreakpoints = {};
48
49     this._debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointResolved, this._breakpointResolved, this);
50     this._workspace.addEventListener(WebInspector.Workspace.Events.ProjectWillReset, this._projectWillReset, this);
51     this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeAdded, this._uiSourceCodeAdded, this);
52     this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeRemoved, this._uiSourceCodeRemoved, this);
53 }
54
55 WebInspector.BreakpointManager.Events = {
56     BreakpointAdded: "breakpoint-added",
57     BreakpointRemoved: "breakpoint-removed"
58 }
59
60 WebInspector.BreakpointManager._sourceFileId = function(uiSourceCode)
61 {
62     if (!uiSourceCode.url)
63         return "";
64     var deobfuscatedPrefix = uiSourceCode.formatted() ? "deobfuscated:" : "";
65     return deobfuscatedPrefix + uiSourceCode.uri();
66 }
67
68 /**
69  * @param {string} sourceFileId
70  * @param {number} lineNumber
71  * @param {number} columnNumber
72  * @return {string}
73  */
74 WebInspector.BreakpointManager._breakpointStorageId = function(sourceFileId, lineNumber, columnNumber)
75 {
76     if (!sourceFileId)
77         return "";
78     return sourceFileId + ":" + lineNumber + ":" + columnNumber;
79 }
80
81 WebInspector.BreakpointManager.prototype = {
82     /**
83      * @param {string} sourceFileId
84      */
85     _provisionalBreakpointsForSourceFileId: function(sourceFileId)
86     {
87         var result = new StringMap();
88         for (var debuggerId in this._breakpointForDebuggerId) {
89             var breakpoint = this._breakpointForDebuggerId[debuggerId];
90             if (breakpoint._sourceFileId === sourceFileId)
91                 result.put(breakpoint._breakpointStorageId(), breakpoint);
92         }
93         return result;
94     },
95
96     /**
97      * @param {!WebInspector.UISourceCode} uiSourceCode
98      */
99     _restoreBreakpoints: function(uiSourceCode)
100     {
101         var sourceFileId = WebInspector.BreakpointManager._sourceFileId(uiSourceCode);
102         if (!sourceFileId || this._sourceFilesWithRestoredBreakpoints[sourceFileId])
103             return;
104         this._sourceFilesWithRestoredBreakpoints[sourceFileId] = true;
105
106         this._storage.mute();
107         var breakpointItems = this._storage.breakpointItems(uiSourceCode);
108         var provisionalBreakpoints = this._provisionalBreakpointsForSourceFileId(sourceFileId);
109         for (var i = 0; i < breakpointItems.length; ++i) {
110             var breakpointItem = breakpointItems[i];
111             var itemStorageId = WebInspector.BreakpointManager._breakpointStorageId(breakpointItem.sourceFileId, breakpointItem.lineNumber, breakpointItem.columnNumber);
112             var provisionalBreakpoint = provisionalBreakpoints.get(itemStorageId);
113             if (provisionalBreakpoint) {
114                 if (!this._breakpointsForPrimaryUISourceCode.get(uiSourceCode))
115                     this._breakpointsForPrimaryUISourceCode.put(uiSourceCode, []);
116                 this._breakpointsForPrimaryUISourceCode.get(uiSourceCode).push(provisionalBreakpoint);
117                 provisionalBreakpoint._updateInDebugger();
118             } else {
119                 this._innerSetBreakpoint(uiSourceCode, breakpointItem.lineNumber, breakpointItem.columnNumber, breakpointItem.condition, breakpointItem.enabled);
120             }
121         }
122         this._storage.unmute();
123     },
124
125     /**
126      * @param {!WebInspector.Event} event
127      */
128     _uiSourceCodeAdded: function(event)
129     {
130         var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
131         this._restoreBreakpoints(uiSourceCode);
132         if (uiSourceCode.contentType() === WebInspector.resourceTypes.Script || uiSourceCode.contentType() === WebInspector.resourceTypes.Document) {
133             uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.SourceMappingChanged, this._uiSourceCodeMappingChanged, this);
134             uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.FormattedChanged, this._uiSourceCodeFormatted, this);
135         }
136     },
137
138     /**
139      * @param {!WebInspector.Event} event
140      */
141     _uiSourceCodeFormatted: function(event)
142     {
143         var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.target);
144         this._restoreBreakpoints(uiSourceCode);
145     },
146
147     /**
148      * @param {!WebInspector.Event} event
149      */
150     _uiSourceCodeRemoved: function(event)
151     {
152         var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
153         this._removeUISourceCode(uiSourceCode);
154     },
155
156     /**
157      * @param {!WebInspector.Event} event
158      */
159     _uiSourceCodeMappingChanged: function(event)
160     {
161         var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.target);
162         var breakpoints = this._breakpointsForPrimaryUISourceCode.get(uiSourceCode) || [];
163         for (var i = 0; i < breakpoints.length; ++i)
164             breakpoints[i]._updateInDebugger();
165     },
166
167     /**
168      * @param {!WebInspector.UISourceCode} uiSourceCode
169      */
170     _removeUISourceCode: function(uiSourceCode)
171     {
172         var breakpoints = this._breakpointsForPrimaryUISourceCode.get(uiSourceCode) || [];
173         for (var i = 0; i < breakpoints.length; ++i)
174             breakpoints[i]._resetLocations();
175         var sourceFileId = WebInspector.BreakpointManager._sourceFileId(uiSourceCode);
176         delete this._sourceFilesWithRestoredBreakpoints[sourceFileId];
177         uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.FormattedChanged, this._uiSourceCodeFormatted, this);
178         uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.SourceMappingChanged, this._uiSourceCodeMappingChanged, this);
179         this._breakpointsForPrimaryUISourceCode.remove(uiSourceCode);
180     },
181
182     /**
183      * @param {!WebInspector.UISourceCode} uiSourceCode
184      * @param {number} lineNumber
185      * @param {number} columnNumber
186      * @param {string} condition
187      * @param {boolean} enabled
188      * @return {!WebInspector.BreakpointManager.Breakpoint}
189      */
190     setBreakpoint: function(uiSourceCode, lineNumber, columnNumber, condition, enabled)
191     {
192         this._debuggerModel.setBreakpointsActive(true);
193         return this._innerSetBreakpoint(uiSourceCode, lineNumber, columnNumber, condition, enabled);
194     },
195
196     /**
197      * @param {!WebInspector.UISourceCode} uiSourceCode
198      * @param {number} lineNumber
199      * @param {number} columnNumber
200      * @param {string} condition
201      * @param {boolean} enabled
202      * @return {!WebInspector.BreakpointManager.Breakpoint}
203      */
204     _innerSetBreakpoint: function(uiSourceCode, lineNumber, columnNumber, condition, enabled)
205     {
206         var breakpoint = this.findBreakpoint(uiSourceCode, lineNumber, columnNumber);
207         if (breakpoint) {
208             breakpoint._updateBreakpoint(condition, enabled);
209             return breakpoint;
210         }
211         var projectId = uiSourceCode.project().id();
212         var path = uiSourceCode.path();
213         var sourceFileId = WebInspector.BreakpointManager._sourceFileId(uiSourceCode);
214         breakpoint = new WebInspector.BreakpointManager.Breakpoint(this, projectId, path, sourceFileId, lineNumber, columnNumber, condition, enabled);
215         if (!this._breakpointsForPrimaryUISourceCode.get(uiSourceCode))
216             this._breakpointsForPrimaryUISourceCode.put(uiSourceCode, []);
217         this._breakpointsForPrimaryUISourceCode.get(uiSourceCode).push(breakpoint);
218         return breakpoint;
219     },
220
221     /**
222      * @param {!WebInspector.UISourceCode} uiSourceCode
223      * @param {number} lineNumber
224      * @param {number} columnNumber
225      * @return {?WebInspector.BreakpointManager.Breakpoint}
226      */
227     findBreakpoint: function(uiSourceCode, lineNumber, columnNumber)
228     {
229         var breakpoints = this._breakpointsForUISourceCode.get(uiSourceCode);
230         var lineBreakpoints = breakpoints ? breakpoints.get(String(lineNumber)) : null;
231         var columnBreakpoints = lineBreakpoints ? lineBreakpoints.get(String(columnNumber)) : null;
232         return columnBreakpoints ? columnBreakpoints[0] : null;
233     },
234
235     /**
236      * @param {!WebInspector.UISourceCode} uiSourceCode
237      * @param {number} lineNumber
238      * @return {?WebInspector.BreakpointManager.Breakpoint}
239      */
240     findBreakpointOnLine: function(uiSourceCode, lineNumber)
241     {
242         var breakpoints = this._breakpointsForUISourceCode.get(uiSourceCode);
243         var lineBreakpoints = breakpoints ? breakpoints.get(String(lineNumber)) : null;
244         return lineBreakpoints ? lineBreakpoints.values()[0][0] : null;
245     },
246
247     /**
248      * @param {!WebInspector.UISourceCode} uiSourceCode
249      * @return {!Array.<!WebInspector.BreakpointManager.Breakpoint>}
250      */
251     breakpointsForUISourceCode: function(uiSourceCode)
252     {
253         var result = [];
254         var uiSourceCodeBreakpoints = this._breakpointsForUISourceCode.get(uiSourceCode);
255         var breakpoints = uiSourceCodeBreakpoints ? uiSourceCodeBreakpoints.values() : [];
256         for (var i = 0; i < breakpoints.length; ++i) {
257             var lineBreakpoints = breakpoints[i];
258             var columnBreakpointArrays = lineBreakpoints ? lineBreakpoints.values() : [];
259             result = result.concat.apply(result, columnBreakpointArrays);
260         }
261         return result;
262     },
263
264     /**
265      * @return {!Array.<!WebInspector.BreakpointManager.Breakpoint>}
266      */
267     allBreakpoints: function()
268     {
269         var result = [];
270         var uiSourceCodes = this._breakpointsForUISourceCode.keys();
271         for (var i = 0; i < uiSourceCodes.length; ++i)
272             result = result.concat(this.breakpointsForUISourceCode(uiSourceCodes[i]));
273         return result;
274     },
275
276     /**
277      * @param {!WebInspector.UISourceCode} uiSourceCode
278      * @return {!Array.<!{breakpoint: !WebInspector.BreakpointManager.Breakpoint, uiLocation: !WebInspector.UILocation}>}
279      */
280     breakpointLocationsForUISourceCode: function(uiSourceCode)
281     {
282         var uiSourceCodeBreakpoints = this._breakpointsForUISourceCode.get(uiSourceCode);
283         var lineNumbers = uiSourceCodeBreakpoints ? uiSourceCodeBreakpoints.keys() : [];
284         var result = [];
285         for (var i = 0; i < lineNumbers.length; ++i) {
286             var lineBreakpoints = uiSourceCodeBreakpoints.get(lineNumbers[i]);
287             var columnNumbers = lineBreakpoints.keys();
288             for (var j = 0; j < columnNumbers.length; ++j) {
289                 var columnBreakpoints = lineBreakpoints.get(columnNumbers[j]);
290                 var lineNumber = parseInt(lineNumbers[i], 10);
291                 var columnNumber = parseInt(columnNumbers[j], 10);
292                 for (var k = 0; k < columnBreakpoints.length; ++k) {
293                     var breakpoint = columnBreakpoints[k];
294                     var uiLocation = new WebInspector.UILocation(uiSourceCode, lineNumber, columnNumber);
295                     result.push({breakpoint: breakpoint, uiLocation: uiLocation});
296                 }
297             }
298         }
299         return result;
300     },
301
302     /**
303      * @return {!Array.<!{breakpoint: !WebInspector.BreakpointManager.Breakpoint, uiLocation: !WebInspector.UILocation}>}
304      */
305     allBreakpointLocations: function()
306     {
307         var result = [];
308         var uiSourceCodes = this._breakpointsForUISourceCode.keys();
309         for (var i = 0; i < uiSourceCodes.length; ++i)
310             result = result.concat(this.breakpointLocationsForUISourceCode(uiSourceCodes[i]));
311         return result;
312     },
313
314     /**
315      * @param {boolean} toggleState
316      */
317     toggleAllBreakpoints: function(toggleState)
318     {
319         var breakpoints = this.allBreakpoints();
320         for (var i = 0; i < breakpoints.length; ++i)
321             breakpoints[i].setEnabled(toggleState);
322     },
323
324     removeAllBreakpoints: function()
325     {
326         var breakpoints = this.allBreakpoints();
327         for (var i = 0; i < breakpoints.length; ++i)
328             breakpoints[i].remove();
329     },
330
331     removeProvisionalBreakpoints: function()
332     {
333         for (var debuggerId in this._breakpointForDebuggerId)
334             this._debuggerModel.removeBreakpoint(debuggerId);
335     },
336
337     _projectWillReset: function(event)
338     {
339         var project = /** @type {!WebInspector.Project} */ (event.data);
340         var uiSourceCodes = project.uiSourceCodes();
341         for (var i = 0; i < uiSourceCodes.length; ++i)
342             this._removeUISourceCode(uiSourceCodes[i]);
343     },
344
345     _breakpointResolved: function(event)
346     {
347         var breakpointId = /** @type {!DebuggerAgent.BreakpointId} */ (event.data.breakpointId);
348         var location = /** @type {!WebInspector.DebuggerModel.Location} */ (event.data.location);
349         var breakpoint = this._breakpointForDebuggerId[breakpointId];
350         if (!breakpoint)
351             return;
352         breakpoint._addResolvedLocation(location);
353     },
354
355     /**
356      * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint
357      * @param {boolean} removeFromStorage
358      */
359     _removeBreakpoint: function(breakpoint, removeFromStorage)
360     {
361         var uiSourceCode = breakpoint.uiSourceCode();
362         var breakpoints = uiSourceCode ? this._breakpointsForPrimaryUISourceCode.get(uiSourceCode) || [] : [];
363         var index = breakpoints.indexOf(breakpoint);
364         if (index > -1)
365             breakpoints.splice(index, 1);
366         console.assert(!breakpoint._debuggerId)
367         if (removeFromStorage)
368             this._storage._removeBreakpoint(breakpoint);
369     },
370
371     /**
372      * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint
373      * @param {!WebInspector.UILocation} uiLocation
374      */
375     _uiLocationAdded: function(breakpoint, uiLocation)
376     {
377         var breakpoints = this._breakpointsForUISourceCode.get(uiLocation.uiSourceCode);
378         if (!breakpoints) {
379             breakpoints = new StringMap();
380             this._breakpointsForUISourceCode.put(uiLocation.uiSourceCode, breakpoints);
381         }
382         var lineBreakpoints = breakpoints.get(String(uiLocation.lineNumber));
383         if (!lineBreakpoints) {
384             lineBreakpoints = new StringMap();
385             breakpoints.put(String(uiLocation.lineNumber), lineBreakpoints);
386         }
387         var columnBreakpoints = lineBreakpoints.get(String(uiLocation.columnNumber));
388         if (!columnBreakpoints) {
389             columnBreakpoints = [];
390             lineBreakpoints.put(String(uiLocation.columnNumber), columnBreakpoints);
391         }
392         columnBreakpoints.push(breakpoint);
393         this.dispatchEventToListeners(WebInspector.BreakpointManager.Events.BreakpointAdded, {breakpoint: breakpoint, uiLocation: uiLocation});
394     },
395
396     /**
397      * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint
398      * @param {!WebInspector.UILocation} uiLocation
399      */
400     _uiLocationRemoved: function(breakpoint, uiLocation)
401     {
402         var breakpoints = this._breakpointsForUISourceCode.get(uiLocation.uiSourceCode);
403         if (!breakpoints)
404             return;
405
406         var lineBreakpoints = breakpoints.get(String(uiLocation.lineNumber));
407         if (!lineBreakpoints)
408             return;
409         var columnBreakpoints = lineBreakpoints.get(String(uiLocation.columnNumber));
410         if (!columnBreakpoints)
411             return;
412         columnBreakpoints.remove(breakpoint);
413         if (!columnBreakpoints.length)
414             lineBreakpoints.remove(String(uiLocation.columnNumber));
415         if (!lineBreakpoints.size())
416             breakpoints.remove(String(uiLocation.lineNumber));
417         if (!breakpoints.size())
418             this._breakpointsForUISourceCode.remove(uiLocation.uiSourceCode);
419         this.dispatchEventToListeners(WebInspector.BreakpointManager.Events.BreakpointRemoved, {breakpoint: breakpoint, uiLocation: uiLocation});
420     },
421
422     __proto__: WebInspector.Object.prototype
423 }
424
425 /**
426  * @constructor
427  * @param {!WebInspector.BreakpointManager} breakpointManager
428  * @param {string} projectId
429  * @param {string} path
430  * @param {string} sourceFileId
431  * @param {number} lineNumber
432  * @param {number} columnNumber
433  * @param {string} condition
434  * @param {boolean} enabled
435  */
436 WebInspector.BreakpointManager.Breakpoint = function(breakpointManager, projectId, path, sourceFileId, lineNumber, columnNumber, condition, enabled)
437 {
438     this._breakpointManager = breakpointManager;
439     this._projectId = projectId;
440     this._path = path;
441     this._lineNumber = lineNumber;
442     this._columnNumber = columnNumber;
443     this._sourceFileId = sourceFileId;
444     /** @type {!Array.<!WebInspector.Script.Location>} */
445     this._liveLocations = [];
446     /** @type {!Object.<string, !WebInspector.UILocation>} */
447     this._uiLocations = {};
448
449     // Force breakpoint update.
450     /** @type {string} */ this._condition;
451     /** @type {boolean} */ this._enabled;
452     this._updateBreakpoint(condition, enabled);
453 }
454
455 WebInspector.BreakpointManager.Breakpoint.prototype = {
456     /**
457      * @return {string}
458      */
459     projectId: function()
460     {
461         return this._projectId;
462     },
463
464     /**
465      * @return {string}
466      */
467     path: function()
468     {
469         return this._path;
470     },
471
472     /**
473      * @return {number}
474      */
475     lineNumber: function()
476     {
477         return this._lineNumber;
478     },
479
480     /**
481      * @return {number}
482      */
483     columnNumber: function()
484     {
485         return this._columnNumber;
486     },
487
488     /**
489      * @return {?WebInspector.UISourceCode}
490      */
491     uiSourceCode: function()
492     {
493         return this._breakpointManager._workspace.uiSourceCode(this._projectId, this._path);
494     },
495
496     /**
497      * @param {!WebInspector.DebuggerModel.Location} location
498      */
499     _addResolvedLocation: function(location)
500     {
501         this._liveLocations.push(this._breakpointManager._debuggerModel.createLiveLocation(location, this._locationUpdated.bind(this, location)));
502     },
503
504     /**
505      * @param {!WebInspector.DebuggerModel.Location} location
506      * @param {!WebInspector.UILocation} uiLocation
507      */
508     _locationUpdated: function(location, uiLocation)
509     {
510         var stringifiedLocation = location.scriptId + ":" + location.lineNumber + ":" + location.columnNumber;
511         var oldUILocation = /** @type {!WebInspector.UILocation} */ (this._uiLocations[stringifiedLocation]);
512         if (oldUILocation)
513             this._breakpointManager._uiLocationRemoved(this, oldUILocation);
514         if (this._uiLocations[""]) {
515             var defaultLocation = this._uiLocations[""];
516             delete this._uiLocations[""];
517             this._breakpointManager._uiLocationRemoved(this, defaultLocation);
518         }
519         this._uiLocations[stringifiedLocation] = uiLocation;
520         this._breakpointManager._uiLocationAdded(this, uiLocation);
521     },
522
523     /**
524      * @return {boolean}
525      */
526     enabled: function()
527     {
528         return this._enabled;
529     },
530
531     /**
532      * @param {boolean} enabled
533      */
534     setEnabled: function(enabled)
535     {
536         this._updateBreakpoint(this._condition, enabled);
537     },
538
539     /**
540      * @return {string}
541      */
542     condition: function()
543     {
544         return this._condition;
545     },
546
547     /**
548      * @param {string} condition
549      */
550     setCondition: function(condition)
551     {
552         this._updateBreakpoint(condition, this._enabled);
553     },
554
555     /**
556      * @param {string} condition
557      * @param {boolean} enabled
558      */
559     _updateBreakpoint: function(condition, enabled)
560     {
561         if (this._enabled === enabled && this._condition === condition)
562             return;
563         this._removeFromDebugger();
564         this._enabled = enabled;
565         this._condition = condition;
566         this._breakpointManager._storage._updateBreakpoint(this);
567         this._fakeBreakpointAtPrimaryLocation();
568         this._updateInDebugger();
569     },
570
571     _updateInDebugger: function()
572     {
573         var uiSourceCode = this.uiSourceCode();
574         if (!uiSourceCode || !uiSourceCode.hasSourceMapping())
575             return;
576         var scriptFile = uiSourceCode && uiSourceCode.scriptFile();
577         if (this._enabled && !(scriptFile && scriptFile.hasDivergedFromVM()))
578             this._setInDebugger();
579     },
580
581     /**
582      * @param {boolean=} keepInStorage
583      */
584     remove: function(keepInStorage)
585     {
586         var removeFromStorage = !keepInStorage;
587         this._resetLocations();
588         this._removeFromDebugger();
589         this._breakpointManager._removeBreakpoint(this, removeFromStorage);
590     },
591
592     _setInDebugger: function()
593     {
594         this._removeFromDebugger();
595         var uiSourceCode = this._breakpointManager._workspace.uiSourceCode(this._projectId, this._path);
596         if (!uiSourceCode)
597             return;
598         var rawLocation = uiSourceCode.uiLocationToRawLocation(this._lineNumber, this._columnNumber);
599         var debuggerModelLocation = /** @type {!WebInspector.DebuggerModel.Location} */ (rawLocation);
600         if (debuggerModelLocation)
601             this._breakpointManager._debuggerModel.setBreakpointByScriptLocation(debuggerModelLocation, this._condition, this._didSetBreakpointInDebugger.bind(this));
602         else if (uiSourceCode.url)
603             this._breakpointManager._debuggerModel.setBreakpointByURL(uiSourceCode.url, this._lineNumber, this._columnNumber, this._condition, this._didSetBreakpointInDebugger.bind(this));
604     },
605
606     /**
607     * @this {WebInspector.BreakpointManager.Breakpoint}
608     * @param {?DebuggerAgent.BreakpointId} breakpointId
609     * @param {!Array.<!WebInspector.DebuggerModel.Location>} locations
610     */
611     _didSetBreakpointInDebugger: function(breakpointId, locations)
612     {
613         if (!breakpointId) {
614             this._resetLocations();
615             this._breakpointManager._removeBreakpoint(this, false);
616             return;
617         }
618
619         this._debuggerId = breakpointId;
620         this._breakpointManager._breakpointForDebuggerId[breakpointId] = this;
621
622         if (!locations.length) {
623             this._fakeBreakpointAtPrimaryLocation();
624             return;
625         }
626
627         this._resetLocations();
628         for (var i = 0; i < locations.length; ++i) {
629             var script = this._breakpointManager._debuggerModel.scriptForId(locations[i].scriptId);
630             var uiLocation = script.rawLocationToUILocation(locations[i].lineNumber, locations[i].columnNumber);
631             if (this._breakpointManager.findBreakpoint(uiLocation.uiSourceCode, uiLocation.lineNumber, uiLocation.columnNumber)) {
632                 // location clash
633                 this.remove();
634                 return;
635             }
636         }
637
638         for (var i = 0; i < locations.length; ++i)
639             this._addResolvedLocation(locations[i]);
640     },
641
642     _removeFromDebugger: function()
643     {
644         if (!this._debuggerId)
645             return;
646         this._breakpointManager._debuggerModel.removeBreakpoint(this._debuggerId);
647         delete this._breakpointManager._breakpointForDebuggerId[this._debuggerId];
648         delete this._debuggerId;
649     },
650
651     _resetLocations: function()
652     {
653         for (var stringifiedLocation in this._uiLocations)
654             this._breakpointManager._uiLocationRemoved(this, this._uiLocations[stringifiedLocation]);
655         for (var i = 0; i < this._liveLocations.length; ++i)
656             this._liveLocations[i].dispose();
657         this._liveLocations = [];
658         this._uiLocations = {};
659     },
660
661     /**
662      * @return {string}
663      */
664     _breakpointStorageId: function()
665     {
666         return WebInspector.BreakpointManager._breakpointStorageId(this._sourceFileId, this._lineNumber, this._columnNumber);
667     },
668
669     _fakeBreakpointAtPrimaryLocation: function()
670     {
671         this._resetLocations();
672         var uiSourceCode = this._breakpointManager._workspace.uiSourceCode(this._projectId, this._path);
673         if (!uiSourceCode)
674             return;
675         var uiLocation = new WebInspector.UILocation(uiSourceCode, this._lineNumber, this._columnNumber);
676         this._uiLocations[""] = uiLocation;
677         this._breakpointManager._uiLocationAdded(this, uiLocation);
678     }
679 }
680
681 /**
682  * @constructor
683  * @param {!WebInspector.BreakpointManager} breakpointManager
684  * @param {!WebInspector.Setting} setting
685  */
686 WebInspector.BreakpointManager.Storage = function(breakpointManager, setting)
687 {
688     this._breakpointManager = breakpointManager;
689     this._setting = setting;
690     var breakpoints = this._setting.get();
691     /** @type {!Object.<string, !WebInspector.BreakpointManager.Storage.Item>} */
692     this._breakpoints = {};
693     for (var i = 0; i < breakpoints.length; ++i) {
694         var breakpoint = /** @type {!WebInspector.BreakpointManager.Storage.Item} */ (breakpoints[i]);
695         breakpoint.columnNumber = breakpoint.columnNumber || 0;
696         this._breakpoints[breakpoint.sourceFileId + ":" + breakpoint.lineNumber + ":" + breakpoint.columnNumber] = breakpoint;
697     }
698 }
699
700 WebInspector.BreakpointManager.Storage.prototype = {
701     mute: function()
702     {
703         this._muted = true;
704     },
705
706     unmute: function()
707     {
708         delete this._muted;
709     },
710
711     /**
712      * @param {!WebInspector.UISourceCode} uiSourceCode
713      * @return {!Array.<!WebInspector.BreakpointManager.Storage.Item>}
714      */
715     breakpointItems: function(uiSourceCode)
716     {
717         var result = [];
718         var sourceFileId = WebInspector.BreakpointManager._sourceFileId(uiSourceCode);
719         for (var id in this._breakpoints) {
720             var breakpoint = this._breakpoints[id];
721             if (breakpoint.sourceFileId === sourceFileId)
722                 result.push(breakpoint);
723         }
724         return result;
725     },
726
727     /**
728      * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint
729      */
730     _updateBreakpoint: function(breakpoint)
731     {
732         if (this._muted || !breakpoint._breakpointStorageId())
733             return;
734         this._breakpoints[breakpoint._breakpointStorageId()] = new WebInspector.BreakpointManager.Storage.Item(breakpoint);
735         this._save();
736     },
737
738     /**
739      * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint
740      */
741     _removeBreakpoint: function(breakpoint)
742     {
743         if (this._muted)
744             return;
745         delete this._breakpoints[breakpoint._breakpointStorageId()];
746         this._save();
747     },
748
749     _save: function()
750     {
751         var breakpointsArray = [];
752         for (var id in this._breakpoints)
753             breakpointsArray.push(this._breakpoints[id]);
754         this._setting.set(breakpointsArray);
755     }
756 }
757
758 /**
759  * @constructor
760  * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint
761  */
762 WebInspector.BreakpointManager.Storage.Item = function(breakpoint)
763 {
764     this.sourceFileId = breakpoint._sourceFileId;
765     this.lineNumber = breakpoint.lineNumber();
766     this.columnNumber = breakpoint.columnNumber();
767     this.condition = breakpoint.condition();
768     this.enabled = breakpoint.enabled();
769 }
770
771 /** @type {!WebInspector.BreakpointManager} */
772 WebInspector.breakpointManager;