Bug 415707 - multiple text selection improvement doesn't work with double-click "word-by-word" or triple-click "paragraph" modes. r+sr=roc.

This commit is contained in:
Uri Bernstein 2008-10-17 21:46:33 +02:00
Родитель f6621ba654
Коммит 269b19b637
3 изменённых файлов: 109 добавлений и 96 удалений

Просмотреть файл

@ -1959,7 +1959,11 @@ nsFrame::HandlePress(nsPresContext* aPresContext,
#ifdef XP_MACOSX
if (me->isControl)
return NS_OK;//short ciruit. hard coded for mac due to time restraints.
PRBool control = me->isMeta;
#else
PRBool control = me->isControl;
#endif
nsCOMPtr<nsFrameSelection> fc = const_cast<nsFrameSelection*>(frameselection);
if (me->clickCount >1 )
{
@ -1967,7 +1971,7 @@ nsFrame::HandlePress(nsPresContext* aPresContext,
// so no need for nsWeakFrame.
fc->SetMouseDownState(PR_TRUE);
fc->SetMouseDoubleDown(PR_TRUE);
return HandleMultiplePress(aPresContext, aEvent, aEventStatus);
return HandleMultiplePress(aPresContext, aEvent, aEventStatus, control);
}
if (!offsets.content)
@ -2036,12 +2040,6 @@ nsFrame::HandlePress(nsPresContext* aPresContext,
fc->SetMouseDownState(PR_TRUE);
#ifdef XP_MACOSX
PRBool control = me->isMeta;
#else
PRBool control = me->isControl;
#endif
// Do not touch any nsFrame members after this point without adding
// weakFrame checks.
rv = fc->HandleClick(offsets.content, offsets.StartOffset(),
@ -2074,8 +2072,9 @@ nsFrame::HandlePress(nsPresContext* aPresContext,
*/
NS_IMETHODIMP
nsFrame::HandleMultiplePress(nsPresContext* aPresContext,
nsGUIEvent* aEvent,
nsEventStatus* aEventStatus)
nsGUIEvent* aEvent,
nsEventStatus* aEventStatus,
PRBool aControlHeld)
{
NS_ENSURE_ARG_POINTER(aEventStatus);
if (nsEventStatus_eConsumeNoDefault == *aEventStatus) {
@ -2130,7 +2129,8 @@ nsFrame::HandleMultiplePress(nsPresContext* aPresContext,
return frame->PeekBackwardAndForward(beginAmount, endAmount,
offsets.offset, aPresContext,
beginAmount != eSelectWord);
beginAmount != eSelectWord,
aControlHeld);
}
NS_IMETHODIMP
@ -2138,23 +2138,13 @@ nsFrame::PeekBackwardAndForward(nsSelectionAmount aAmountBack,
nsSelectionAmount aAmountForward,
PRInt32 aStartPos,
nsPresContext* aPresContext,
PRBool aJumpLines)
PRBool aJumpLines,
PRBool aMultipleSelection)
{
nsCOMPtr<nsISelectionController> selcon;
nsresult rv = GetSelectionController(aPresContext, getter_AddRefs(selcon));
if (NS_FAILED(rv)) return rv;
if (!selcon)
return NS_ERROR_NOT_INITIALIZED;
// Use peek offset one way then the other:
nsCOMPtr<nsIContent> startContent;
nsCOMPtr<nsIDOMNode> startNode;
nsCOMPtr<nsIContent> endContent;
nsCOMPtr<nsIDOMNode> endNode;
nsIFrame* baseFrame = this;
PRInt32 baseOffset = aStartPos;
nsresult rv;
if (aAmountBack == eSelectWord) {
// To avoid selecting the previous word when at start of word,
// first move one character forward.
@ -2173,6 +2163,8 @@ nsFrame::PeekBackwardAndForward(nsSelectionAmount aAmountBack,
baseOffset = pos.mContentOffset;
}
}
// Use peek offset one way then the other:
nsPeekOffsetStruct startpos;
startpos.SetData(aAmountBack,
eDirPrevious,
@ -2199,26 +2191,22 @@ nsFrame::PeekBackwardAndForward(nsSelectionAmount aAmountBack,
if (NS_FAILED(rv))
return rv;
endNode = do_QueryInterface(endpos.mResultContent, &rv);
if (NS_FAILED(rv))
return rv;
startNode = do_QueryInterface(startpos.mResultContent, &rv);
// Keep frameSelection alive.
nsRefPtr<nsFrameSelection> frameSelection = GetFrameSelection();
rv = frameSelection->HandleClick(startpos.mResultContent,
startpos.mContentOffset, startpos.mContentOffset,
PR_FALSE, aMultipleSelection,
nsFrameSelection::HINTRIGHT);
if (NS_FAILED(rv))
return rv;
// Keep frameSelection alive.
nsRefPtr<nsFrameSelection> frameSelection = GetFrameSelection();
nsCOMPtr<nsISelection> selection;
if (NS_SUCCEEDED(selcon->GetSelection(nsISelectionController::SELECTION_NORMAL,
getter_AddRefs(selection)))){
rv = selection->Collapse(startNode,startpos.mContentOffset);
if (NS_FAILED(rv))
return rv;
rv = selection->Extend(endNode,endpos.mContentOffset);
if (NS_FAILED(rv))
return rv;
}
//no release
rv = frameSelection->HandleClick(endpos.mResultContent,
endpos.mContentOffset, endpos.mContentOffset,
PR_TRUE, PR_FALSE,
nsFrameSelection::HINTLEFT);
if (NS_FAILED(rv))
return rv;
// maintain selection
return frameSelection->MaintainSelection(aAmountBack);

Просмотреть файл

@ -345,7 +345,8 @@ public:
NS_IMETHOD HandleMultiplePress(nsPresContext* aPresContext,
nsGUIEvent * aEvent,
nsEventStatus* aEventStatus);
nsEventStatus* aEventStatus,
PRBool aControlHeld);
NS_IMETHOD HandleDrag(nsPresContext* aPresContext,
nsGUIEvent * aEvent,
@ -359,7 +360,8 @@ public:
nsSelectionAmount aAmountForward,
PRInt32 aStartPos,
nsPresContext* aPresContext,
PRBool aJumpLines);
PRBool aJumpLines,
PRBool aMultipleSelection);
// Helper for GetContentAndOffsetsFromPoint; calculation of content offsets

Просмотреть файл

@ -219,6 +219,7 @@ public:
PRInt16 aHPercent = NS_PRESSHELL_SCROLL_ANYWHERE);
nsresult AddItem(nsIDOMRange *aRange, PRInt32* aOutIndex = nsnull);
nsresult RemoveItem(nsIDOMRange *aRange);
nsresult RemoveCollapsedRanges();
nsresult Clear(nsPresContext* aPresContext);
// methods for convenience. Note, these don't addref
@ -236,7 +237,7 @@ public:
nsDirection GetDirection(){return mDirection;}
void SetDirection(nsDirection aDir){mDirection = aDir;}
NS_IMETHOD CopyRangeToAnchorFocus(nsIDOMRange *aRange);
void ReplaceAnchorFocusRange(nsIDOMRange *aRange);
// NS_IMETHOD GetPrimaryFrameForRangeEndpoint(nsIDOMNode *aNode, PRInt32 aOffset, PRBool aIsEndNode, nsIFrame **aResultFrame);
NS_IMETHOD GetPrimaryFrameForAnchorNode(nsIFrame **aResultFrame);
@ -1628,12 +1629,6 @@ nsresult
nsFrameSelection::MaintainSelection(nsSelectionAmount aAmount)
{
PRInt8 index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
nsCOMPtr<nsIDOMRange> range;
nsresult rv = mDomSelections[index]->GetRangeAt(0, getter_AddRefs(range));
if (NS_FAILED(rv))
return rv;
if (!range)
return NS_ERROR_FAILURE;
mMaintainedAmount = aAmount;
@ -1641,10 +1636,15 @@ nsFrameSelection::MaintainSelection(nsSelectionAmount aAmount)
nsCOMPtr<nsIDOMNode> endNode;
PRInt32 startOffset;
PRInt32 endOffset;
range->GetStartContainer(getter_AddRefs(startNode));
range->GetEndContainer(getter_AddRefs(endNode));
range->GetStartOffset(&startOffset);
range->GetEndOffset(&endOffset);
nsresult rv;
rv = mDomSelections[index]->GetAnchorNode(getter_AddRefs(startNode));
NS_ENSURE_SUCCESS(rv, rv);
rv = mDomSelections[index]->GetFocusNode(getter_AddRefs(endNode));
NS_ENSURE_SUCCESS(rv, rv);
rv = mDomSelections[index]->GetAnchorOffset(&startOffset);
NS_ENSURE_SUCCESS(rv, rv);
rv = mDomSelections[index]->GetFocusOffset(&endOffset);
NS_ENSURE_SUCCESS(rv, rv);
mMaintainRange = nsnull;
NS_NewRange(getter_AddRefs(mMaintainRange));
@ -1731,55 +1731,44 @@ PRBool
nsFrameSelection::AdjustForMaintainedSelection(nsIContent *aContent,
PRInt32 aOffset)
{
// Is the desired content and offset currently in selection?
// If the double click flag is set then don't continue selection if the
// desired content and offset are currently inside a selection.
// This will stop double click then mouse-drag from undoing the desired
// selecting of a word.
if (!mMaintainRange)
return PR_FALSE;
nsCOMPtr<nsIDOMNode> rangenode;
PRInt32 rangeOffset;
mMaintainRange->GetStartContainer(getter_AddRefs(rangenode));
mMaintainRange->GetStartOffset(&rangeOffset);
nsCOMPtr<nsIDOMNode> domNode = do_QueryInterface(aContent);
if (domNode)
{
PRInt8 index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
nsCOMPtr<nsIDOMNSRange> nsrange = do_QueryInterface(mMaintainRange);
if (nsrange)
{
PRBool insideSelection = PR_FALSE;
nsrange->IsPointInRange(domNode, aOffset, &insideSelection);
if (!domNode)
return PR_FALSE;
PRInt8 index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
// Done when we find a range that we are in
if (insideSelection)
{
mDomSelections[index]->Collapse(rangenode, rangeOffset);
mMaintainRange->GetEndContainer(getter_AddRefs(rangenode));
mMaintainRange->GetEndOffset(&rangeOffset);
mDomSelections[index]->Extend(rangenode,rangeOffset);
return PR_TRUE; // dragging in selection aborted
}
}
nsCOMPtr<nsIDOMNode> rangeStartNode, rangeEndNode;
PRInt32 rangeStartOffset, rangeEndOffset;
mMaintainRange->GetStartContainer(getter_AddRefs(rangeStartNode));
mMaintainRange->GetEndContainer(getter_AddRefs(rangeEndNode));
mMaintainRange->GetStartOffset(&rangeStartOffset);
mMaintainRange->GetEndOffset(&rangeEndOffset);
PRInt32 relativePosition = CompareDOMPoints(rangenode, rangeOffset,
domNode, aOffset);
// if == 0 or -1 do nothing if < 0 then we need to swap direction
if (relativePosition > 0
&& (mDomSelections[index]->GetDirection() == eDirNext))
{
mMaintainRange->GetEndContainer(getter_AddRefs(rangenode));
mMaintainRange->GetEndOffset(&rangeOffset);
mDomSelections[index]->Collapse(rangenode, rangeOffset);
PRInt32 relToStart = CompareDOMPoints(rangeStartNode, rangeStartOffset,
domNode, aOffset);
PRInt32 relToEnd = CompareDOMPoints(rangeEndNode, rangeEndOffset,
domNode, aOffset);
// If aContent/aOffset is inside the maintained selection, or if it is on the
// "anchor" side of the maintained selection, we need to do something.
if (relToStart < 0 && relToEnd > 0 ||
(relToStart > 0 &&
mDomSelections[index]->GetDirection() == eDirNext) ||
(relToEnd < 0 &&
mDomSelections[index]->GetDirection() == eDirPrevious)) {
// Set the current range to the maintained range.
mDomSelections[index]->ReplaceAnchorFocusRange(mMaintainRange);
if (relToStart < 0 && relToEnd > 0) {
// We're inside the maintained selection, just keep it selected.
return PR_TRUE;
}
else if (relativePosition < 0
&& (mDomSelections[index]->GetDirection() == eDirPrevious))
mDomSelections[index]->Collapse(rangenode, rangeOffset);
// Reverse the direction of the selection so that the anchor will be on the
// far side of the maintained selection, relative to aContent/aOffset.
mDomSelections[index]->SetDirection(relToStart > 0 ? eDirPrevious : eDirNext);
}
return PR_FALSE;
}
@ -1937,7 +1926,11 @@ nsFrameSelection::TakeFocus(nsIContent *aNewFocus,
PRBool changes = mChangesDuringBatching;
mBatching = 1;
if (aMultipleSelection){
if (aMultipleSelection) {
// Remove existing collapsed ranges as there's no point in having
// non-anchor/focus collapsed ranges.
mDomSelections[index]->RemoveCollapsedRanges();
nsCOMPtr<nsIDOMRange> newRange;
NS_NewRange(getter_AddRefs(newRange));
@ -4066,6 +4059,24 @@ nsTypedSelection::RemoveItem(nsIDOMRange *aItem)
return NS_OK;
}
nsresult
nsTypedSelection::RemoveCollapsedRanges()
{
nsresult rv;
PRUint32 i = 0;
while (i < mRanges.Length()) {
PRBool isCollapsed;
rv = mRanges[i].mRange->GetCollapsed(&isCollapsed);
NS_ENSURE_SUCCESS(rv, rv);
if (isCollapsed) {
rv = RemoveItem(mRanges[i].mRange);
NS_ENSURE_SUCCESS(rv, rv);
} else {
++i;
}
}
return NS_OK;
}
nsresult
nsTypedSelection::Clear(nsPresContext* aPresContext)
@ -5637,6 +5648,18 @@ nsTypedSelection::CopyRangeToAnchorFocus(nsIDOMRange *aRange)
return NS_OK;
}
void
nsTypedSelection::ReplaceAnchorFocusRange(nsIDOMRange *aRange)
{
nsCOMPtr<nsPresContext> presContext;
GetPresContext(getter_AddRefs(presContext));
if (presContext) {
selectFrames(presContext, mAnchorFocusRange, PR_FALSE);
CopyRangeToAnchorFocus(aRange);
selectFrames(presContext, mAnchorFocusRange, PR_TRUE);
}
}
/*
Notes which might come in handy for extend: