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 ContextMenuItemTagOpenMediaInNewWindow: openNewWindow(result.absoluteMediaURL(), frame); break; case ContextMenuItemTagCopyMediaLinkToClipboard: frame->editor()->copyURL(result.absoluteMediaURL(), result.textContent()); break; case ContextMenuItemTagToggleMediaControls: result.toggleMediaControlsDisplay(); break; case ContextMenuItemTagToggleMediaLoop: result.toggleMediaLoopPlayback(); break; case ContextMenuItemTagEnterVideoFullscreen: result.enterFullscreenForVideo(); break; case ContextMenuItemTagMediaPlayPause: result.toggleMediaPlayState(); break; case ContextMenuItemTagMediaMute: result.toggleMediaMuteState(); 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->editor()->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->selection()->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; } }
void ContextMenu::populate() { ContextMenuItem OpenLinkItem(ActionType, ContextMenuItemTagOpenLink, contextMenuItemTagOpenLink()); ContextMenuItem OpenLinkInNewWindowItem(ActionType, ContextMenuItemTagOpenLinkInNewWindow, contextMenuItemTagOpenLinkInNewWindow()); ContextMenuItem DownloadFileItem(ActionType, ContextMenuItemTagDownloadLinkToDisk, contextMenuItemTagDownloadLinkToDisk()); ContextMenuItem CopyLinkItem(ActionType, ContextMenuItemTagCopyLinkToClipboard, contextMenuItemTagCopyLinkToClipboard()); ContextMenuItem OpenImageInNewWindowItem(ActionType, ContextMenuItemTagOpenImageInNewWindow, contextMenuItemTagOpenImageInNewWindow()); ContextMenuItem DownloadImageItem(ActionType, ContextMenuItemTagDownloadImageToDisk, contextMenuItemTagDownloadImageToDisk()); ContextMenuItem CopyImageItem(ActionType, ContextMenuItemTagCopyImageToClipboard, contextMenuItemTagCopyImageToClipboard()); #if PLATFORM(MAC) ContextMenuItem SearchSpotlightItem(ActionType, ContextMenuItemTagSearchInSpotlight, contextMenuItemTagSearchInSpotlight()); ContextMenuItem LookInDictionaryItem(ActionType, ContextMenuItemTagLookUpInDictionary, contextMenuItemTagLookUpInDictionary()); #endif ContextMenuItem SearchWebItem(ActionType, ContextMenuItemTagSearchWeb, contextMenuItemTagSearchWeb()); ContextMenuItem CopyItem(ActionType, ContextMenuItemTagCopy, contextMenuItemTagCopy()); ContextMenuItem BackItem(ActionType, ContextMenuItemTagGoBack, contextMenuItemTagGoBack()); ContextMenuItem ForwardItem(ActionType, ContextMenuItemTagGoForward, contextMenuItemTagGoForward()); ContextMenuItem StopItem(ActionType, ContextMenuItemTagStop, contextMenuItemTagStop()); ContextMenuItem ReloadItem(ActionType, ContextMenuItemTagReload, contextMenuItemTagReload()); ContextMenuItem OpenFrameItem(ActionType, ContextMenuItemTagOpenFrameInNewWindow, contextMenuItemTagOpenFrameInNewWindow()); ContextMenuItem NoGuessesItem(ActionType, ContextMenuItemTagNoGuessesFound, contextMenuItemTagNoGuessesFound()); ContextMenuItem IgnoreSpellingItem(ActionType, ContextMenuItemTagIgnoreSpelling, contextMenuItemTagIgnoreSpelling()); ContextMenuItem LearnSpellingItem(ActionType, ContextMenuItemTagLearnSpelling, contextMenuItemTagLearnSpelling()); ContextMenuItem IgnoreGrammarItem(ActionType, ContextMenuItemTagIgnoreGrammar, contextMenuItemTagIgnoreGrammar()); ContextMenuItem CutItem(ActionType, ContextMenuItemTagCut, contextMenuItemTagCut()); ContextMenuItem PasteItem(ActionType, ContextMenuItemTagPaste, contextMenuItemTagPaste()); #if PLATFORM(GTK) ContextMenuItem DeleteItem(ActionType, ContextMenuItemTagDelete, contextMenuItemTagDelete()); ContextMenuItem SelectAllItem(ActionType, ContextMenuItemTagSelectAll, contextMenuItemTagSelectAll()); #endif HitTestResult result = hitTestResult(); Node* node = m_hitTestResult.innerNonSharedNode(); if (!node) return; #if PLATFORM(GTK) if (!result.isContentEditable() && (node->isElementNode() && static_cast<Element*>(node)->isFormControlElement())) return; #endif Frame* frame = node->document()->frame(); if (!frame) return; if (!result.isContentEditable()) { FrameLoader* loader = frame->loader(); KURL linkURL = result.absoluteLinkURL(); if (!linkURL.isEmpty()) { if (loader->canHandleRequest(ResourceRequest(linkURL))) { appendItem(OpenLinkItem); appendItem(OpenLinkInNewWindowItem); appendItem(DownloadFileItem); } appendItem(CopyLinkItem); } KURL imageURL = result.absoluteImageURL(); if (!imageURL.isEmpty()) { if (!linkURL.isEmpty()) appendItem(*separatorItem()); appendItem(OpenImageInNewWindowItem); appendItem(DownloadImageItem); if (imageURL.isLocalFile() || m_hitTestResult.image()) appendItem(CopyImageItem); } if (imageURL.isEmpty() && linkURL.isEmpty()) { if (result.isSelected()) { if (selectionContainsPossibleWord(frame)) { #if PLATFORM(MAC) appendItem(SearchSpotlightItem); #endif appendItem(SearchWebItem); appendItem(*separatorItem()); #if PLATFORM(MAC) appendItem(LookInDictionaryItem); appendItem(*separatorItem()); #endif } appendItem(CopyItem); } else { #if PLATFORM(GTK) appendItem(BackItem); appendItem(ForwardItem); appendItem(StopItem); appendItem(ReloadItem); #else if (loader->canGoBackOrForward(-1)) appendItem(BackItem); if (loader->canGoBackOrForward(1)) appendItem(ForwardItem); // use isLoadingInAPISense rather than isLoading because Stop/Reload are // intended to match WebKit's API, not WebCore's internal notion of loading status if (loader->documentLoader()->isLoadingInAPISense()) appendItem(StopItem); else appendItem(ReloadItem); #endif if (frame->page() && frame != frame->page()->mainFrame()) appendItem(OpenFrameItem); } } } else { // Make an editing context menu SelectionController* selection = frame->selection(); bool inPasswordField = selection->isInPasswordField(); if (!inPasswordField) { // Consider adding spelling-related or grammar-related context menu items (never both, since a single selected range // is never considered a misspelling and bad grammar at the same time) bool misspelling; bool badGrammar; Vector<String> guesses = frame->editor()->guessesForMisspelledOrUngrammaticalSelection(misspelling, badGrammar); if (misspelling || badGrammar) { size_t size = guesses.size(); if (size == 0) { // If there's bad grammar but no suggestions (e.g., repeated word), just leave off the suggestions // list and trailing separator rather than adding a "No Guesses Found" item (matches AppKit) if (misspelling) { appendItem(NoGuessesItem); appendItem(*separatorItem()); } } else { for (unsigned i = 0; i < size; i++) { const String &guess = guesses[i]; if (!guess.isEmpty()) { ContextMenuItem item(ActionType, ContextMenuItemTagSpellingGuess, guess); appendItem(item); } } appendItem(*separatorItem()); } if (misspelling) { appendItem(IgnoreSpellingItem); appendItem(LearnSpellingItem); } else appendItem(IgnoreGrammarItem); appendItem(*separatorItem()); #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) } else { // If the string was autocorrected, generate a contextual menu item allowing it to be changed back. String replacedString = result.replacedString(); if (!replacedString.isEmpty()) { ContextMenuItem item(ActionType, ContextMenuItemTagChangeBack, contextMenuItemTagChangeBack(replacedString)); appendItem(item); appendItem(*separatorItem()); } #endif } } FrameLoader* loader = frame->loader(); KURL linkURL = result.absoluteLinkURL(); if (!linkURL.isEmpty()) { if (loader->canHandleRequest(ResourceRequest(linkURL))) { appendItem(OpenLinkItem); appendItem(OpenLinkInNewWindowItem); appendItem(DownloadFileItem); } appendItem(CopyLinkItem); appendItem(*separatorItem()); } if (result.isSelected() && !inPasswordField && selectionContainsPossibleWord(frame)) { #if PLATFORM(MAC) appendItem(SearchSpotlightItem); #endif appendItem(SearchWebItem); appendItem(*separatorItem()); #if PLATFORM(MAC) appendItem(LookInDictionaryItem); appendItem(*separatorItem()); #endif } appendItem(CutItem); appendItem(CopyItem); appendItem(PasteItem); #if PLATFORM(GTK) appendItem(DeleteItem); appendItem(*separatorItem()); appendItem(SelectAllItem); #endif if (!inPasswordField) { appendItem(*separatorItem()); #ifndef BUILDING_ON_TIGER ContextMenuItem SpellingAndGrammarMenuItem(SubmenuType, ContextMenuItemTagSpellingMenu, contextMenuItemTagSpellingMenu()); createAndAppendSpellingAndGrammarSubMenu(m_hitTestResult, SpellingAndGrammarMenuItem); appendItem(SpellingAndGrammarMenuItem); #else ContextMenuItem SpellingMenuItem(SubmenuType, ContextMenuItemTagSpellingMenu, contextMenuItemTagSpellingMenu()); createAndAppendSpellingSubMenu(m_hitTestResult, SpellingMenuItem); appendItem(SpellingMenuItem); #endif #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) ContextMenuItem substitutionsMenuItem(SubmenuType, ContextMenuItemTagSubstitutionsMenu, contextMenuItemTagSubstitutionsMenu()); createAndAppendSubstitutionsSubMenu(m_hitTestResult, substitutionsMenuItem); appendItem(substitutionsMenuItem); ContextMenuItem transformationsMenuItem(SubmenuType, ContextMenuItemTagTransformationsMenu, contextMenuItemTagTransformationsMenu()); createAndAppendTransformationsSubMenu(m_hitTestResult, transformationsMenuItem); appendItem(transformationsMenuItem); #endif ContextMenuItem FontMenuItem(SubmenuType, ContextMenuItemTagFontMenu, contextMenuItemTagFontMenu()); createAndAppendFontSubMenu(m_hitTestResult, FontMenuItem); appendItem(FontMenuItem); #if PLATFORM(MAC) ContextMenuItem SpeechMenuItem(SubmenuType, ContextMenuItemTagSpeechMenu, contextMenuItemTagSpeechMenu()); createAndAppendSpeechSubMenu(m_hitTestResult, SpeechMenuItem); appendItem(SpeechMenuItem); #endif #if !PLATFORM(GTK) ContextMenuItem WritingDirectionMenuItem(SubmenuType, ContextMenuItemTagWritingDirectionMenu, contextMenuItemTagWritingDirectionMenu()); createAndAppendWritingDirectionSubMenu(m_hitTestResult, WritingDirectionMenuItem); appendItem(WritingDirectionMenuItem); if (Page* page = frame->page()) { if (Settings* settings = page->settings()) { bool includeTextDirectionSubmenu = settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAlwaysIncluded || (settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAutomaticallyIncluded && frame->editor()->hasBidiSelection()); if (includeTextDirectionSubmenu) { ContextMenuItem TextDirectionMenuItem(SubmenuType, ContextMenuItemTagTextDirectionMenu, contextMenuItemTagTextDirectionMenu()); createAndAppendTextDirectionSubMenu(m_hitTestResult, TextDirectionMenuItem); appendItem(TextDirectionMenuItem); } } } #endif } } }