Remove unneeded header imports from some Web Inspector files.
[WebKit-https.git] / WebKit / mac / WebCoreSupport / WebInspectorClient.mm
1 /*
2  * Copyright (C) 2006, 2007 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 "WebFrameInternal.h"
32 #import "WebInspector.h"
33 #import "WebLocalizableStrings.h"
34 #import "WebNodeHighlight.h"
35 #import "WebUIDelegate.h"
36 #import "WebViewInternal.h"
37
38 #import <WebCore/InspectorController.h>
39 #import <WebCore/Page.h>
40
41 #import <WebKit/DOMExtensions.h>
42
43 using namespace WebCore;
44
45 @interface WebInspectorWindowController : NSWindowController <NSWindowDelegate> {
46 @private
47     WebView *_inspectedWebView;
48     WebView *_webView;
49     WebNodeHighlight *_currentHighlight;
50     BOOL _attachedToInspectedWebView;
51     BOOL _shouldAttach;
52     BOOL _visible;
53     BOOL _movingWindows;
54 }
55 - (id)initWithInspectedWebView:(WebView *)webView;
56 - (BOOL)inspectorVisible;
57 - (WebView *)webView;
58 - (void)attach;
59 - (void)detach;
60 - (void)highlightAndScrollToNode:(DOMNode *)node;
61 - (void)highlightNode:(DOMNode *)node;
62 - (void)hideHighlight;
63 @end
64
65 #pragma mark -
66
67 WebInspectorClient::WebInspectorClient(WebView *webView)
68 : m_webView(webView)
69 {
70 }
71
72 void WebInspectorClient::inspectorDestroyed()
73 {
74     [[m_windowController.get() webView] close];
75     delete this;
76 }
77
78 Page* WebInspectorClient::createPage()
79 {
80     if (!m_windowController)
81         m_windowController.adoptNS([[WebInspectorWindowController alloc] initWithInspectedWebView:m_webView]);
82
83     return core([m_windowController.get() webView]);
84 }
85
86 String WebInspectorClient::localizedStringsURL()
87 {
88     NSString *path = [[NSBundle bundleWithIdentifier:@"com.apple.WebCore"] pathForResource:@"localizedStrings" ofType:@"js"];
89     if (path)
90         return [[NSURL fileURLWithPath:path] absoluteString];
91     return String();
92 }
93
94 void WebInspectorClient::showWindow()
95 {
96     updateWindowTitle();
97     [m_windowController.get() showWindow:nil];
98 }
99
100 void WebInspectorClient::closeWindow()
101 {
102     [m_windowController.get() close];
103 }
104
105 void WebInspectorClient::attachWindow()
106 {
107     [m_windowController.get() attach];
108 }
109
110 void WebInspectorClient::detachWindow()
111 {
112     [m_windowController.get() detach];
113 }
114
115 void WebInspectorClient::highlight(Node* node)
116 {
117     [m_windowController.get() highlightAndScrollToNode:kit(node)];
118 }
119
120 void WebInspectorClient::hideHighlight()
121 {
122     [m_windowController.get() hideHighlight];
123 }
124
125 void WebInspectorClient::inspectedURLChanged(const String& newURL)
126 {
127     m_inspectedURL = newURL;
128     updateWindowTitle();
129 }
130
131 void WebInspectorClient::updateWindowTitle() const
132 {
133     NSString *title = [NSString stringWithFormat:UI_STRING("Web Inspector — %@", "Web Inspector window title"), (NSString *)m_inspectedURL];
134     [[m_windowController.get() window] setTitle:title];
135 }
136
137 #pragma mark -
138
139 #define WebKitInspectorAttachedViewHeightKey @"WebKitInspectorAttachedViewHeight"
140
141 @implementation WebInspectorWindowController
142 - (id)init
143 {
144     if (![super initWithWindow:nil])
145         return nil;
146
147     // Keep preferences separate from the rest of the client, making sure we are using expected preference values.
148     // One reason this is good is that it keeps the inspector out of history via "private browsing".
149
150     WebPreferences *preferences = [[WebPreferences alloc] init];
151     [preferences setAutosaves:NO];
152     [preferences setPrivateBrowsingEnabled:YES];
153     [preferences setLoadsImagesAutomatically:YES];
154     [preferences setAuthorAndUserStylesEnabled:YES];
155     [preferences setJavaScriptEnabled:YES];
156     [preferences setAllowsAnimatedImages:YES];
157     [preferences setPlugInsEnabled:NO];
158     [preferences setJavaEnabled:NO];
159     [preferences setUserStyleSheetEnabled:NO];
160     [preferences setTabsToLinks:NO];
161     [preferences setMinimumFontSize:0];
162     [preferences setMinimumLogicalFontSize:9];
163
164     _webView = [[WebView alloc] init];
165     [_webView setPreferences:preferences];
166     [_webView setDrawsBackground:NO];
167     [_webView setProhibitsMainFrameScrolling:YES];
168     [_webView setUIDelegate:self];
169
170     [preferences release];
171
172     NSString *path = [[NSBundle bundleWithIdentifier:@"com.apple.WebCore"] pathForResource:@"inspector" ofType:@"html" inDirectory:@"inspector"];
173     NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL fileURLWithPath:path]];
174     [[_webView mainFrame] loadRequest:request];
175     [request release];
176
177     [self setWindowFrameAutosaveName:@"Web Inspector 2"];
178     return self;
179 }
180
181 - (id)initWithInspectedWebView:(WebView *)webView
182 {
183     if (![self init])
184         return nil;
185
186     // Don't retain to avoid a circular reference
187     _inspectedWebView = webView;
188     return self;
189 }
190
191 - (void)dealloc
192 {
193     ASSERT(!_currentHighlight);
194     [_webView release];
195     [super dealloc];
196 }
197
198 #pragma mark -
199
200 - (BOOL)inspectorVisible
201 {
202     return _visible;
203 }
204
205 - (WebView *)webView
206 {
207     return _webView;
208 }
209
210 - (NSWindow *)window
211 {
212     NSWindow *window = [super window];
213     if (window)
214         return window;
215
216     NSUInteger styleMask = (NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask);
217
218 #ifndef BUILDING_ON_TIGER
219     styleMask |= NSTexturedBackgroundWindowMask;
220 #endif
221
222     window = [[NSWindow alloc] initWithContentRect:NSMakeRect(60.0, 200.0, 750.0, 650.0) styleMask:styleMask backing:NSBackingStoreBuffered defer:NO];
223     [window setDelegate:self];
224     [window setMinSize:NSMakeSize(400.0, 400.0)];
225
226 #ifndef BUILDING_ON_TIGER
227     [window setAutorecalculatesContentBorderThickness:NO forEdge:NSMaxYEdge];
228     [window setContentBorderThickness:55. forEdge:NSMaxYEdge];
229 #endif
230
231     [self setWindow:window];
232     [window release];
233
234     return window;
235 }
236
237 #pragma mark -
238
239 - (BOOL)windowShouldClose:(id)sender
240 {
241     _visible = NO;
242
243     [_inspectedWebView page]->inspectorController()->setWindowVisible(false);
244
245     [self hideHighlight];
246
247     return YES;
248 }
249
250 - (void)close
251 {
252     if (!_visible)
253         return;
254
255     _visible = NO;
256
257     if (!_movingWindows)
258         [_inspectedWebView page]->inspectorController()->setWindowVisible(false);
259
260     [self hideHighlight];
261
262     if (_attachedToInspectedWebView) {
263         if ([_inspectedWebView _isClosed])
264             return;
265
266         WebFrameView *frameView = [[_inspectedWebView mainFrame] frameView];
267
268         NSRect frameViewRect = [frameView frame];
269         frameViewRect = NSMakeRect(0, 0, NSWidth(frameViewRect), NSHeight([_inspectedWebView frame]));
270
271         [frameView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
272         [frameView setFrame:frameViewRect];
273
274         [_inspectedWebView displayIfNeeded];
275     } else
276         [super close];
277 }
278
279 - (IBAction)showWindow:(id)sender
280 {
281     if (_visible) {
282         if (!_attachedToInspectedWebView)
283             [super showWindow:sender]; // call super so the window will be ordered front if needed
284         return;
285     }
286
287     _visible = YES;
288
289     if (_shouldAttach) {
290         WebFrameView *frameView = [[_inspectedWebView mainFrame] frameView];
291
292         NSRect frameViewRect = [frameView frame];
293         float attachedHeight = [[NSUserDefaults standardUserDefaults] integerForKey:WebKitInspectorAttachedViewHeightKey];
294         attachedHeight = MAX(300.0, MIN(attachedHeight, (NSHeight(frameViewRect) * 0.6)));
295         frameViewRect = NSMakeRect(0, attachedHeight, NSWidth(frameViewRect), NSHeight(frameViewRect) - attachedHeight);
296
297         [_webView removeFromSuperview];
298         [_inspectedWebView addSubview:_webView positioned:NSWindowBelow relativeTo:(NSView*)frameView];
299
300         [_webView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable | NSViewMaxYMargin)];
301         [_webView setFrame:NSMakeRect(0, 0, NSWidth(frameViewRect), attachedHeight)];
302
303         [frameView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable | NSViewMinYMargin)];
304         [frameView setFrame:frameViewRect];
305
306         _attachedToInspectedWebView = YES;
307     } else {
308         _attachedToInspectedWebView = NO;
309
310         NSView *contentView = [[self window] contentView];
311         [_webView setFrame:[contentView frame]];
312         [_webView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
313         [_webView removeFromSuperview];
314         [contentView addSubview:_webView];
315
316         [super showWindow:nil];
317     }
318
319     [_inspectedWebView page]->inspectorController()->setWindowVisible(true);
320 }
321
322 #pragma mark -
323
324 - (void)attach
325 {
326     if (_attachedToInspectedWebView)
327         return;
328
329     _shouldAttach = YES;
330     _movingWindows = YES;
331
332     [self close];
333     [self showWindow:nil];
334
335     _movingWindows = NO;
336 }
337
338 - (void)detach
339 {
340     if (!_attachedToInspectedWebView)
341         return;
342
343     _shouldAttach = NO;
344     _movingWindows = YES;
345
346     [self close];
347     [self showWindow:nil];
348
349     _movingWindows = NO;
350 }
351
352 #pragma mark -
353
354 - (void)highlightAndScrollToNode:(DOMNode *)node
355 {
356     NSRect bounds = [node boundingBox];
357     if (!NSIsEmptyRect(bounds)) {
358         // FIXME: this needs to use the frame the node coordinates are in
359         NSRect visible = [[[[_inspectedWebView mainFrame] frameView] documentView] visibleRect];
360         BOOL needsScroll = !NSContainsRect(visible, bounds) && !NSContainsRect(bounds, visible);
361
362         // only scroll if the bounds isn't in the visible rect and dosen't contain the visible rect
363         if (needsScroll) {
364             // scroll to the parent element if we aren't focused on an element
365             DOMElement *element;
366             if ([node isKindOfClass:[DOMElement class]])
367                 element = (DOMElement *)node;
368             else
369                 element = (DOMElement *)[node parentNode];
370             [element scrollIntoViewIfNeeded:YES];
371
372             // give time for the scroll to happen
373             [self performSelector:@selector(highlightNode:) withObject:node afterDelay:0.25];
374         } else
375             [self highlightNode:node];
376     }
377 }
378
379 - (void)highlightNode:(DOMNode *)node
380 {
381     // The scrollview's content view stays around between page navigations, so target it
382     NSView *view = [[[[[_inspectedWebView mainFrame] frameView] documentView] enclosingScrollView] contentView];
383     if (![view window])
384         return; // skip the highlight if we have no window (e.g. hidden tab)
385
386     if (!_currentHighlight) {
387         _currentHighlight = [[WebNodeHighlight alloc] initWithTargetView:view inspectorController:[_inspectedWebView page]->inspectorController()];
388         [_currentHighlight setDelegate:self];
389         [_currentHighlight attach];
390     }
391
392     // FIXME: this is a hack until we hook up a didDraw and didScroll call in WebHTMLView
393     [[_currentHighlight highlightView] setNeedsDisplay:YES];
394 }
395
396 - (void)hideHighlight
397 {
398     [_currentHighlight detach];
399     [_currentHighlight setDelegate:nil];
400     [_currentHighlight release];
401     _currentHighlight = nil;
402 }
403
404 #pragma mark -
405 #pragma mark UI delegate
406
407 - (NSUInteger)webView:(WebView *)sender dragDestinationActionMaskForDraggingInfo:(id <NSDraggingInfo>)draggingInfo
408 {
409     return WebDragDestinationActionNone;
410 }
411
412 #pragma mark -
413
414 // These methods can be used by UI elements such as menu items and toolbar buttons when the inspector is the key window.
415
416 // This method is really only implemented to keep any UI elements enabled.
417 - (void)showWebInspector:(id)sender
418 {
419     [[_inspectedWebView inspector] show:sender];
420 }
421
422 - (void)showErrorConsole:(id)sender
423 {
424     [[_inspectedWebView inspector] showConsole:sender];
425 }
426
427 - (void)toggleDebuggingJavaScript:(id)sender
428 {
429     [[_inspectedWebView inspector] toggleDebuggingJavaScript:sender];
430 }
431
432 - (void)toggleProfilingJavaScript:(id)sender
433 {
434     [[_inspectedWebView inspector] toggleProfilingJavaScript:sender];
435 }
436
437 - (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
438 {
439     BOOL isMenuItem = [(id)item isKindOfClass:[NSMenuItem class]];
440     if ([item action] == @selector(toggleDebuggingJavaScript:) && isMenuItem) {
441         NSMenuItem *menuItem = (NSMenuItem *)item;
442         if ([[_inspectedWebView inspector] isDebuggingJavaScript])
443             [menuItem setTitle:UI_STRING("Stop Debugging JavaScript", "title for Stop Debugging JavaScript menu item")];
444         else
445             [menuItem setTitle:UI_STRING("Start Debugging JavaScript", "title for Start Debugging JavaScript menu item")];
446     } else if ([item action] == @selector(toggleProfilingJavaScript:) && isMenuItem) {
447         NSMenuItem *menuItem = (NSMenuItem *)item;
448         if ([[_inspectedWebView inspector] isProfilingJavaScript])
449             [menuItem setTitle:UI_STRING("Stop Profiling JavaScript", "title for Stop Profiling JavaScript menu item")];
450         else
451             [menuItem setTitle:UI_STRING("Start Profiling JavaScript", "title for Start Profiling JavaScript menu item")];
452     }
453
454     return YES;
455 }
456
457 @end