Web Inspector: Remove InspectorFrontendHost load/saveSessionSetting
[WebKit-https.git] / Source / WebKit / mac / WebCoreSupport / WebInspectorClient.mm
1 /*
2  * Copyright (C) 2006, 2007, 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  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #import "WebInspectorClient.h"
30
31 #import "DOMNodeInternal.h"
32 #import "WebDelegateImplementationCaching.h"
33 #import "WebFrameInternal.h"
34 #import "WebFrameView.h"
35 #import "WebInspector.h"
36 #import "WebInspectorPrivate.h"
37 #import "WebInspectorFrontend.h"
38 #import "WebLocalizableStringsInternal.h"
39 #import "WebNodeHighlighter.h"
40 #import "WebUIDelegate.h"
41 #import "WebViewInternal.h"
42 #import <WebCore/InspectorController.h>
43 #import <WebCore/Page.h>
44 #import <WebKit/DOMExtensions.h>
45 #import <WebKitSystemInterface.h>
46 #import <wtf/PassOwnPtr.h>
47
48 using namespace WebCore;
49
50 @interface WebInspectorWindowController : NSWindowController <NSWindowDelegate> {
51 @private
52     RetainPtr<WebView> _inspectedWebView;
53     WebView *_webView;
54     WebInspectorFrontendClient* _frontendClient;
55     WebInspectorClient* _inspectorClient;
56     BOOL _attachedToInspectedWebView;
57     BOOL _shouldAttach;
58     BOOL _visible;
59     BOOL _destroyingInspectorView;
60 }
61 - (id)initWithInspectedWebView:(WebView *)webView;
62 - (WebView *)webView;
63 - (void)attach;
64 - (void)detach;
65 - (BOOL)attached;
66 - (void)setFrontendClient:(WebInspectorFrontendClient*)frontendClient;
67 - (void)setInspectorClient:(WebInspectorClient*)inspectorClient;
68 - (WebInspectorClient*)inspectorClient;
69 - (void)setAttachedWindowHeight:(unsigned)height;
70 - (void)destroyInspectorView:(bool)notifyInspectorController;
71 @end
72
73
74 // MARK: -
75
76 WebInspectorClient::WebInspectorClient(WebView *webView)
77     : m_webView(webView)
78     , m_highlighter(AdoptNS, [[WebNodeHighlighter alloc] initWithInspectedWebView:webView])
79     , m_frontendPage(0)
80 {
81 }
82
83 void WebInspectorClient::inspectorDestroyed()
84 {
85     delete this;
86 }
87
88 void WebInspectorClient::openInspectorFrontend(InspectorController* inspectorController)
89 {
90     RetainPtr<WebInspectorWindowController> windowController(AdoptNS, [[WebInspectorWindowController alloc] initWithInspectedWebView:m_webView]);
91     [windowController.get() setInspectorClient:this];
92
93     m_frontendPage = core([windowController.get() webView]);
94     OwnPtr<WebInspectorFrontendClient> frontendClient = adoptPtr(new WebInspectorFrontendClient(m_webView, windowController.get(), inspectorController, m_frontendPage, createFrontendSettings()));
95     RetainPtr<WebInspectorFrontend> webInspectorFrontend(AdoptNS, [[WebInspectorFrontend alloc] initWithFrontendClient:frontendClient.get()]);
96     [[m_webView inspector] setFrontend:webInspectorFrontend.get()];
97     m_frontendPage->inspectorController()->setInspectorFrontendClient(frontendClient.release());
98 }
99
100 void WebInspectorClient::highlight()
101 {
102     [m_highlighter.get() highlight];
103 }
104
105 void WebInspectorClient::hideHighlight()
106 {
107     [m_highlighter.get() hideHighlight];
108 }
109
110 WebInspectorFrontendClient::WebInspectorFrontendClient(WebView* inspectedWebView, WebInspectorWindowController* windowController, InspectorController* inspectorController, Page* frontendPage, WTF::PassOwnPtr<Settings> settings)
111     : InspectorFrontendClientLocal(inspectorController,  frontendPage, settings)
112     , m_inspectedWebView(inspectedWebView)
113     , m_windowController(windowController)
114 {
115     [windowController setFrontendClient:this];
116 }
117
118 void WebInspectorFrontendClient::frontendLoaded()
119 {
120     [m_windowController.get() showWindow:nil];
121     if ([m_windowController.get() attached])
122         restoreAttachedWindowHeight();
123
124     InspectorFrontendClientLocal::frontendLoaded();
125
126     WebFrame *frame = [m_inspectedWebView mainFrame];
127     
128     WebFrameLoadDelegateImplementationCache* implementations = WebViewGetFrameLoadDelegateImplementations(m_inspectedWebView);
129     if (implementations->didClearInspectorWindowObjectForFrameFunc)
130         CallFrameLoadDelegate(implementations->didClearInspectorWindowObjectForFrameFunc, m_inspectedWebView,
131                               @selector(webView:didClearInspectorWindowObject:forFrame:), [frame windowObject], frame);
132
133     bool attached = [m_windowController.get() attached];
134     setAttachedWindow(attached);
135 }
136
137 String WebInspectorFrontendClient::localizedStringsURL()
138 {
139     NSString *path = [[NSBundle bundleWithIdentifier:@"com.apple.WebCore"] pathForResource:@"localizedStrings" ofType:@"js"];
140     if (path)
141         return [[NSURL fileURLWithPath:path] absoluteString];
142     return String();
143 }
144
145 String WebInspectorFrontendClient::hiddenPanels()
146 {
147     NSString *hiddenPanels = [[NSUserDefaults standardUserDefaults] stringForKey:@"WebKitInspectorHiddenPanels"];
148     if (hiddenPanels)
149         return hiddenPanels;
150     return String();
151 }
152
153 void WebInspectorFrontendClient::bringToFront()
154 {
155     updateWindowTitle();
156     [m_windowController.get() showWindow:nil];
157 }
158
159 void WebInspectorFrontendClient::closeWindow()
160 {
161     [m_windowController.get() destroyInspectorView:true];
162 }
163
164 void WebInspectorFrontendClient::disconnectFromBackend()
165 {
166     [m_windowController.get() destroyInspectorView:false];
167 }
168
169 void WebInspectorFrontendClient::attachWindow()
170 {
171     if ([m_windowController.get() attached])
172         return;
173     [m_windowController.get() attach];
174     restoreAttachedWindowHeight();
175 }
176
177 void WebInspectorFrontendClient::detachWindow()
178 {
179     [m_windowController.get() detach];
180 }
181
182 void WebInspectorFrontendClient::setAttachedWindowHeight(unsigned height)
183 {
184     [m_windowController.get() setAttachedWindowHeight:height];
185 }
186
187 void WebInspectorFrontendClient::inspectedURLChanged(const String& newURL)
188 {
189     m_inspectedURL = newURL;
190     updateWindowTitle();
191 }
192
193 void WebInspectorFrontendClient::updateWindowTitle() const
194 {
195     NSString *title = [NSString stringWithFormat:UI_STRING_INTERNAL("Web Inspector — %@", "Web Inspector window title"), (NSString *)m_inspectedURL];
196     [[m_windowController.get() window] setTitle:title];
197 }
198
199
200 // MARK: -
201
202 @implementation WebInspectorWindowController
203 - (id)init
204 {
205     if (!(self = [super initWithWindow:nil]))
206         return nil;
207
208     // Keep preferences separate from the rest of the client, making sure we are using expected preference values.
209
210     WebPreferences *preferences = [[WebPreferences alloc] init];
211     [preferences setAutosaves:NO];
212     [preferences setLoadsImagesAutomatically:YES];
213     [preferences setAuthorAndUserStylesEnabled:YES];
214     [preferences setJavaScriptEnabled:YES];
215     [preferences setAllowsAnimatedImages:YES];
216     [preferences setPlugInsEnabled:NO];
217     [preferences setJavaEnabled:NO];
218     [preferences setUserStyleSheetEnabled:NO];
219     [preferences setTabsToLinks:NO];
220     [preferences setMinimumFontSize:0];
221     [preferences setMinimumLogicalFontSize:9];
222 #ifndef BUILDING_ON_LEOPARD
223     [preferences setFixedFontFamily:@"Menlo"];
224     [preferences setDefaultFixedFontSize:11];
225 #else
226     [preferences setFixedFontFamily:@"Monaco"];
227     [preferences setDefaultFixedFontSize:10];
228 #endif
229
230     _webView = [[WebView alloc] init];
231     [_webView setPreferences:preferences];
232     [_webView setDrawsBackground:NO];
233     [_webView setProhibitsMainFrameScrolling:YES];
234     [_webView setUIDelegate:self];
235
236     [preferences release];
237
238     NSString *path = [[NSBundle bundleWithIdentifier:@"com.apple.WebCore"] pathForResource:@"inspector" ofType:@"html" inDirectory:@"inspector"];
239     NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL fileURLWithPath:path]];
240     [[_webView mainFrame] loadRequest:request];
241     [request release];
242
243     [self setWindowFrameAutosaveName:@"Web Inspector 2"];
244     return self;
245 }
246
247 - (id)initWithInspectedWebView:(WebView *)webView
248 {
249     if (!(self = [self init]))
250         return nil;
251
252     _inspectedWebView = webView;
253     return self;
254 }
255
256 - (void)dealloc
257 {
258     [_webView release];
259     [super dealloc];
260 }
261
262 // MARK: -
263
264 - (WebView *)webView
265 {
266     return _webView;
267 }
268
269 - (NSWindow *)window
270 {
271     NSWindow *window = [super window];
272     if (window)
273         return window;
274
275     NSUInteger styleMask = (NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask);
276
277     styleMask |= NSTexturedBackgroundWindowMask;
278
279     window = [[NSWindow alloc] initWithContentRect:NSMakeRect(60.0, 200.0, 750.0, 650.0) styleMask:styleMask backing:NSBackingStoreBuffered defer:NO];
280     [window setDelegate:self];
281     [window setMinSize:NSMakeSize(400.0, 400.0)];
282
283     [window setAutorecalculatesContentBorderThickness:NO forEdge:NSMaxYEdge];
284     [window setContentBorderThickness:55. forEdge:NSMaxYEdge];
285
286     WKNSWindowMakeBottomCornersSquare(window);
287
288     [self setWindow:window];
289     [window release];
290
291     return window;
292 }
293
294 // MARK: -
295
296 - (BOOL)windowShouldClose:(id)sender
297 {
298     [self destroyInspectorView:true];
299
300     return YES;
301 }
302
303 - (void)close
304 {
305     if (!_visible)
306         return;
307
308     _visible = NO;
309
310     if (_attachedToInspectedWebView) {
311         if ([_inspectedWebView.get() _isClosed])
312             return;
313
314         [_webView removeFromSuperview];
315
316         WebFrameView *frameView = [[_inspectedWebView.get() mainFrame] frameView];
317         NSRect frameViewRect = [frameView frame];
318
319         // Setting the height based on the previous height is done to work with
320         // Safari's find banner. This assumes the previous height is the Y origin.
321         frameViewRect.size.height += NSMinY(frameViewRect);
322         frameViewRect.origin.y = 0.0;
323
324         [frameView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
325         [frameView setFrame:frameViewRect];
326
327         [_inspectedWebView.get() displayIfNeeded];
328     } else
329         [super close];
330 }
331
332 - (IBAction)showWindow:(id)sender
333 {
334     if (_visible) {
335         if (!_attachedToInspectedWebView)
336             [super showWindow:sender]; // call super so the window will be ordered front if needed
337         return;
338     }
339
340     _visible = YES;
341     
342     _shouldAttach = _inspectorClient->inspectorStartsAttached();
343     
344     if (_shouldAttach && !_frontendClient->canAttachWindow())
345         _shouldAttach = NO;
346
347     if (_shouldAttach) {
348         WebFrameView *frameView = [[_inspectedWebView.get() mainFrame] frameView];
349
350         [_webView removeFromSuperview];
351         [_inspectedWebView.get() addSubview:_webView positioned:NSWindowBelow relativeTo:(NSView *)frameView];
352
353         [_webView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable | NSViewMaxYMargin)];
354         [frameView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable | NSViewMinYMargin)];
355
356         _attachedToInspectedWebView = YES;
357     } else {
358         _attachedToInspectedWebView = NO;
359
360         NSView *contentView = [[self window] contentView];
361         [_webView setFrame:[contentView frame]];
362         [_webView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
363         [_webView removeFromSuperview];
364         [contentView addSubview:_webView];
365
366         [super showWindow:nil];
367     }
368 }
369
370 // MARK: -
371
372 - (void)attach
373 {
374     if (_attachedToInspectedWebView)
375         return;
376
377     _inspectorClient->setInspectorStartsAttached(true);
378
379     [self close];
380     [self showWindow:nil];
381 }
382
383 - (void)detach
384 {
385     if (!_attachedToInspectedWebView)
386         return;
387
388     _inspectorClient->setInspectorStartsAttached(false);
389
390     [self close];
391     [self showWindow:nil];
392 }
393
394 - (BOOL)attached
395 {
396     return _attachedToInspectedWebView;
397 }
398
399 - (void)setFrontendClient:(WebInspectorFrontendClient*)frontendClient
400 {
401     _frontendClient = frontendClient;
402 }
403
404 - (void)setInspectorClient:(WebInspectorClient*)inspectorClient
405 {
406     _inspectorClient = inspectorClient;
407 }
408
409 - (WebInspectorClient*)inspectorClient
410 {
411     return _inspectorClient;
412 }
413
414 - (void)setAttachedWindowHeight:(unsigned)height
415 {
416     if (!_attachedToInspectedWebView)
417         return;
418
419     WebFrameView *frameView = [[_inspectedWebView.get() mainFrame] frameView];
420     NSRect frameViewRect = [frameView frame];
421
422     // Setting the height based on the difference is done to work with
423     // Safari's find banner. This assumes the previous height is the Y origin.
424     CGFloat heightDifference = (NSMinY(frameViewRect) - height);
425     frameViewRect.size.height += heightDifference;
426     frameViewRect.origin.y = height;
427
428     [_webView setFrame:NSMakeRect(0.0, 0.0, NSWidth(frameViewRect), height)];
429     [frameView setFrame:frameViewRect];
430 }
431
432 - (void)destroyInspectorView:(bool)notifyInspectorController
433 {
434     if (_destroyingInspectorView)
435         return;
436     _destroyingInspectorView = YES;
437
438     if (_attachedToInspectedWebView)
439         [self close];
440
441     _visible = NO;
442
443     if (notifyInspectorController) {
444         if (Page* inspectedPage = [_inspectedWebView.get() page])
445             inspectedPage->inspectorController()->disconnectFrontend();
446
447         _inspectorClient->releaseFrontendPage();
448     }
449
450     [_webView close];
451 }
452
453 // MARK: -
454 // MARK: UI delegate
455
456 - (NSUInteger)webView:(WebView *)sender dragDestinationActionMaskForDraggingInfo:(id <NSDraggingInfo>)draggingInfo
457 {
458     return WebDragDestinationActionNone;
459 }
460
461 // MARK: -
462 // These methods can be used by UI elements such as menu items and toolbar buttons when the inspector is the key window.
463
464 // This method is really only implemented to keep any UI elements enabled.
465 - (void)showWebInspector:(id)sender
466 {
467     [[_inspectedWebView.get() inspector] show:sender];
468 }
469
470 - (void)showErrorConsole:(id)sender
471 {
472     [[_inspectedWebView.get() inspector] showConsole:sender];
473 }
474
475 - (void)toggleDebuggingJavaScript:(id)sender
476 {
477     [[_inspectedWebView.get() inspector] toggleDebuggingJavaScript:sender];
478 }
479
480 - (void)toggleProfilingJavaScript:(id)sender
481 {
482     [[_inspectedWebView.get() inspector] toggleProfilingJavaScript:sender];
483 }
484
485 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
486 {
487     BOOL isMenuItem = [(id)item isKindOfClass:[NSMenuItem class]];
488     if ([item action] == @selector(toggleDebuggingJavaScript:) && isMenuItem) {
489         NSMenuItem *menuItem = (NSMenuItem *)item;
490         if ([[_inspectedWebView.get() inspector] isDebuggingJavaScript])
491             [menuItem setTitle:UI_STRING_INTERNAL("Stop Debugging JavaScript", "title for Stop Debugging JavaScript menu item")];
492         else
493             [menuItem setTitle:UI_STRING_INTERNAL("Start Debugging JavaScript", "title for Start Debugging JavaScript menu item")];
494     } else if ([item action] == @selector(toggleProfilingJavaScript:) && isMenuItem) {
495         NSMenuItem *menuItem = (NSMenuItem *)item;
496         if ([[_inspectedWebView.get() inspector] isProfilingJavaScript])
497             [menuItem setTitle:UI_STRING_INTERNAL("Stop Profiling JavaScript", "title for Stop Profiling JavaScript menu item")];
498         else
499             [menuItem setTitle:UI_STRING_INTERNAL("Start Profiling JavaScript", "title for Start Profiling JavaScript menu item")];
500     }
501
502     return YES;
503 }
504
505
506 @end