Reviewed by Harrison.
authordarin <darin@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 20 Mar 2005 21:18:26 +0000 (21:18 +0000)
committerdarin <darin@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sun, 20 Mar 2005 21:18:26 +0000 (21:18 +0000)
        - fixed <rdar://problem/4059914> when you select all of a frame's content, need to select the frame in the parent document so it can be easily deleted

        * khtml/khtml_part.h: Added selectFrameElementInParentIfFullySelected.
        * khtml/khtml_part.cpp:
        (isFrame): Added.
        (KHTMLPart::setFocusNodeIfNeeded): Changed to not set focus to a frame; was not what this function was
        intended to do, and caused trouble when trying to select a frame element.
        (KHTMLPart::khtmlMouseReleaseEvent): Call selectFrameElementInParentIfFullySelected.
        (KHTMLPart::selectAll): Call selectFrameElementInParentIfFullySelected.
        (KHTMLPart::selectFrameElementInParentIfFullySelected): Added. Selects the frame element in the parent
        if a frame is entirely selected, which makes it easier to delete or replace the frame and is consistent
        with the changes Maciej made recently for other elements.

        * kwq/WebCoreBridge.mm:
        (-[WebCoreBridge alterCurrentSelection:direction:granularity:]): Call selectFrameElementInParentIfFullySelected.
        (-[WebCoreBridge alterCurrentSelection:verticalDistance:]): Call selectFrameElementInParentIfFullySelected.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@8942 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebCore/ChangeLog-2005-08-23
WebCore/khtml/khtml_part.cpp
WebCore/khtml/khtml_part.h
WebCore/kwq/WebCoreBridge.mm

index d1a7de125784007375bb8d59c54c3144e62b3516..60a606d84c161c41949b0a2b7bdbd3f9f33d4949 100644 (file)
@@ -1,3 +1,24 @@
+2005-03-20  Darin Adler  <darin@apple.com>
+
+        Reviewed by Harrison.
+
+        - fixed <rdar://problem/4059914> when you select all of a frame's content, need to select the frame in the parent document so it can be easily deleted
+
+        * khtml/khtml_part.h: Added selectFrameElementInParentIfFullySelected.
+        * khtml/khtml_part.cpp:
+        (isFrame): Added.
+        (KHTMLPart::setFocusNodeIfNeeded): Changed to not set focus to a frame; was not what this function was
+        intended to do, and caused trouble when trying to select a frame element.
+        (KHTMLPart::khtmlMouseReleaseEvent): Call selectFrameElementInParentIfFullySelected.
+        (KHTMLPart::selectAll): Call selectFrameElementInParentIfFullySelected.
+        (KHTMLPart::selectFrameElementInParentIfFullySelected): Added. Selects the frame element in the parent
+        if a frame is entirely selected, which makes it easier to delete or replace the frame and is consistent
+        with the changes Maciej made recently for other elements.
+
+        * kwq/WebCoreBridge.mm:
+        (-[WebCoreBridge alterCurrentSelection:direction:granularity:]): Call selectFrameElementInParentIfFullySelected.
+        (-[WebCoreBridge alterCurrentSelection:verticalDistance:]): Call selectFrameElementInParentIfFullySelected.
+
 2005-03-20  Darin Adler  <darin@apple.com>
 
         Reviewed by me, code change by Ken.
index ef812fd4242e0dcd7a991c1d82fb43514a3c8542..52046f307c9abb1dc38046357f0333471ac85525 100644 (file)
@@ -47,6 +47,7 @@
 #include "editing/selection.h"
 #include "editing/visible_position.h"
 #include "editing/visible_text.h"
+#include "editing/visible_units.h"
 #include "html/html_documentimpl.h"
 #include "html/html_baseimpl.h"
 #include "html/html_miscimpl.h"
@@ -116,10 +117,13 @@ using khtml::EditCommandPtr;
 using khtml::ETextGranularity;
 using khtml::FormData;
 using khtml::InlineTextBox;
+using khtml::isEndOfDocument;
+using khtml::isStartOfDocument;
 using khtml::PARAGRAPH;
 using khtml::plainText;
 using khtml::RenderObject;
 using khtml::RenderText;
+using khtml::RenderWidget;
 using khtml::Selection;
 using khtml::Tokenizer;
 using khtml::TypingCommand;
@@ -2501,6 +2505,19 @@ void KHTMLPart::clearCaretRectIfNeeded()
     }        
 }
 
+// Helper function that tells whether a particular node is an element that has an entire
+// KHTMLPart and KHTMLView, a <frame>, <iframe>, or <object>.
+static bool isFrame(const NodeImpl *n)
+{
+    if (!n)
+        return false;
+    RenderObject *renderer = n->renderer();
+    if (!renderer || !renderer->isWidget())
+        return false;
+    QWidget *widget = static_cast<RenderWidget *>(renderer)->widget();
+    return widget && widget->inherits("KHTMLView");
+}
+
 void KHTMLPart::setFocusNodeIfNeeded()
 {
     if (!xmlDocImpl() || d->m_selection.isNone() || !d->m_isFocused)
@@ -2521,7 +2538,10 @@ void KHTMLPart::setFocusNodeIfNeeded()
     
     if (target) {
         for ( ; target; target = target->parentNode()) {
-            if (target->isMouseFocusable()) {
+            // We don't want to set focus on a subframe when selecting in a parent frame,
+            // so add the !isFrame check here. There's probably a better way to make this
+            // work in the long term, but this is the safest fix at this time.
+            if (target->isMouseFocusable() && !isFrame(target)) {
                 xmlDocImpl()->setFocusNode(target);
                 return;
             }
@@ -4907,6 +4927,8 @@ void KHTMLPart::khtmlMouseReleaseEvent( khtml::MouseReleaseEvent *event )
     cb->setSelectionMode(false);
 #endif // QT_NO_CLIPBOARD
 
+    selectFrameElementInParentIfFullySelected();
+
 #endif // KHTML_NO_SELECTION
 }
 
@@ -5057,6 +5079,7 @@ void KHTMLPart::selectAll()
     NodeImpl *de = d->m_doc->documentElement();
     int n = de ? de->childNodeCount() : 0;
     setSelection(Selection(VisiblePosition(de, 0, khtml::DOWNSTREAM), VisiblePosition(de, n, khtml::DOWNSTREAM)));
+    selectFrameElementInParentIfFullySelected();
 }
 
 bool KHTMLPart::shouldBeginEditing(const Range &range) const
@@ -5822,5 +5845,49 @@ void KHTMLPart::slotEndLifeSupport()
     deref();
 }
 
+// Workaround for the fact that it's hard to delete a frame.
+// Call this after doing user-triggered selections to make it easy to delete the frame you entirely selected.
+// Can't do this implicitly as part of every setSelection call because in some contexts it might not be good
+// for the focus to move to another frame. So instead we call it from places where we are selecting with the
+// mouse or the keyboard after setting the selection.
+void KHTMLPart::selectFrameElementInParentIfFullySelected()
+{
+    // Find the parent frame; if there is none, then we have nothing to do.
+    KHTMLPart *parent = parentPart();
+    if (!parent)
+        return;
+    KHTMLView *parentView = parent->view();
+    if (!parentView)
+        return;
+
+    // Check if the selection contains the entire frame contents; if not, then there is nothing to do.
+    if (!d->m_selection.isRange())
+        return;
+    if (!isStartOfDocument(VisiblePosition(d->m_selection.start(), d->m_selection.startAffinity())))
+        return;
+    if (!isEndOfDocument(VisiblePosition(d->m_selection.end(), d->m_selection.endAffinity())))
+        return;
+
+    // Get to the <iframe> or <frame> (or even <object>) element in the parent frame.
+    DocumentImpl *document = xmlDocImpl();
+    if (!document)
+        return;
+    ElementImpl *ownerElement = document->ownerElement();
+    if (!ownerElement)
+        return;
+    NodeImpl *ownerElementParent = ownerElement->parentNode();
+    if (!ownerElementParent)
+        return;
+
+    // Create compute positions before and after the element.
+    unsigned long ownerElementNodeIndex = ownerElement->nodeIndex();
+    VisiblePosition beforeOwnerElement(VisiblePosition(ownerElementParent, ownerElementNodeIndex, khtml::SEL_DEFAULT_AFFINITY));
+    VisiblePosition afterOwnerElement(VisiblePosition(ownerElementParent, ownerElementNodeIndex + 1, khtml::SEL_PREFER_UPSTREAM_AFFINITY));
+
+    // Focus on the parent frame, and then select from before this element to after.
+    parentView->setFocus();
+    parent->setSelection(Selection(beforeOwnerElement, afterOwnerElement));
+}
+
 using namespace KParts;
 #include "khtml_part.moc"
index 555ed24de04f69198d948dade546906da9881845..963860abaa27f2487c7d97b5a1c708defb6f00d2 100644 (file)
@@ -1290,6 +1290,10 @@ private:
 public:
   DOM::DocumentImpl *xmlDocImpl() const;
   void replaceDocImpl(DOM::DocumentImpl* newDoc);
+
+  // Workaround for the fact that it's hard to delete a frame.
+  // Call this after doing user-triggered selections to make it easy to delete the frame you entirely selected.
+  void selectFrameElementInParentIfFullySelected();
   
 private:
   khtml::ChildFrame *childFrame( const QObject *obj );
index 08bf82addb6f23d2716e9e0668b0cf64c838d3ab..1070969c489fd2f5f8c9a3eb1ba43c0371f24a81 100644 (file)
@@ -1545,6 +1545,8 @@ static HTMLFormElementImpl *formElementFromDOMElement(DOMElement *element)
     if (xPos != KHTMLPart::NoXPosForVerticalArrowNavigation)
         _part->setXPosForVerticalArrowNavigation(xPos);
 
+    _part->selectFrameElementInParentIfFullySelected();
+
     [self ensureSelectionVisible];
 }
 
@@ -1572,6 +1574,8 @@ static HTMLFormElementImpl *formElementFromDOMElement(DOMElement *element)
     _part->setSelectionGranularity(static_cast<ETextGranularity>(WebSelectByCharacter));
     _part->setXPosForVerticalArrowNavigation(xPos);
 
+    _part->selectFrameElementInParentIfFullySelected();
+
     [self ensureSelectionVisible];
 }