--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WebCore/page/ContextMenuController.cpp Fri Sep 17 09:02:29 2010 +0300
@@ -0,0 +1,379 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ContextMenuController.h"
+
+#if ENABLE(CONTEXT_MENUS)
+
+#include "Chrome.h"
+#include "ContextMenu.h"
+#include "ContextMenuClient.h"
+#include "ContextMenuProvider.h"
+#include "Document.h"
+#include "DocumentFragment.h"
+#include "DocumentLoader.h"
+#include "Editor.h"
+#include "EditorClient.h"
+#include "Event.h"
+#include "EventHandler.h"
+#include "EventNames.h"
+#include "FormState.h"
+#include "Frame.h"
+#include "FrameLoadRequest.h"
+#include "FrameLoader.h"
+#include "HTMLFormElement.h"
+#include "HitTestRequest.h"
+#include "HitTestResult.h"
+#include "InspectorController.h"
+#include "MouseEvent.h"
+#include "Node.h"
+#include "Page.h"
+#include "RenderLayer.h"
+#include "RenderObject.h"
+#include "ReplaceSelectionCommand.h"
+#include "ResourceRequest.h"
+#include "SelectionController.h"
+#include "Settings.h"
+#include "TextIterator.h"
+#include "WindowFeatures.h"
+#include "markup.h"
+
+namespace WebCore {
+
+ContextMenuController::ContextMenuController(Page* page, ContextMenuClient* client)
+ : m_page(page)
+ , m_client(client)
+ , m_contextMenu(0)
+{
+ ASSERT_ARG(page, page);
+ ASSERT_ARG(client, client);
+}
+
+ContextMenuController::~ContextMenuController()
+{
+ m_client->contextMenuDestroyed();
+}
+
+void ContextMenuController::clearContextMenu()
+{
+ m_contextMenu.set(0);
+ if (m_menuProvider)
+ m_menuProvider->contextMenuCleared();
+ m_menuProvider = 0;
+}
+
+void ContextMenuController::handleContextMenuEvent(Event* event)
+{
+ m_contextMenu.set(createContextMenu(event));
+ if (!m_contextMenu)
+ return;
+ m_contextMenu->populate();
+ showContextMenu(event);
+}
+
+void ContextMenuController::showContextMenu(Event* event, PassRefPtr<ContextMenuProvider> menuProvider)
+{
+ m_menuProvider = menuProvider;
+
+ m_contextMenu.set(createContextMenu(event));
+ if (!m_contextMenu) {
+ clearContextMenu();
+ return;
+ }
+
+ m_menuProvider->populateContextMenu(m_contextMenu.get());
+ showContextMenu(event);
+}
+
+ContextMenu* ContextMenuController::createContextMenu(Event* event)
+{
+ if (!event->isMouseEvent())
+ return 0;
+ MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
+ HitTestResult result(mouseEvent->absoluteLocation());
+
+ if (Frame* frame = event->target()->toNode()->document()->frame())
+ result = frame->eventHandler()->hitTestResultAtPoint(mouseEvent->absoluteLocation(), false);
+
+ if (!result.innerNonSharedNode())
+ return 0;
+ return new ContextMenu(result);
+}
+
+void ContextMenuController::showContextMenu(Event* event)
+{
+#if ENABLE(INSPECTOR)
+ if (m_page->inspectorController()->enabled())
+ m_contextMenu->addInspectElementItem();
+#endif
+ PlatformMenuDescription customMenu = m_client->getCustomMenuFromDefaultItems(m_contextMenu.get());
+ m_contextMenu->setPlatformDescription(customMenu);
+ event->setDefaultHandled();
+}
+
+static void openNewWindow(const KURL& urlToLoad, Frame* frame)
+{
+ if (Page* oldPage = frame->page()) {
+ WindowFeatures features;
+ if (Page* newPage = oldPage->chrome()->createWindow(frame, FrameLoadRequest(ResourceRequest(urlToLoad, frame->loader()->outgoingReferrer())), features))
+ newPage->chrome()->show();
+ }
+}
+
+void ContextMenuController::contextMenuItemSelected(ContextMenuItem* item)
+{
+ ASSERT(item->type() == ActionType || item->type() == CheckableActionType);
+
+ if (item->action() >= ContextMenuItemBaseApplicationTag) {
+ m_client->contextMenuItemSelected(item, m_contextMenu.get());
+ return;
+ }
+
+ if (item->action() >= ContextMenuItemBaseCustomTag) {
+ ASSERT(m_menuProvider);
+ m_menuProvider->contextMenuItemSelected(item);
+ return;
+ }
+
+ HitTestResult result = m_contextMenu->hitTestResult();
+ Frame* frame = result.innerNonSharedNode()->document()->frame();
+ if (!frame)
+ return;
+
+ switch (item->action()) {
+ case ContextMenuItemTagOpenLinkInNewWindow:
+ openNewWindow(result.absoluteLinkURL(), frame);
+ break;
+ case ContextMenuItemTagDownloadLinkToDisk:
+ // FIXME: Some day we should be able to do this from within WebCore.
+ m_client->downloadURL(result.absoluteLinkURL());
+ break;
+ case ContextMenuItemTagCopyLinkToClipboard:
+ frame->editor()->copyURL(result.absoluteLinkURL(), result.textContent());
+ break;
+ case ContextMenuItemTagOpenImageInNewWindow:
+ openNewWindow(result.absoluteImageURL(), frame);
+ break;
+ case ContextMenuItemTagDownloadImageToDisk:
+ // FIXME: Some day we should be able to do this from within WebCore.
+ m_client->downloadURL(result.absoluteImageURL());
+ break;
+ case ContextMenuItemTagCopyImageToClipboard:
+ // FIXME: The Pasteboard class is not written yet
+ // For now, call into the client. This is temporary!
+ frame->editor()->copyImage(result);
+ break;
+ case ContextMenuItemTagOpenFrameInNewWindow: {
+ DocumentLoader* loader = frame->loader()->documentLoader();
+ if (!loader->unreachableURL().isEmpty())
+ openNewWindow(loader->unreachableURL(), frame);
+ else
+ openNewWindow(loader->url(), frame);
+ break;
+ }
+ case ContextMenuItemTagCopy:
+ frame->editor()->copy();
+ break;
+ case ContextMenuItemTagGoBack:
+ if (Page* page = frame->page())
+ page->goBackOrForward(-1);
+ break;
+ case ContextMenuItemTagGoForward:
+ if (Page* page = frame->page())
+ page->goBackOrForward(1);
+ break;
+ case ContextMenuItemTagStop:
+ frame->loader()->stop();
+ break;
+ case ContextMenuItemTagReload:
+ frame->loader()->reload();
+ break;
+ case ContextMenuItemTagCut:
+ frame->editor()->cut();
+ break;
+ case ContextMenuItemTagPaste:
+ frame->editor()->paste();
+ break;
+#if PLATFORM(GTK)
+ case ContextMenuItemTagDelete:
+ frame->editor()->performDelete();
+ break;
+ case ContextMenuItemTagSelectAll:
+ frame->editor()->command("SelectAll").execute();
+ break;
+#endif
+ case ContextMenuItemTagSpellingGuess:
+ ASSERT(frame->selectedText().length());
+ if (frame->editor()->shouldInsertText(item->title(), frame->selection()->toNormalizedRange().get(), EditorInsertActionPasted)) {
+ Document* document = frame->document();
+ RefPtr<ReplaceSelectionCommand> command = ReplaceSelectionCommand::create(document, createFragmentFromMarkup(document, item->title(), ""), true, false, true);
+ applyCommand(command);
+ frame->revealSelection(ScrollAlignment::alignToEdgeIfNeeded);
+ }
+ break;
+ case ContextMenuItemTagIgnoreSpelling:
+ frame->editor()->ignoreSpelling();
+ break;
+ case ContextMenuItemTagLearnSpelling:
+ frame->editor()->learnSpelling();
+ break;
+ case ContextMenuItemTagSearchWeb:
+ m_client->searchWithGoogle(frame);
+ break;
+ case ContextMenuItemTagLookUpInDictionary:
+ // FIXME: Some day we may be able to do this from within WebCore.
+ m_client->lookUpInDictionary(frame);
+ break;
+ case ContextMenuItemTagOpenLink:
+ if (Frame* targetFrame = result.targetFrame())
+ targetFrame->loader()->loadFrameRequest(FrameLoadRequest(ResourceRequest(result.absoluteLinkURL(), frame->loader()->outgoingReferrer())), false, false, 0, 0, SendReferrer);
+ else
+ openNewWindow(result.absoluteLinkURL(), frame);
+ break;
+ case ContextMenuItemTagBold:
+ frame->editor()->command("ToggleBold").execute();
+ break;
+ case ContextMenuItemTagItalic:
+ frame->editor()->command("ToggleItalic").execute();
+ break;
+ case ContextMenuItemTagUnderline:
+ frame->editor()->toggleUnderline();
+ break;
+ case ContextMenuItemTagOutline:
+ // We actually never enable this because CSS does not have a way to specify an outline font,
+ // which may make this difficult to implement. Maybe a special case of text-shadow?
+ break;
+ case ContextMenuItemTagStartSpeaking: {
+ ExceptionCode ec;
+ RefPtr<Range> selectedRange = frame->selection()->toNormalizedRange();
+ if (!selectedRange || selectedRange->collapsed(ec)) {
+ Document* document = result.innerNonSharedNode()->document();
+ selectedRange = document->createRange();
+ selectedRange->selectNode(document->documentElement(), ec);
+ }
+ m_client->speak(plainText(selectedRange.get()));
+ break;
+ }
+ case ContextMenuItemTagStopSpeaking:
+ m_client->stopSpeaking();
+ break;
+ case ContextMenuItemTagDefaultDirection:
+ frame->editor()->setBaseWritingDirection(NaturalWritingDirection);
+ break;
+ case ContextMenuItemTagLeftToRight:
+ frame->editor()->setBaseWritingDirection(LeftToRightWritingDirection);
+ break;
+ case ContextMenuItemTagRightToLeft:
+ frame->editor()->setBaseWritingDirection(RightToLeftWritingDirection);
+ break;
+ case ContextMenuItemTagTextDirectionDefault:
+ frame->editor()->command("MakeTextWritingDirectionNatural").execute();
+ break;
+ case ContextMenuItemTagTextDirectionLeftToRight:
+ frame->editor()->command("MakeTextWritingDirectionLeftToRight").execute();
+ break;
+ case ContextMenuItemTagTextDirectionRightToLeft:
+ frame->editor()->command("MakeTextWritingDirectionRightToLeft").execute();
+ break;
+#if PLATFORM(MAC)
+ case ContextMenuItemTagSearchInSpotlight:
+ m_client->searchWithSpotlight();
+ break;
+#endif
+ case ContextMenuItemTagShowSpellingPanel:
+ frame->editor()->showSpellingGuessPanel();
+ break;
+ case ContextMenuItemTagCheckSpelling:
+ frame->editor()->advanceToNextMisspelling();
+ break;
+ case ContextMenuItemTagCheckSpellingWhileTyping:
+ frame->editor()->toggleContinuousSpellChecking();
+ break;
+#ifndef BUILDING_ON_TIGER
+ case ContextMenuItemTagCheckGrammarWithSpelling:
+ frame->editor()->toggleGrammarChecking();
+ break;
+#endif
+#if PLATFORM(MAC)
+ case ContextMenuItemTagShowFonts:
+ frame->editor()->showFontPanel();
+ break;
+ case ContextMenuItemTagStyles:
+ frame->editor()->showStylesPanel();
+ break;
+ case ContextMenuItemTagShowColors:
+ frame->editor()->showColorPanel();
+ break;
+#endif
+#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ case ContextMenuItemTagMakeUpperCase:
+ frame->editor()->uppercaseWord();
+ break;
+ case ContextMenuItemTagMakeLowerCase:
+ frame->editor()->lowercaseWord();
+ break;
+ case ContextMenuItemTagCapitalize:
+ frame->editor()->capitalizeWord();
+ break;
+ case ContextMenuItemTagShowSubstitutions:
+ frame->editor()->showSubstitutionsPanel();
+ break;
+ case ContextMenuItemTagSmartCopyPaste:
+ frame->editor()->toggleSmartInsertDelete();
+ break;
+ case ContextMenuItemTagSmartQuotes:
+ frame->editor()->toggleAutomaticQuoteSubstitution();
+ break;
+ case ContextMenuItemTagSmartDashes:
+ frame->editor()->toggleAutomaticDashSubstitution();
+ break;
+ case ContextMenuItemTagSmartLinks:
+ frame->editor()->toggleAutomaticLinkDetection();
+ break;
+ case ContextMenuItemTagTextReplacement:
+ frame->editor()->toggleAutomaticTextReplacement();
+ break;
+ case ContextMenuItemTagCorrectSpellingAutomatically:
+ frame->editor()->toggleAutomaticSpellingCorrection();
+ break;
+ case ContextMenuItemTagChangeBack:
+ frame->editor()->changeBackToReplacedString(result.replacedString());
+ break;
+#endif
+#if ENABLE(INSPECTOR)
+ case ContextMenuItemTagInspectElement:
+ if (Page* page = frame->page())
+ page->inspectorController()->inspect(result.innerNonSharedNode());
+ break;
+#endif
+ default:
+ break;
+ }
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(CONTEXT_MENUS)