Remove some dead code.
[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     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(Node* node)
101 {
102     [m_highlighter.get() highlightNode:kit(node)];
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::saveSessionSetting(const String& key, const String& value)
194 {
195     WebInspectorClient* client = [m_windowController.get() inspectorClient];
196     if (client)
197         client->saveSessionSetting(key, value);
198 }
199
200 void WebInspectorFrontendClient::loadSessionSetting(const String& key, String* value)
201 {
202     WebInspectorClient* client = [m_windowController.get() inspectorClient];
203     if (client)
204         client->loadSessionSetting(key, value);
205 }
206
207 void WebInspectorFrontendClient::updateWindowTitle() const
208 {
209     NSString *title = [NSString stringWithFormat:UI_STRING_INTERNAL("Web Inspector — %@", "Web Inspector window title"), (NSString *)m_inspectedURL];
210     [[m_windowController.get() window] setTitle:title];
211 }
212
213
214 // MARK: -
215
216 @implementation WebInspectorWindowController
217 - (id)init
218 {
219     if (!(self = [super initWithWindow:nil]))
220         return nil;
221
222     // Keep preferences separate from the rest of the client, making sure we are using expected preference values.
223
224     WebPreferences *preferences = [[WebPreferences alloc] init];
225     [preferences setAutosaves:NO];
226     [preferences setLoadsImagesAutomatically:YES];
227     [preferences setAuthorAndUserStylesEnabled:YES];
228     [preferences setJavaScriptEnabled:YES];
229     [preferences setAllowsAnimatedImages:YES];
230     [preferences setPlugInsEnabled:NO];
231     [preferences setJavaEnabled:NO];
232     [preferences setUserStyleSheetEnabled:NO];
233     [preferences setTabsToLinks:NO];
234     [preferences setMinimumFontSize:0];
235     [preferences setMinimumLogicalFontSize:9];
236 #ifndef BUILDING_ON_LEOPARD
237     [preferences setFixedFontFamily:@"Menlo"];
238     [preferences setDefaultFixedFontSize:11];
239 #else
240     [preferences setFixedFontFamily:@"Monaco"];
241     [preferences setDefaultFixedFontSize:10];
242 #endif
243
244     _webView = [[WebView alloc] init];
245     [_webView setPreferences:preferences];
246     [_webView setDrawsBackground:NO];
247     [_webView setProhibitsMainFrameScrolling:YES];
248     [_webView setUIDelegate:self];
249
250     [preferences release];
251
252     NSString *path = [[NSBundle bundleWithIdentifier:@"com.apple.WebCore"] pathForResource:@"inspector" ofType:@"html" inDirectory:@"inspector"];
253     NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL fileURLWithPath:path]];
254     [[_webView mainFrame] loadRequest:request];
255     [request release];
256
257     [self setWindowFrameAutosaveName:@"Web Inspector 2"];
258     return self;
259 }
260
261 - (id)initWithInspectedWebView:(WebView *)webView
262 {
263     if (!(self = [self init]))
264         return nil;
265
266     // Don't retain to avoid a circular reference.
267     _inspectedWebView = webView;
268     return self;
269 }
270
271 - (void)dealloc
272 {
273     [_webView release];
274     [super dealloc];
275 }
276
277 // MARK: -
278
279 - (WebView *)webView
280 {
281     return _webView;
282 }
283
284 - (NSWindow *)window
285 {
286     NSWindow *window = [super window];
287     if (window)
288         return window;
289
290     NSUInteger styleMask = (NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask);
291
292     styleMask |= NSTexturedBackgroundWindowMask;
293
294     window = [[NSWindow alloc] initWithContentRect:NSMakeRect(60.0, 200.0, 750.0, 650.0) styleMask:styleMask backing:NSBackingStoreBuffered defer:NO];
295     [window setDelegate:self];
296     [window setMinSize:NSMakeSize(400.0, 400.0)];
297
298     [window setAutorecalculatesContentBorderThickness:NO forEdge:NSMaxYEdge];
299     [window setContentBorderThickness:55. forEdge:NSMaxYEdge];
300
301     WKNSWindowMakeBottomCornersSquare(window);
302
303     [self setWindow:window];
304     [window release];
305
306     return window;
307 }
308
309 // MARK: -
310
311 - (BOOL)windowShouldClose:(id)sender
312 {
313     [self destroyInspectorView:true];
314
315     return YES;
316 }
317
318 - (void)close
319 {
320     if (!_visible)
321         return;
322
323     _visible = NO;
324
325     if (_attachedToInspectedWebView) {
326         if ([_inspectedWebView _isClosed])
327             return;
328
329         [_webView removeFromSuperview];
330
331         WebFrameView *frameView = [[_inspectedWebView mainFrame] frameView];
332         NSRect frameViewRect = [frameView frame];
333
334         // Setting the height based on the previous height is done to work with
335         // Safari's find banner. This assumes the previous height is the Y origin.
336         frameViewRect.size.height += NSMinY(frameViewRect);
337         frameViewRect.origin.y = 0.0;
338
339         [frameView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
340         [frameView setFrame:frameViewRect];
341
342         [_inspectedWebView displayIfNeeded];
343     } else
344         [super close];
345 }
346
347 - (IBAction)showWindow:(id)sender
348 {
349     if (_visible) {
350         if (!_attachedToInspectedWebView)
351             [super showWindow:sender]; // call super so the window will be ordered front if needed
352         return;
353     }
354
355     _visible = YES;
356     
357     _shouldAttach = _inspectorClient->inspectorStartsAttached();
358     
359     if (_shouldAttach && !_frontendClient->canAttachWindow())
360         _shouldAttach = NO;
361
362     if (_shouldAttach) {
363         WebFrameView *frameView = [[_inspectedWebView mainFrame] frameView];
364
365         [_webView removeFromSuperview];
366         [_inspectedWebView addSubview:_webView positioned:NSWindowBelow relativeTo:(NSView *)frameView];
367
368         [_webView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable | NSViewMaxYMargin)];
369         [frameView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable | NSViewMinYMargin)];
370
371         _attachedToInspectedWebView = YES;
372     } else {
373         _attachedToInspectedWebView = NO;
374
375         NSView *contentView = [[self window] contentView];
376         [_webView setFrame:[contentView frame]];
377         [_webView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
378         [_webView removeFromSuperview];
379         [contentView addSubview:_webView];
380
381         [super showWindow:nil];
382     }
383 }
384
385 // MARK: -
386
387 - (void)attach
388 {
389     if (_attachedToInspectedWebView)
390         return;
391
392     _inspectorClient->setInspectorStartsAttached(true);
393
394     [self close];
395     [self showWindow:nil];
396 }
397
398 - (void)detach
399 {
400     if (!_attachedToInspectedWebView)
401         return;
402
403     _inspectorClient->setInspectorStartsAttached(false);
404
405     [self close];
406     [self showWindow:nil];
407 }
408
409 - (BOOL)attached
410 {
411     return _attachedToInspectedWebView;
412 }
413
414 - (void)setFrontendClient:(WebInspectorFrontendClient*)frontendClient
415 {
416     _frontendClient = frontendClient;
417 }
418
419 - (void)setInspectorClient:(WebInspectorClient*)inspectorClient
420 {
421     _inspectorClient = inspectorClient;
422 }
423
424 - (WebInspectorClient*)inspectorClient
425 {
426     return _inspectorClient;
427 }
428
429 - (void)setAttachedWindowHeight:(unsigned)height
430 {
431     if (!_attachedToInspectedWebView)
432         return;
433
434     WebFrameView *frameView = [[_inspectedWebView mainFrame] frameView];
435     NSRect frameViewRect = [frameView frame];
436
437     // Setting the height based on the difference is done to work with
438     // Safari's find banner. This assumes the previous height is the Y origin.
439     CGFloat heightDifference = (NSMinY(frameViewRect) - height);
440     frameViewRect.size.height += heightDifference;
441     frameViewRect.origin.y = height;
442
443     [_webView setFrame:NSMakeRect(0.0, 0.0, NSWidth(frameViewRect), height)];
444     [frameView setFrame:frameViewRect];
445 }
446
447 - (void)destroyInspectorView:(bool)notifyInspectorController
448 {
449     if (_destroyingInspectorView)
450         return;
451     _destroyingInspectorView = YES;
452
453     if (_attachedToInspectedWebView)
454         [self close];
455
456     _visible = NO;
457
458     if (notifyInspectorController) {
459         if (Page* inspectedPage = [_inspectedWebView page])
460             inspectedPage->inspectorController()->disconnectFrontend();
461
462         _inspectorClient->releaseFrontendPage();
463     }
464
465     [_webView close];
466 }
467
468 // MARK: -
469 // MARK: UI delegate
470
471 - (NSUInteger)webView:(WebView *)sender dragDestinationActionMaskForDraggingInfo:(id <NSDraggingInfo>)draggingInfo
472 {
473     return WebDragDestinationActionNone;
474 }
475
476 // MARK: -
477
478 // These methods can be used by UI elements such as menu items and toolbar buttons when the inspector is the key window.
479
480 // This method is really only implemented to keep any UI elements enabled.
481 - (void)showWebInspector:(id)sender
482 {
483     [[_inspectedWebView inspector] show:sender];
484 }
485
486 - (void)showErrorConsole:(id)sender
487 {
488     [[_inspectedWebView inspector] showConsole:sender];
489 }
490
491 - (void)toggleDebuggingJavaScript:(id)sender
492 {
493     [[_inspectedWebView inspector] toggleDebuggingJavaScript:sender];
494 }
495
496 - (void)toggleProfilingJavaScript:(id)sender
497 {
498     [[_inspectedWebView inspector] toggleProfilingJavaScript:sender];
499 }
500
501 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
502 {
503     BOOL isMenuItem = [(id)item isKindOfClass:[NSMenuItem class]];
504     if ([item action] == @selector(toggleDebuggingJavaScript:) && isMenuItem) {
505         NSMenuItem *menuItem = (NSMenuItem *)item;
506         if ([[_inspectedWebView inspector] isDebuggingJavaScript])
507             [menuItem setTitle:UI_STRING_INTERNAL("Stop Debugging JavaScript", "title for Stop Debugging JavaScript menu item")];
508         else
509             [menuItem setTitle:UI_STRING_INTERNAL("Start Debugging JavaScript", "title for Start Debugging JavaScript menu item")];
510     } else if ([item action] == @selector(toggleProfilingJavaScript:) && isMenuItem) {
511         NSMenuItem *menuItem = (NSMenuItem *)item;
512         if ([[_inspectedWebView inspector] isProfilingJavaScript])
513             [menuItem setTitle:UI_STRING_INTERNAL("Stop Profiling JavaScript", "title for Stop Profiling JavaScript menu item")];
514         else
515             [menuItem setTitle:UI_STRING_INTERNAL("Start Profiling JavaScript", "title for Start Profiling JavaScript menu item")];
516     }
517
518     return YES;
519 }
520
521 @end