Upstream version 7.35.144.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     return uiSourceCode.uri();
65 }
66
67 /**
68  * @param {string} sourceFileId
69  * @param {number} lineNumber
70  * @param {number} columnNumber
71  * @return {string}
72  */
73 WebInspector.BreakpointManager._breakpointStorageId = function(sourceFileId, lineNumber, columnNumber)
74 {
75     if (!sourceFileId)
76         return "";
77     return sourceFileId + ":" + lineNumber + ":" + columnNumber;
78 }
79
80 WebInspector.BreakpointManager.prototype = {
81     /**
82      * @param {string} sourceFileId
83      */
84     _provisionalBreakpointsForSourceFileId: function(sourceFileId)
85     {
86         var result = new StringMap();
87         for (var debuggerId in this._breakpointForDebuggerId) {
88             var breakpoint = this._breakpointForDebuggerId[debuggerId];
89             if (breakpoint._sourceFileId === sourceFileId)
90                 result.put(breakpoint._breakpointStorageId(), breakpoint);
91         }
92         return result;
93     },
94
95     removeProvisionalBreakpointsForTest: function()
96     {
97         for (var debuggerId in this._breakpointForDebuggerId)
98             this._debuggerModel.removeBreakpoint(debuggerId);
99     },
100
101     /**
102      * @param {!WebInspector.UISourceCode} uiSourceCode
103      */
104     _restoreBreakpoints: function(uiSourceCode)
105     {
106         var sourceFileId = WebInspector.BreakpointManager._sourceFileId(uiSourceCode);
107         if (!sourceFileId || this._sourceFilesWithRestoredBreakpoints[sourceFileId])
108             return;
109         this._sourceFilesWithRestoredBreakpoints[sourceFileId] = true;
110
111         this._storage.mute();
112         var breakpointItems = this._storage.breakpointItems(uiSourceCode);
113         var provisionalBreakpoints = this._provisionalBreakpointsForSourceFileId(sourceFileId);
114         for (var i = 0; i < breakpointItems.length; ++i) {
115             var breakpointItem = breakpointItems[i];
116             var itemStorageId = WebInspector.BreakpointManager._breakpointStorageId(breakpointItem.sourceFileId, breakpointItem.lineNumber, breakpointItem.columnNumber);
117             var provisionalBreakpoint = provisionalBreakpoints.get(itemStorageId);
118             if (provisionalBreakpoint) {
119                 if (!this._breakpointsForPrimaryUISourceCode.get(uiSourceCode))
120                     this._breakpointsForPrimaryUISourceCode.put(uiSourceCode, []);
121                 this._breakpointsForPrimaryUISourceCode.get(uiSourceCode).push(provisionalBreakpoint);
122                 provisionalBreakpoint._updateInDebugger();
123             } else {
124                 this._innerSetBreakpoint(uiSourceCode, breakpointItem.lineNumber, breakpointItem.columnNumber, breakpointItem.condition, breakpointItem.enabled);
125             }
126         }
127         this._storage.unmute();
128     },
129
130     /**
131      * @param {!WebInspector.Event} event
132      */
133     _uiSourceCodeAdded: function(event)
134     {
135         var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
136         this._restoreBreakpoints(uiSourceCode);
137         if (uiSourceCode.contentType() === WebInspector.resourceTypes.Script || uiSourceCode.contentType() === WebInspector.resourceTypes.Document)
138             uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.SourceMappingChanged, this._uiSourceCodeMappingChanged, this);
139     },
140
141     /**
142      * @param {!WebInspector.Event} event
143      */
144     _uiSourceCodeRemoved: function(event)
145     {
146         var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.data);
147         this._removeUISourceCode(uiSourceCode);
148     },
149
150     /**
151      * @param {!WebInspector.Event} event
152      */
153     _uiSourceCodeMappingChanged: function(event)
154     {
155         var uiSourceCode = /** @type {!WebInspector.UISourceCode} */ (event.target);
156         var isIdentity = /** @type {boolean} */ (event.data.isIdentity);
157         if (isIdentity)
158             return;
159         var breakpoints = this._breakpointsForPrimaryUISourceCode.get(uiSourceCode) || [];
160         for (var i = 0; i < breakpoints.length; ++i)
161             breakpoints[i]._updateInDebugger();
162     },
163
164     /**
165      * @param {!WebInspector.UISourceCode} uiSourceCode
166      */
167     _removeUISourceCode: function(uiSourceCode)
168     {
169         var breakpoints = this._breakpointsForPrimaryUISourceCode.get(uiSourceCode) || [];
170         for (var i = 0; i < breakpoints.length; ++i)
171             breakpoints[i]._resetLocations();
172         var sourceFileId = WebInspector.BreakpointManager._sourceFileId(uiSourceCode);
173         delete this._sourceFilesWithRestoredBreakpoints[sourceFileId];
174         uiSourceCode.removeEventListener(WebInspector.UISourceCode.Events.SourceMappingChanged, this._uiSourceCodeMappingChanged, this);
175         this._breakpointsForPrimaryUISourceCode.remove(uiSourceCode);
176     },
177
178     /**
179      * @param {!WebInspector.UISourceCode} uiSourceCode
180      * @param {number} lineNumber
181      * @param {number} columnNumber
182      * @param {string} condition
183      * @param {boolean} enabled
184      * @return {!WebInspector.BreakpointManager.Breakpoint}
185      */
186     setBreakpoint: function(uiSourceCode, lineNumber, columnNumber, condition, enabled)
187     {
188         this._debuggerModel.setBreakpointsActive(true);
189         return this._innerSetBreakpoint(uiSourceCode, lineNumber, columnNumber, condition, enabled);
190     },
191
192     /**
193      * @param {!WebInspector.UISourceCode} uiSourceCode
194      * @param {number} lineNumber
195      * @param {number} columnNumber
196      * @param {string} condition
197      * @param {boolean} enabled
198      * @return {!WebInspector.BreakpointManager.Breakpoint}
199      */
200     _innerSetBreakpoint: function(uiSourceCode, lineNumber, columnNumber, condition, enabled)
201     {
202         var breakpoint = this.findBreakpoint(uiSourceCode, lineNumber, columnNumber);
203         if (breakpoint) {
204             breakpoint._updateBreakpoint(condition, enabled);
205             return breakpoint;
206         }
207         var projectId = uiSourceCode.project().id();
208         var path = uiSourceCode.path();
209         var sourceFileId = WebInspector.BreakpointManager._sourceFileId(uiSourceCode);
210         breakpoint = new WebInspector.BreakpointManager.Breakpoint(this, projectId, path, sourceFileId, lineNumber, columnNumber, condition, enabled);
211         if (!this._breakpointsForPrimaryUISourceCode.get(uiSourceCode))
212             this._breakpointsForPrimaryUISourceCode.put(uiSourceCode, []);
213         this._breakpointsForPrimaryUISourceCode.get(uiSourceCode).push(breakpoint);
214         return breakpoint;
215     },
216
217     /**
218      * @param {!WebInspector.UISourceCode} uiSourceCode
219      * @param {number} lineNumber
220      * @param {number} columnNumber
221      * @return {?WebInspector.BreakpointManager.Breakpoint}
222      */
223     findBreakpoint: function(uiSourceCode, lineNumber, columnNumber)
224     {
225         var breakpoints = this._breakpointsForUISourceCode.get(uiSourceCode);
226         var lineBreakpoints = breakpoints ? breakpoints.get(String(lineNumber)) : null;
227         var columnBreakpoints = lineBreakpoints ? lineBreakpoints.get(String(columnNumber)) : null;
228         return columnBreakpoints ? columnBreakpoints[0] : null;
229     },
230
231     /**
232      * @param {!WebInspector.UISourceCode} uiSourceCode
233      * @param {number} lineNumber
234      * @return {?WebInspector.BreakpointManager.Breakpoint}
235      */
236     findBreakpointOnLine: function(uiSourceCode, lineNumber)
237     {
238         var breakpoints = this._breakpointsForUISourceCode.get(uiSourceCode);
239         var lineBreakpoints = breakpoints ? breakpoints.get(String(lineNumber)) : null;
240         return lineBreakpoints ? lineBreakpoints.values()[0][0] : null;
241     },
242
243     /**
244      * @param {!WebInspector.UISourceCode} uiSourceCode
245      * @return {!Array.<!WebInspector.BreakpointManager.Breakpoint>}
246      */
247     breakpointsForUISourceCode: function(uiSourceCode)
248     {
249         var result = [];
250         var uiSourceCodeBreakpoints = this._breakpointsForUISourceCode.get(uiSourceCode);
251         var breakpoints = uiSourceCodeBreakpoints ? uiSourceCodeBreakpoints.values() : [];
252         for (var i = 0; i < breakpoints.length; ++i) {
253             var lineBreakpoints = breakpoints[i];
254             var columnBreakpointArrays = lineBreakpoints ? lineBreakpoints.values() : [];
255             result = result.concat.apply(result, columnBreakpointArrays);
256         }
257         return result;
258     },
259
260     /**
261      * @return {!Array.<!WebInspector.BreakpointManager.Breakpoint>}
262      */
263     allBreakpoints: function()
264     {
265         var result = [];
266         var uiSourceCodes = this._breakpointsForUISourceCode.keys();
267         for (var i = 0; i < uiSourceCodes.length; ++i)
268             result = result.concat(this.breakpointsForUISourceCode(uiSourceCodes[i]));
269         return result;
270     },
271
272     /**
273      * @param {!WebInspector.UISourceCode} uiSourceCode
274      * @return {!Array.<!{breakpoint: !WebInspector.BreakpointManager.Breakpoint, uiLocation: !WebInspector.UILocation}>}
275      */
276     breakpointLocationsForUISourceCode: function(uiSourceCode)
277     {
278         var uiSourceCodeBreakpoints = this._breakpointsForUISourceCode.get(uiSourceCode);
279         var lineNumbers = uiSourceCodeBreakpoints ? uiSourceCodeBreakpoints.keys() : [];
280         var result = [];
281         for (var i = 0; i < lineNumbers.length; ++i) {
282             var lineBreakpoints = uiSourceCodeBreakpoints.get(lineNumbers[i]);
283             var columnNumbers = lineBreakpoints.keys();
284             for (var j = 0; j < columnNumbers.length; ++j) {
285                 var columnBreakpoints = lineBreakpoints.get(columnNumbers[j]);
286                 var lineNumber = parseInt(lineNumbers[i], 10);
287                 var columnNumber = parseInt(columnNumbers[j], 10);
288                 for (var k = 0; k < columnBreakpoints.length; ++k) {
289                     var breakpoint = columnBreakpoints[k];
290                     var uiLocation = new WebInspector.UILocation(uiSourceCode, lineNumber, columnNumber);
291                     result.push({breakpoint: breakpoint, uiLocation: uiLocation});
292                 }
293             }
294         }
295         return result;
296     },
297
298     /**
299      * @return {!Array.<!{breakpoint: !WebInspector.BreakpointManager.Breakpoint, uiLocation: !WebInspector.UILocation}>}
300      */
301     allBreakpointLocations: function()
302     {
303         var result = [];
304         var uiSourceCodes = this._breakpointsForUISourceCode.keys();
305         for (var i = 0; i < uiSourceCodes.length; ++i)
306             result = result.concat(this.breakpointLocationsForUISourceCode(uiSourceCodes[i]));
307         return result;
308     },
309
310     /**
311      * @param {boolean} toggleState
312      */
313     toggleAllBreakpoints: function(toggleState)
314     {
315         var breakpoints = this.allBreakpoints();
316         for (var i = 0; i < breakpoints.length; ++i)
317             breakpoints[i].setEnabled(toggleState);
318     },
319
320     removeAllBreakpoints: function()
321     {
322         var breakpoints = this.allBreakpoints();
323         for (var i = 0; i < breakpoints.length; ++i)
324             breakpoints[i].remove();
325     },
326
327     _projectWillReset: function(event)
328     {
329         var project = /** @type {!WebInspector.Project} */ (event.data);
330         var uiSourceCodes = project.uiSourceCodes();
331         for (var i = 0; i < uiSourceCodes.length; ++i)
332             this._removeUISourceCode(uiSourceCodes[i]);
333     },
334
335     _breakpointResolved: function(event)
336     {
337         var breakpointId = /** @type {!DebuggerAgent.BreakpointId} */ (event.data.breakpointId);
338         var location = /** @type {!WebInspector.DebuggerModel.Location} */ (event.data.location);
339         var breakpoint = this._breakpointForDebuggerId[breakpointId];
340         if (!breakpoint)
341             return;
342         breakpoint._addResolvedLocation(location);
343     },
344
345     /**
346      * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint
347      * @param {boolean} removeFromStorage
348      */
349     _removeBreakpoint: function(breakpoint, removeFromStorage)
350     {
351         var uiSourceCode = breakpoint.uiSourceCode();
352         var breakpoints = uiSourceCode ? this._breakpointsForPrimaryUISourceCode.get(uiSourceCode) || [] : [];
353         var index = breakpoints.indexOf(breakpoint);
354         if (index > -1)
355             breakpoints.splice(index, 1);
356         if (removeFromStorage)
357             this._storage._removeBreakpoint(breakpoint);
358     },
359
360     /**
361      * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint
362      * @param {!WebInspector.UILocation} uiLocation
363      */
364     _uiLocationAdded: function(breakpoint, uiLocation)
365     {
366         var breakpoints = this._breakpointsForUISourceCode.get(uiLocation.uiSourceCode);
367         if (!breakpoints) {
368             breakpoints = new StringMap();
369             this._breakpointsForUISourceCode.put(uiLocation.uiSourceCode, breakpoints);
370         }
371         var lineBreakpoints = breakpoints.get(String(uiLocation.lineNumber));
372         if (!lineBreakpoints) {
373             lineBreakpoints = new StringMap();
374             breakpoints.put(String(uiLocation.lineNumber), lineBreakpoints);
375         }
376         var columnBreakpoints = lineBreakpoints.get(String(uiLocation.columnNumber));
377         if (!columnBreakpoints) {
378             columnBreakpoints = [];
379             lineBreakpoints.put(String(uiLocation.columnNumber), columnBreakpoints);
380         }
381         columnBreakpoints.push(breakpoint);
382         this.dispatchEventToListeners(WebInspector.BreakpointManager.Events.BreakpointAdded, {breakpoint: breakpoint, uiLocation: uiLocation});
383     },
384
385     /**
386      * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint
387      * @param {!WebInspector.UILocation} uiLocation
388      */
389     _uiLocationRemoved: function(breakpoint, uiLocation)
390     {
391         var breakpoints = this._breakpointsForUISourceCode.get(uiLocation.uiSourceCode);
392         if (!breakpoints)
393             return;
394
395         var lineBreakpoints = breakpoints.get(String(uiLocation.lineNumber));
396         if (!lineBreakpoints)
397             return;
398         var columnBreakpoints = lineBreakpoints.get(String(uiLocation.columnNumber));
399         if (!columnBreakpoints)
400             return;
401         columnBreakpoints.remove(breakpoint);
402         if (!columnBreakpoints.length)
403             lineBreakpoints.remove(String(uiLocation.columnNumber));
404         if (!lineBreakpoints.size())
405             breakpoints.remove(String(uiLocation.lineNumber));
406         if (!breakpoints.size())
407             this._breakpointsForUISourceCode.remove(uiLocation.uiSourceCode);
408         this.dispatchEventToListeners(WebInspector.BreakpointManager.Events.BreakpointRemoved, {breakpoint: breakpoint, uiLocation: uiLocation});
409     },
410
411     __proto__: WebInspector.Object.prototype
412 }
413
414 /**
415  * @constructor
416  * @param {!WebInspector.BreakpointManager} breakpointManager
417  * @param {string} projectId
418  * @param {string} path
419  * @param {string} sourceFileId
420  * @param {number} lineNumber
421  * @param {number} columnNumber
422  * @param {string} condition
423  * @param {boolean} enabled
424  */
425 WebInspector.BreakpointManager.Breakpoint = function(breakpointManager, projectId, path, sourceFileId, lineNumber, columnNumber, condition, enabled)
426 {
427     this._breakpointManager = breakpointManager;
428     this._projectId = projectId;
429     this._path = path;
430     this._lineNumber = lineNumber;
431     this._columnNumber = columnNumber;
432     this._sourceFileId = sourceFileId;
433     /** @type {!Array.<!WebInspector.Script.Location>} */
434     this._liveLocations = [];
435     /** @type {!Object.<string, !WebInspector.UILocation>} */
436     this._uiLocations = {};
437
438     // Force breakpoint update.
439     /** @type {string} */ this._condition;
440     /** @type {boolean} */ this._enabled;
441     this._updateBreakpoint(condition, enabled);
442 }
443
444 WebInspector.BreakpointManager.Breakpoint.prototype = {
445     /**
446      * @return {string}
447      */
448     projectId: function()
449     {
450         return this._projectId;
451     },
452
453     /**
454      * @return {string}
455      */
456     path: function()
457     {
458         return this._path;
459     },
460
461     /**
462      * @return {number}
463      */
464     lineNumber: function()
465     {
466         return this._lineNumber;
467     },
468
469     /**
470      * @return {number}
471      */
472     columnNumber: function()
473     {
474         return this._columnNumber;
475     },
476
477     /**
478      * @return {?WebInspector.UISourceCode}
479      */
480     uiSourceCode: function()
481     {
482         return this._breakpointManager._workspace.uiSourceCode(this._projectId, this._path);
483     },
484
485     /**
486      * @param {!WebInspector.DebuggerModel.Location} location
487      */
488     _addResolvedLocation: function(location)
489     {
490         this._liveLocations.push(this._breakpointManager._debuggerModel.createLiveLocation(location, this._locationUpdated.bind(this, location)));
491     },
492
493     /**
494      * @param {!WebInspector.DebuggerModel.Location} location
495      * @param {!WebInspector.UILocation} uiLocation
496      */
497     _locationUpdated: function(location, uiLocation)
498     {
499         var stringifiedLocation = location.scriptId + ":" + location.lineNumber + ":" + location.columnNumber;
500         var oldUILocation = /** @type {!WebInspector.UILocation} */ (this._uiLocations[stringifiedLocation]);
501         if (oldUILocation)
502             this._breakpointManager._uiLocationRemoved(this, oldUILocation);
503         if (this._uiLocations[""]) {
504             var defaultLocation = this._uiLocations[""];
505             delete this._uiLocations[""];
506             this._breakpointManager._uiLocationRemoved(this, defaultLocation);
507         }
508         this._uiLocations[stringifiedLocation] = uiLocation;
509         this._breakpointManager._uiLocationAdded(this, uiLocation);
510     },
511
512     /**
513      * @return {boolean}
514      */
515     enabled: function()
516     {
517         return this._enabled;
518     },
519
520     /**
521      * @param {boolean} enabled
522      */
523     setEnabled: function(enabled)
524     {
525         this._updateBreakpoint(this._condition, enabled);
526     },
527
528     /**
529      * @return {string}
530      */
531     condition: function()
532     {
533         return this._condition;
534     },
535
536     /**
537      * @param {string} condition
538      */
539     setCondition: function(condition)
540     {
541         this._updateBreakpoint(condition, this._enabled);
542     },
543
544     /**
545      * @param {string} condition
546      * @param {boolean} enabled
547      */
548     _updateBreakpoint: function(condition, enabled)
549     {
550         if (this._enabled === enabled && this._condition === condition)
551             return;
552         this._removeFromDebugger();
553         this._enabled = enabled;
554         this._condition = condition;
555         this._breakpointManager._storage._updateBreakpoint(this);
556         this._fakeBreakpointAtPrimaryLocation();
557         this._updateInDebugger();
558     },
559
560     _updateInDebugger: function()
561     {
562         var uiSourceCode = this.uiSourceCode();
563         if (!uiSourceCode)
564             return;
565         var scriptFile = uiSourceCode && uiSourceCode.scriptFile();
566         if (this._enabled && !(scriptFile && scriptFile.hasDivergedFromVM()))
567             this._setInDebugger();
568     },
569
570     /**
571      * @param {boolean=} keepInStorage
572      */
573     remove: function(keepInStorage)
574     {
575         var removeFromStorage = !keepInStorage;
576         this._resetLocations();
577         this._removeFromDebugger();
578         this._breakpointManager._removeBreakpoint(this, removeFromStorage);
579     },
580
581     _setInDebugger: function()
582     {
583         this._removeFromDebugger();
584         var uiSourceCode = this._breakpointManager._workspace.uiSourceCode(this._projectId, this._path);
585         if (!uiSourceCode)
586             return;
587         var rawLocation = uiSourceCode.uiLocationToRawLocation(this._lineNumber, this._columnNumber);
588         var debuggerModelLocation = /** @type {!WebInspector.DebuggerModel.Location} */ (rawLocation);
589         if (debuggerModelLocation)
590             this._breakpointManager._debuggerModel.setBreakpointByScriptLocation(debuggerModelLocation, this._condition, this._didSetBreakpointInDebugger.bind(this));
591         else if (uiSourceCode.url)
592             this._breakpointManager._debuggerModel.setBreakpointByURL(uiSourceCode.url, this._lineNumber, this._columnNumber, this._condition, this._didSetBreakpointInDebugger.bind(this));
593     },
594
595     /**
596     * @param {?DebuggerAgent.BreakpointId} breakpointId
597     * @param {!Array.<!WebInspector.DebuggerModel.Location>} locations
598     */
599     _didSetBreakpointInDebugger: function(breakpointId, locations)
600     {
601         if (!breakpointId) {
602             this._resetLocations();
603             this._breakpointManager._removeBreakpoint(this, false);
604             return;
605         }
606
607         this._debuggerId = breakpointId;
608         this._breakpointManager._breakpointForDebuggerId[breakpointId] = this;
609
610         if (!locations.length) {
611             this._fakeBreakpointAtPrimaryLocation();
612             return;
613         }
614
615         this._resetLocations();
616         for (var i = 0; i < locations.length; ++i) {
617             var script = this._breakpointManager._debuggerModel.scriptForId(locations[i].scriptId);
618             var uiLocation = script.rawLocationToUILocation(locations[i].lineNumber, locations[i].columnNumber);
619             if (this._breakpointManager.findBreakpoint(uiLocation.uiSourceCode, uiLocation.lineNumber, uiLocation.columnNumber)) {
620                 // location clash
621                 this.remove();
622                 return;
623             }
624         }
625
626         for (var i = 0; i < locations.length; ++i)
627             this._addResolvedLocation(locations[i]);
628     },
629
630     _removeFromDebugger: function()
631     {
632         if (!this._debuggerId)
633             return;
634         this._breakpointManager._debuggerModel.removeBreakpoint(this._debuggerId, this._didRemoveFromDebugger.bind(this));
635     },
636
637     _didRemoveFromDebugger: function()
638     {
639         delete this._breakpointManager._breakpointForDebuggerId[this._debuggerId];
640         delete this._debuggerId;
641     },
642
643     _resetLocations: function()
644     {
645         for (var stringifiedLocation in this._uiLocations)
646             this._breakpointManager._uiLocationRemoved(this, this._uiLocations[stringifiedLocation]);
647         for (var i = 0; i < this._liveLocations.length; ++i)
648             this._liveLocations[i].dispose();
649         this._liveLocations = [];
650         this._uiLocations = {};
651     },
652
653     /**
654      * @return {string}
655      */
656     _breakpointStorageId: function()
657     {
658         return WebInspector.BreakpointManager._breakpointStorageId(this._sourceFileId, this._lineNumber, this._columnNumber);
659     },
660
661     _fakeBreakpointAtPrimaryLocation: function()
662     {
663         this._resetLocations();
664         var uiSourceCode = this._breakpointManager._workspace.uiSourceCode(this._projectId, this._path);
665         if (!uiSourceCode)
666             return;
667         var uiLocation = new WebInspector.UILocation(uiSourceCode, this._lineNumber, this._columnNumber);
668         this._uiLocations[""] = uiLocation;
669         this._breakpointManager._uiLocationAdded(this, uiLocation);
670     }
671 }
672
673 /**
674  * @constructor
675  * @param {!WebInspector.BreakpointManager} breakpointManager
676  * @param {!WebInspector.Setting} setting
677  */
678 WebInspector.BreakpointManager.Storage = function(breakpointManager, setting)
679 {
680     this._breakpointManager = breakpointManager;
681     this._setting = setting;
682     var breakpoints = this._setting.get();
683     /** @type {!Object.<string, !WebInspector.BreakpointManager.Storage.Item>} */
684     this._breakpoints = {};
685     for (var i = 0; i < breakpoints.length; ++i) {
686         var breakpoint = /** @type {!WebInspector.BreakpointManager.Storage.Item} */ (breakpoints[i]);
687         breakpoint.columnNumber = breakpoint.columnNumber || 0;
688         this._breakpoints[breakpoint.sourceFileId + ":" + breakpoint.lineNumber + ":" + breakpoint.columnNumber] = breakpoint;
689     }
690 }
691
692 WebInspector.BreakpointManager.Storage.prototype = {
693     mute: function()
694     {
695         this._muted = true;
696     },
697
698     unmute: function()
699     {
700         delete this._muted;
701     },
702
703     /**
704      * @param {!WebInspector.UISourceCode} uiSourceCode
705      * @return {!Array.<!WebInspector.BreakpointManager.Storage.Item>}
706      */
707     breakpointItems: function(uiSourceCode)
708     {
709         var result = [];
710         var sourceFileId = WebInspector.BreakpointManager._sourceFileId(uiSourceCode);
711         for (var id in this._breakpoints) {
712             var breakpoint = this._breakpoints[id];
713             if (breakpoint.sourceFileId === sourceFileId)
714                 result.push(breakpoint);
715         }
716         return result;
717     },
718
719     /**
720      * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint
721      */
722     _updateBreakpoint: function(breakpoint)
723     {
724         if (this._muted || !breakpoint._breakpointStorageId())
725             return;
726         this._breakpoints[breakpoint._breakpointStorageId()] = new WebInspector.BreakpointManager.Storage.Item(breakpoint);
727         this._save();
728     },
729
730     /**
731      * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint
732      */
733     _removeBreakpoint: function(breakpoint)
734     {
735         if (this._muted)
736             return;
737         delete this._breakpoints[breakpoint._breakpointStorageId()];
738         this._save();
739     },
740
741     _save: function()
742     {
743         var breakpointsArray = [];
744         for (var id in this._breakpoints)
745             breakpointsArray.push(this._breakpoints[id]);
746         this._setting.set(breakpointsArray);
747     }
748 }
749
750 /**
751  * @constructor
752  * @param {!WebInspector.BreakpointManager.Breakpoint} breakpoint
753  */
754 WebInspector.BreakpointManager.Storage.Item = function(breakpoint)
755 {
756     this.sourceFileId = breakpoint._sourceFileId;
757     this.lineNumber = breakpoint.lineNumber();
758     this.columnNumber = breakpoint.columnNumber();
759     this.condition = breakpoint.condition();
760     this.enabled = breakpoint.enabled();
761 }
762
763 /** @type {!WebInspector.BreakpointManager} */
764 WebInspector.breakpointManager;