diff options
Diffstat (limited to 'src/plugins/help/macwebkithelpviewer.mm')
-rw-r--r-- | src/plugins/help/macwebkithelpviewer.mm | 812 |
1 files changed, 812 insertions, 0 deletions
diff --git a/src/plugins/help/macwebkithelpviewer.mm b/src/plugins/help/macwebkithelpviewer.mm new file mode 100644 index 0000000000..64fd77b6eb --- /dev/null +++ b/src/plugins/help/macwebkithelpviewer.mm @@ -0,0 +1,812 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +****************************************************************************/ + +#include "macwebkithelpviewer.h" + +#include "localhelpmanager.h" +#include "openpagesmanager.h" + +#include <coreplugin/icore.h> +#include <utils/qtcassert.h> + +#include <QApplication> +#include <QClipboard> +#include <QHelpEngine> +#include <QtMac> +#include <QUrl> +#include <QVBoxLayout> + +#include <QDebug> + +#import <AppKit/NSMenuItem.h> +#import <Foundation/NSURLProtocol.h> +#import <Foundation/NSURLResponse.h> +#import <WebKit/DOMDocument.h> +#import <WebKit/DOMElement.h> +#import <WebKit/DOMHTMLElement.h> +#import <WebKit/DOMNodeFilter.h> +#import <WebKit/DOMNodeIterator.h> +#import <WebKit/DOMRange.h> +#import <WebKit/WebBackForwardList.h> +#import <WebKit/WebDataSource.h> +#import <WebKit/WebDocument.h> +#import <WebKit/WebFrame.h> +#import <WebKit/WebFrameLoadDelegate.h> +#import <WebKit/WebFrameView.h> +#import <WebKit/WebHistoryItem.h> +#import <WebKit/WebPreferences.h> +#import <WebKit/WebUIDelegate.h> +#import <WebKit/WebView.h> + +// #pragma mark -- AutoreleasePool + +class AutoreleasePool +{ +public: + AutoreleasePool(); + ~AutoreleasePool(); +private: + NSAutoreleasePool *pool; +}; + +AutoreleasePool::AutoreleasePool() +{ + pool = [[NSAutoreleasePool alloc] init]; +} + +AutoreleasePool::~AutoreleasePool() +{ + [pool release]; +} + +// #pragma mark -- DOMNodeIterator (PrivateExtensions) + +@interface DOMNodeIterator (PrivateExtensions) + +- (BOOL)findNode:(DOMNode *)node; +- (DOMNode *)nextTextNode; +- (DOMNode *)previousTextNode; +- (DOMNode *)gotoEnd; + +@end + +@implementation DOMNodeIterator (PrivateExtensions) + +- (BOOL)findNode:(DOMNode *)node +{ + while (DOMNode *next = [self nextNode]) { + if (next == node) + return YES; + } + return NO; +} + +- (DOMNode *)nextTextNode +{ + DOMNode *node = nil; + do { + node = [self nextNode]; + } while (node && node.nodeType != DOM_TEXT_NODE); + return node; +} + +- (DOMNode *)previousTextNode +{ + DOMNode *node = nil; + do { + node = [self previousNode]; + } while (node && node.nodeType != DOM_TEXT_NODE); + return node; +} + +- (DOMNode *)gotoEnd +{ + DOMNode *previous = nil; + DOMNode *node = nil; + do { + previous = node; + node = [self nextNode]; + } while (node); + return previous; +} + +@end + +// #pragma mark -- QtHelpURLProtocol + +@interface QtHelpURLProtocol : NSURLProtocol +{ +} + ++ (BOOL)canInitWithRequest:(NSURLRequest *)request; + +@end + +@implementation QtHelpURLProtocol + ++ (BOOL)canInitWithRequest:(NSURLRequest *)request +{ + return [[[request URL] scheme] isEqualToString:@"qthelp"]; +} + ++ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request +{ + return request; +} + +- (void)startLoading +{ + const QUrl &url = QUrl::fromNSURL(self.request.URL); + QByteArray data; + Help::Internal::LocalHelpManager *helpManager = Help::Internal::LocalHelpManager::instance(); + + QMetaObject::invokeMethod(helpManager, "helpData", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(QByteArray, data), Q_ARG(QUrl, url)); + + QString mtString = Help::Internal::HelpViewer::mimeFromUrl(url); + if (mtString.isEmpty()) + mtString = QLatin1String("application/octet-stream"); + NSString *mimeType = mtString.toNSString(); + + NSData *nsdata = QtMac::toNSData(data); // Qt 5.3 has this in QByteArray + + NSURLResponse *response = [[NSURLResponse alloc] initWithURL:self.request.URL + MIMEType:mimeType + expectedContentLength:data.length() + textEncodingName:@"UTF8"]; + [self.client URLProtocol:self didReceiveResponse:response + cacheStoragePolicy:NSURLCacheStorageNotAllowed]; + [self.client URLProtocol:self didLoadData:nsdata]; + [self.client URLProtocolDidFinishLoading:self]; + [response release]; +} + +- (void)stopLoading +{ +} + +@end + +static void ensureProtocolHandler() +{ + static bool registered = false; + if (!registered) { + [NSURLProtocol registerClass:[QtHelpURLProtocol class]]; + registered = true; + } +} + +// #pragma mark -- FrameLoadDelegate + +@interface FrameLoadDelegate : NSObject +{ + WebFrame *mainFrame; + Help::Internal::MacWebKitHelpViewer *viewer; +} + +- (id)initWithMainFrame:(WebFrame *)frame viewer:(Help::Internal::MacWebKitHelpViewer *)viewer; +- (void)webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame; +- (void)webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame; +- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame; + +@end + +@implementation FrameLoadDelegate + +- (id)initWithMainFrame:(WebFrame *)frame viewer:(Help::Internal::MacWebKitHelpViewer *)helpViewer +{ + self = [super init]; + if (self) { + mainFrame = frame; + viewer = helpViewer; + } + return self; +} + +- (void)webView:(WebView *)sender didStartProvisionalLoadForFrame:(WebFrame *)frame +{ + Q_UNUSED(sender) + if (frame == mainFrame) + viewer->slotLoadStarted(); +} + +- (void)webView:(WebView *)sender didReceiveTitle:(NSString *)title forFrame:(WebFrame *)frame +{ + Q_UNUSED(sender) + Q_UNUSED(title) + if (frame == mainFrame) + viewer->titleChanged(); +} + +- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame +{ + Q_UNUSED(sender) + if (frame == mainFrame) + viewer->slotLoadFinished(); +} + +@end + +// #pragma mark -- UIDelegate + +@interface UIDelegate : NSObject +{ + QWidget *widget; +} + +@property (assign) BOOL openInNewWindowActionVisible; + +- (id)initWithWidget:(QWidget *)theWidget; +- (void)webView:(WebView *)sender makeFirstResponder:(NSResponder *)responder; +- (NSArray *)webView:(WebView *)sender contextMenuItemsForElement:(NSDictionary *)element + defaultMenuItems:(NSArray *)defaultMenuItems; +- (WebView *)webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request; + +@end + +@implementation UIDelegate + +- (id)initWithWidget:(QWidget *)theWidget +{ + self = [super init]; + if (self) { + widget = theWidget; + self.openInNewWindowActionVisible = YES; + } + return self; +} + +- (void)webView:(WebView *)sender makeFirstResponder:(NSResponder *)responder +{ + // make the widget get focus + if (responder) { + widget->setFocus(); + [sender.window makeFirstResponder:responder]; + } +} + +- (NSArray *)webView:(WebView *)sender contextMenuItemsForElement:(NSDictionary *)element + defaultMenuItems:(NSArray *)defaultMenuItems +{ + Q_UNUSED(sender) + Q_UNUSED(element) + NSMutableArray *ret = [[NSMutableArray alloc] init]; + for (NSMenuItem *item in defaultMenuItems) { + switch (item.tag) { + case WebMenuItemTagCopyLinkToClipboard: + case WebMenuItemTagCopyImageToClipboard: + case WebMenuItemTagCopy: + case WebMenuItemTagGoBack: + case WebMenuItemTagGoForward: + case WebMenuItemTagStop: + case WebMenuItemTagReload: + case WebMenuItemTagOther: + case WebMenuItemTagSearchInSpotlight: + case WebMenuItemTagSearchWeb: + case WebMenuItemTagLookUpInDictionary: + case WebMenuItemTagOpenWithDefaultApplication: + [ret addObject:item]; + break; + case WebMenuItemTagOpenLinkInNewWindow: + case WebMenuItemTagOpenImageInNewWindow: + if (self.openInNewWindowActionVisible) + [ret addObject:item]; + default: + break; + } + } + return [ret autorelease]; +} + +- (WebView *)webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request +{ + Q_UNUSED(sender) + Q_UNUSED(request) + Help::Internal::MacWebKitHelpViewer* viewer + = static_cast<Help::Internal::MacWebKitHelpViewer *>( + Help::Internal::OpenPagesManager::instance().createPage(QUrl())); + return viewer->widget()->webView(); +} + +@end + +// #pragma mark -- MyWebView +@interface MyWebView : WebView +@end + +// work around Qt + WebView issue QTBUG-26593, that Qt does not pass mouseMoved: events up the event chain, +// but the Web(HTML)View is only handling mouse moved for hovering etc if the event was passed up +// to the NSWindow (arguably a bug in Web(HTML)View) +@implementation MyWebView + +- (void)updateTrackingAreas +{ + [super updateTrackingAreas]; + if (NSArray *trackingArray = [self trackingAreas]) { + NSUInteger size = [trackingArray count]; + for (NSUInteger i = 0; i < size; ++i) { + NSTrackingArea *t = [trackingArray objectAtIndex:i]; + [self removeTrackingArea:t]; + } + } + NSUInteger trackingOptions = NSTrackingActiveInActiveApp | NSTrackingInVisibleRect + | NSTrackingMouseMoved; + NSTrackingArea *ta = [[[NSTrackingArea alloc] initWithRect:[self frame] + options:trackingOptions + owner:self + userInfo:nil] + autorelease]; + [self addTrackingArea:ta]; +} + +- (void)mouseMoved:(NSEvent *)theEvent +{ + [self.window mouseMoved:theEvent]; +} + +@end + +namespace Help { +namespace Internal { + +// #pragma mark -- MacWebKitHelpWidget + +class MacWebKitHelpWidgetPrivate +{ +public: + MacWebKitHelpWidgetPrivate() + : m_savedResponder(nil) + { + } + + ~MacWebKitHelpWidgetPrivate() + { + [m_webView release]; + [m_frameLoadDelegate release]; + [m_uiDelegate release]; + } + + WebView *m_webView; + FrameLoadDelegate *m_frameLoadDelegate; + UIDelegate *m_uiDelegate; + NSResponder *m_savedResponder; +}; + +// #pragma mark -- MacWebKitHelpWidget + +MacWebKitHelpWidget::MacWebKitHelpWidget(MacWebKitHelpViewer *parent) + : QMacCocoaViewContainer(0, parent), + d(new MacWebKitHelpWidgetPrivate) +{ + AutoreleasePool pool; Q_UNUSED(pool) + d->m_webView = [[MyWebView alloc] init]; + d->m_frameLoadDelegate = [[FrameLoadDelegate alloc] initWithMainFrame:d->m_webView.mainFrame + viewer:parent]; + [d->m_webView setFrameLoadDelegate:d->m_frameLoadDelegate]; + d->m_uiDelegate = [[UIDelegate alloc] initWithWidget:this]; + [d->m_webView setUIDelegate:d->m_uiDelegate]; + + setCocoaView(d->m_webView); +} + +MacWebKitHelpWidget::~MacWebKitHelpWidget() +{ + delete d; +} + +void MacWebKitHelpWidget::setOpenInNewWindowActionVisible(bool visible) +{ + d->m_uiDelegate.openInNewWindowActionVisible = visible; +} + +WebView *MacWebKitHelpWidget::webView() const +{ + return d->m_webView; +} + +void MacWebKitHelpWidget::hideEvent(QHideEvent *) +{ + [d->m_webView setHidden:YES]; +} + +void MacWebKitHelpWidget::showEvent(QShowEvent *) +{ + [d->m_webView setHidden:NO]; +} + +// #pragma mark -- MacWebKitHelpViewer + +MacWebKitHelpViewer::MacWebKitHelpViewer(qreal zoom, QWidget *parent) + : HelpViewer(parent), + m_widget(new MacWebKitHelpWidget(this)) +{ + static bool responderHackInstalled = false; + if (!responderHackInstalled) { + responderHackInstalled = true; + new MacResponderHack(qApp); + } + + AutoreleasePool pool; Q_UNUSED(pool) + QVBoxLayout *layout = new QVBoxLayout; + setLayout(layout); + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(m_widget, 10); + m_widget->webView().textSizeMultiplier = (zoom == 0.0 ? 1.0 : zoom); +} + +MacWebKitHelpViewer::~MacWebKitHelpViewer() +{ + +} + +QFont MacWebKitHelpViewer::viewerFont() const +{ + AutoreleasePool pool; Q_UNUSED(pool) + WebPreferences *preferences = m_widget->webView().preferences; + QString family = QString::fromNSString([preferences standardFontFamily]); + int size = [preferences defaultFontSize]; + return QFont(family, size); +} + +void MacWebKitHelpViewer::setViewerFont(const QFont &font) +{ + AutoreleasePool pool; Q_UNUSED(pool) + WebPreferences *preferences = m_widget->webView().preferences; + [preferences setStandardFontFamily:font.family().toNSString()]; + [preferences setDefaultFontSize:font.pointSize()]; +} + +void MacWebKitHelpViewer::scaleUp() +{ + AutoreleasePool pool; Q_UNUSED(pool) + m_widget->webView().textSizeMultiplier += 0.1; +} + +void MacWebKitHelpViewer::scaleDown() +{ + AutoreleasePool pool; Q_UNUSED(pool) + m_widget->webView().textSizeMultiplier = qMax(0.1, m_widget->webView().textSizeMultiplier - 0.1); +} + +void MacWebKitHelpViewer::resetScale() +{ + AutoreleasePool pool; Q_UNUSED(pool) + m_widget->webView().textSizeMultiplier = 1.0; +} + +qreal MacWebKitHelpViewer::scale() const +{ + AutoreleasePool pool; Q_UNUSED(pool) + return m_widget->webView().textSizeMultiplier; +} + +QString MacWebKitHelpViewer::title() const +{ + AutoreleasePool pool; Q_UNUSED(pool) + return QString::fromNSString(m_widget->webView().mainFrameTitle); +} + +QUrl MacWebKitHelpViewer::source() const +{ + AutoreleasePool pool; Q_UNUSED(pool) + WebDataSource *dataSource = m_widget->webView().mainFrame.dataSource; + if (!dataSource) + dataSource = m_widget->webView().mainFrame.provisionalDataSource; + return QUrl::fromNSURL(dataSource.request.URL); +} + +void MacWebKitHelpViewer::setSource(const QUrl &url) +{ + AutoreleasePool pool; Q_UNUSED(pool) + ensureProtocolHandler(); + [m_widget->webView().mainFrame loadRequest:[NSURLRequest requestWithURL:url.toNSURL()]]; +} + +void MacWebKitHelpViewer::scrollToAnchor(const QString &anchor) +{ + QUrl url = source(); + url.setFragment(anchor); + setSource(url); +} + +void MacWebKitHelpViewer::setHtml(const QString &html) +{ + AutoreleasePool pool; Q_UNUSED(pool) + [m_widget->webView().mainFrame + loadHTMLString:html.toNSString() + baseURL:[NSURL fileURLWithPath:Core::ICore::resourcePath().toNSString()]]; +} + +QString MacWebKitHelpViewer::selectedText() const +{ + AutoreleasePool pool; Q_UNUSED(pool) + return QString::fromNSString(m_widget->webView().selectedDOMRange.text); +} + +bool MacWebKitHelpViewer::isForwardAvailable() const +{ + AutoreleasePool pool; Q_UNUSED(pool) + return m_widget->webView().canGoForward; +} + +bool MacWebKitHelpViewer::isBackwardAvailable() const +{ + AutoreleasePool pool; Q_UNUSED(pool) + return m_widget->webView().canGoBack; +} + +void MacWebKitHelpViewer::addBackHistoryItems(QMenu *backMenu) +{ + AutoreleasePool pool; Q_UNUSED(pool) + WebBackForwardList *list = m_widget->webView().backForwardList; + int backListCount = list.backListCount; + for (int i = 0; i < backListCount; ++i) { + int historyIndex = -(i+1); + QAction *action = new QAction(backMenu); + action->setText(QString::fromNSString([list itemAtIndex:historyIndex].title)); + action->setData(historyIndex); + connect(action, SIGNAL(triggered()), this, SLOT(goToHistoryItem())); + backMenu->addAction(action); + } +} + +void MacWebKitHelpViewer::addForwardHistoryItems(QMenu *forwardMenu) +{ + AutoreleasePool pool; Q_UNUSED(pool) + WebBackForwardList *list = m_widget->webView().backForwardList; + int forwardListCount = list.forwardListCount; + for (int i = 0; i < forwardListCount; ++i) { + int historyIndex = i + 1; + QAction *action = new QAction(forwardMenu); + action->setText(QString::fromNSString([list itemAtIndex:historyIndex].title)); + action->setData(historyIndex); + connect(action, SIGNAL(triggered()), this, SLOT(goToHistoryItem())); + forwardMenu->addAction(action); + } +} + +void MacWebKitHelpViewer::setOpenInNewWindowActionVisible(bool visible) +{ + m_widget->setOpenInNewWindowActionVisible(visible); +} + +DOMRange *MacWebKitHelpViewer::findText(NSString *text, bool forward, bool caseSensitive, DOMNode *startNode, int startOffset) +{ + QTC_ASSERT(text, return nil); + if (text.length == 0) + return nil; + DOMDocument *document = m_widget->webView().mainFrame.DOMDocument; + // search only the body + DOMNodeIterator *iterator = [document createNodeIterator:document.body whatToShow:DOM_SHOW_ALL + filter:nil expandEntityReferences:NO]; + + DOMNode *selectionStart = nil; + int selectionStartOffset = 0; + DOMNode *currentNode = startNode; + int currentOffset = startOffset; + NSString *searchTerm = caseSensitive ? text : [text lowercaseString]; + int searchTermLength = searchTerm.length; + int indexInSearchTerm = forward ? 0 : searchTerm.length - 1; + if (!currentNode) { // search whole body from end + if (forward) + currentNode = document.body; + else + currentNode = [iterator gotoEnd]; + } else { // otherwise find the start node + QTC_ASSERT([iterator findNode:currentNode], return nil); + } + if (!forward) { // findNode leaves iterator behind currentNode, we need to go back + QTC_ASSERT([iterator previousNode] == currentNode, return nil); + } + if (currentNode.nodeType != DOM_TEXT_NODE) { // we only want text nodes + currentNode = forward ? [iterator nextTextNode] : [iterator previousTextNode]; + currentOffset = -1; // search whole node + } + while (currentNode) { + NSString *currentText = caseSensitive ? currentNode.nodeValue : [currentNode.nodeValue lowercaseString]; + int currentTextLength = currentText.length; + if (currentOffset < 0) // search whole node + currentOffset = forward ? 0 : currentTextLength - 1; + while (currentOffset < currentTextLength/*forward*/ && currentOffset >= 0/*backward*/) { + if ([currentText characterAtIndex:currentOffset] == [searchTerm characterAtIndex:indexInSearchTerm]) { + indexInSearchTerm += forward ? 1 : -1; + if (!selectionStart) { + selectionStart = currentNode; + selectionStartOffset = currentOffset; + } + } else { + indexInSearchTerm = forward ? 0 : searchTerm.length - 1; + selectionStart = nil; + } + currentOffset += forward ? 1 : -1; + if (indexInSearchTerm >= searchTermLength/*forward*/ || indexInSearchTerm < 0/*backward*/) { + // we have found a match! + DOMRange *range = [document createRange]; + if (forward) { + [range setStart:selectionStart offset:selectionStartOffset]; + [range setEnd:currentNode offset:currentOffset]; + } else { + [range setStart:currentNode offset:(currentOffset + 1)]; // was already decreased + [range setEnd:selectionStart offset:(selectionStartOffset + 1)]; + } + return range; + } + } + currentNode = forward ? [iterator nextTextNode] : [iterator previousTextNode]; + currentOffset = -1; // search whole node + } + return nil; +} + +bool MacWebKitHelpViewer::findText(const QString &text, Core::FindFlags flags, bool incremental, + bool fromSearch, bool *wrapped) +{ + Q_UNUSED(incremental); + Q_UNUSED(fromSearch); + AutoreleasePool pool; Q_UNUSED(pool) + if (wrapped) + *wrapped = false; + bool forward = !(flags & Core::FindBackward); + bool caseSensitive = (flags & Core::FindCaseSensitively); + WebView *webView = m_widget->webView(); + + // WebView searchFor:.... grabs first responder, and when losing first responder afterwards, + // it removes the selection and forgets the search state, making it pretty useless for us + + // define the start node and offset for the search + DOMNode *start = nil; // default is search whole body + int startOffset = -1; + DOMRange *selection = webView.selectedDOMRange; + if (selection) { + if (QString::fromNSString(selection.text).compare( + text, caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive) != 0) { + // for incremental search we want to search from the beginning of the selection + start = selection.startContainer; + startOffset = selection.startOffset; + } else { + // search for next occurrence + if (forward) { + start = selection.endContainer; + startOffset = selection.endOffset; + } else { + start = selection.startContainer; + startOffset = selection.startOffset; + } + } + } + DOMRange *newSelection = findText(text.toNSString(), forward, caseSensitive, + start, startOffset); + if (!newSelection && start != nil) { // wrap + start = nil; + startOffset = -1; + newSelection = findText(text.toNSString(), forward, caseSensitive, + start, startOffset); + if (newSelection && wrapped) + *wrapped = true; + } + if (newSelection) { + // found, select and scroll there + [webView setSelectedDOMRange:newSelection affinity:NSSelectionAffinityDownstream]; + if (forward) + [newSelection.endContainer.parentElement scrollIntoViewIfNeeded:YES]; + else + [newSelection.startContainer.parentElement scrollIntoViewIfNeeded:YES]; + return true; + } + return false; +} + +void MacWebKitHelpViewer::copy() +{ + QApplication::clipboard()->setText(selectedText()); +} + +void MacWebKitHelpViewer::stop() +{ + [m_widget->webView() stopLoading:nil]; +} + +void MacWebKitHelpViewer::forward() +{ + AutoreleasePool pool; Q_UNUSED(pool) + [m_widget->webView() goForward]; + emit forwardAvailable(isForwardAvailable()); + emit backwardAvailable(isBackwardAvailable()); +} + +void MacWebKitHelpViewer::backward() +{ + AutoreleasePool pool; Q_UNUSED(pool) + [m_widget->webView() goBack]; + emit forwardAvailable(isForwardAvailable()); + emit backwardAvailable(isBackwardAvailable()); +} + +void MacWebKitHelpViewer::print(QPrinter *printer) +{ + Q_UNUSED(printer) +} + +void MacWebKitHelpViewer::slotLoadStarted() +{ + HelpViewer::slotLoadStarted(); +} + +void MacWebKitHelpViewer::slotLoadFinished() +{ + HelpViewer::slotLoadFinished(); + emit forwardAvailable(isForwardAvailable()); + emit backwardAvailable(isBackwardAvailable()); +} + +void MacWebKitHelpViewer::goToHistoryItem() +{ + AutoreleasePool pool; Q_UNUSED(pool) + QAction *action = qobject_cast<QAction *>(sender()); + QTC_ASSERT(action, return); + bool ok = false; + int index = action->data().toInt(&ok); + QTC_ASSERT(ok, return); + WebBackForwardList *list = m_widget->webView().backForwardList; + WebHistoryItem *item = [list itemAtIndex:index]; + QTC_ASSERT(item, return); + [m_widget->webView() goToBackForwardItem:item]; + emit forwardAvailable(isForwardAvailable()); + emit backwardAvailable(isBackwardAvailable()); +} + +// #pragma mark -- MacResponderHack + +MacResponderHack::MacResponderHack(QObject *parent) + : QObject(parent) +{ + connect(qApp, SIGNAL(focusChanged(QWidget*,QWidget*)), + this, SLOT(responderHack(QWidget*,QWidget*))); +} + +void MacResponderHack::responderHack(QWidget *old, QWidget *now) +{ + // On focus change, Qt does not make the corresponding QNSView firstResponder. + // That breaks when embedding native NSView into a Qt hierarchy. When the focus is changed + // by clicking with the mouse into a widget, everything is fine, because Cocoa automatically + // adapts firstResponder in that case, but it breaks when setting the Qt focus from code. + Q_UNUSED(old) + if (!now) + return; + AutoreleasePool pool; Q_UNUSED(pool) + NSView *view; + if (QMacCocoaViewContainer *viewContainer = qobject_cast<QMacCocoaViewContainer *>(now)) + view = viewContainer->cocoaView(); + else + view = (NSView *)now->effectiveWinId(); + [view.window makeFirstResponder:view]; +} + +} // Internal +} // Help |