printf("HandleTableSelection: Unselecting single selected cell\n");
PRINTF("HandleTableSelection: Unselecting single selected cell\n");
nsSelection::HandleTableSelection(nsIContent *aParentContent, PRInt32 aContentOffset, PRUint32 aTarget, nsMouseEvent *aMouseEvent){  if (!aParentContent) return NS_ERROR_NULL_POINTER;  if (mSelectingTableCells && (aTarget & TABLESELECTION_TABLE))  {    // We were selecting cells and user drags mouse in table border or inbetween cells,    //  just do nothing      return NS_OK;  }  nsCOMPtr<nsIDOMNode> parentNode = do_QueryInterface(aParentContent);  if (!parentNode)  return NS_ERROR_FAILURE;  nsCOMPtr<nsIContent> childContent;  nsresult result = aParentContent->ChildAt(aContentOffset, *getter_AddRefs(childContent));  if (NS_FAILED(result)) return result;  if (!childContent)  return NS_ERROR_FAILURE;  nsCOMPtr<nsIDOMNode> childNode = do_QueryInterface(childContent);  if (!childNode)  return NS_ERROR_FAILURE;  // When doing table selection, always set the direction to next  //  so we can be sure that anchorNode's offset always points to the selected cell  PRInt8 index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);  mDomSelections[index]->SetDirection(eDirNext);  // Stack-class to wrap all table selection changes in   //  BeginBatchChanges() / EndBatchChanges()  nsSelectionBatcher selectionBatcher(mDomSelections[index]);  PRInt32 startRowIndex, startColIndex, curRowIndex, curColIndex;  if (mSelectingTableCells)  {    // We are drag-selecting    if (aTarget != TABLESELECTION_TABLE)    {      // If dragging in the same cell as last event, do nothing      if (mEndSelectedCell == childContent)        return NS_OK;      // aTarget can be any "cell mode",      //  so we can easily drag-select rows and columns       // Once we are in row or column mode,      //  we can drift into any cell to stay in that mode      //  even if aTarget = TABLESELECTION_CELL      if (mSelectingTableCellMode == TABLESELECTION_ROW ||          mSelectingTableCellMode == TABLESELECTION_COLUMN)      {        if (mEndSelectedCell)        {          // Also check if cell is in same row/col          result = GetCellIndexes(mEndSelectedCell, startRowIndex, startColIndex);          if (NS_FAILED(result)) return result;          result = GetCellIndexes(childContent, curRowIndex, curColIndex);          if (NS_FAILED(result)) return result;                  if ((mSelectingTableCellMode == TABLESELECTION_ROW && startRowIndex == curRowIndex) ||              (mSelectingTableCellMode == TABLESELECTION_COLUMN && startColIndex == curColIndex))             return NS_OK;        }#ifdef DEBUG_TABLE_SELECTIONprintf("HandleTableSelection: Dragged into a new column or row\n");#endif        // Continue dragging row or column selection        return SelectRowOrColumn(childContent, mSelectingTableCellMode);      }      else if (mSelectingTableCellMode == TABLESELECTION_CELL)      {#ifdef DEBUG_TABLE_SELECTIONprintf("HandleTableSelection: Dragged into a new cell\n");#endif        // Clear this to be sure SelectBlockOfCells works correctly        mAppendStartSelectedCell = nsnull;                // Trick for quick selection of rows and columns        // Hold down shift, then start selecting in one direction        // If next cell dragged into is in same row, select entire row,        //   if next cell is in same column, select entire column        if (mStartSelectedCell && aMouseEvent->isShift)        {          result = GetCellIndexes(mStartSelectedCell, startRowIndex, startColIndex);          if (NS_FAILED(result)) return result;          result = GetCellIndexes(childContent, curRowIndex, curColIndex);          if (NS_FAILED(result)) return result;                    if (startRowIndex == curRowIndex ||               startColIndex == curColIndex)          {            // Force new selection block            mStartSelectedCell = nsnull;            mDomSelections[index]->RemoveAllRanges();            mSelectingTableCellMode =               (startRowIndex == curRowIndex) ? TABLESELECTION_ROW : TABLESELECTION_COLUMN;            return SelectRowOrColumn(childContent, mSelectingTableCellMode);          }        }                // Reselect block of cells to new end location        return SelectBlockOfCells(childContent);      }    }    // Do nothing if dragging in table, but outside a cell    return NS_OK;  }  else   {    // Not dragging  -- mouse event is down or up    if (mMouseDownState)    {#ifdef DEBUG_TABLE_SELECTIONprintf("HandleTableSelection: Mouse down event\n");#endif      // Clear cell we stored in mouse-down      mUnselectCellOnMouseUp = nsnull;            if (aTarget == TABLESELECTION_CELL)      {        PRBool isSelected = PR_FALSE;        // Check if we have other selected cells        nsCOMPtr<nsIDOMNode> previousCellNode;        GetFirstSelectedCellAndRange(getter_AddRefs(previousCellNode), nsnull);        if (previousCellNode)        {          // We have at least 1 other selected cell          // Check if new cell is already selected          nsIFrame  *cellFrame = nsnull;          result = GetTracker()->GetPrimaryFrameFor(childContent, &cellFrame);          if (NS_FAILED(result)) return result;          if (!cellFrame) return NS_ERROR_NULL_POINTER;          result = cellFrame->GetSelected(&isSelected);          if (NS_FAILED(result)) return result;        }        else        {          // No cells selected -- remove non-cell selection          mDomSelections[index]->RemoveAllRanges();        }        mSelectingTableCells = PR_TRUE;    // Signal to start drag-cell-selection        mSelectingTableCellMode = aTarget;        // Set start for new drag-selection block (not appended)        mStartSelectedCell = childContent;        // The initial block end is same as the start        mEndSelectedCell = childContent;                if (isSelected)        {          // Remember this cell to (possibly) unselect it on mouseup          mUnselectCellOnMouseUp = childContent;#ifdef DEBUG_TABLE_SELECTIONprintf("HandleTableSelection: Saving mUnselectCellOnMouseUp\n");#endif        }        else        {          // Select an unselected cell          // but first remove existing selection if not in same table          nsCOMPtr<nsIContent> previousCellContent = do_QueryInterface(previousCellNode);          if (!IsInSameTable(previousCellContent, childContent, nsnull))          {            mDomSelections[index]->RemoveAllRanges();            // Reset selection mode that is cleared in RemoveAllRanges            mSelectingTableCellMode = aTarget;          }          nsCOMPtr<nsIDOMElement> cellElement = do_QueryInterface(childContent);          return SelectCellElement(cellElement);        }        return NS_OK;      }      else if (aTarget == TABLESELECTION_TABLE)      {        //TODO: We currently select entire table when clicked between cells,        //  should we restrict to only around border?        //  *** How do we get location data for cell and click?        mSelectingTableCells = PR_FALSE;        mStartSelectedCell = nsnull;        mEndSelectedCell = nsnull;        // Remove existing selection and select the table        mDomSelections[index]->RemoveAllRanges();        return CreateAndAddRange(parentNode, aContentOffset);      }      else if (aTarget == TABLESELECTION_ROW || aTarget == TABLESELECTION_COLUMN)      {        // Start drag-selecting mode so multiple rows/cols can be selected        // Note: Currently, nsFrame::GetDataForTableSelection        //       will never call us for row or column selection on mouse down        mSelectingTableCells = PR_TRUE;              // Force new selection block        mStartSelectedCell = nsnull;        mDomSelections[index]->RemoveAllRanges();        // Always do this AFTER RemoveAllRanges        mSelectingTableCellMode = aTarget;        return SelectRowOrColumn(childContent, aTarget);      }    }    else    {#ifdef DEBUG_TABLE_SELECTIONprintf("HandleTableSelection: Mouse UP event\n");#endif      // First check if we are extending a block selection      PRInt32 rangeCount;      result = mDomSelections[index]->GetRangeCount(&rangeCount);      if (NS_FAILED(result)) return result;      if (rangeCount > 0 && aMouseEvent->isShift &&           mAppendStartSelectedCell && mAppendStartSelectedCell != childContent)      {        // If Shift is down as well, append a block selection        return SelectBlockOfCells(childContent);      }          // Unselect a cell only if it wasn't      //  just selected on mousedown      if( childContent == mUnselectCellOnMouseUp)      {        // Scan ranges to find the cell to unselect (the selection range to remove)        nsCOMPtr<nsIDOMNode> previousCellParent;        nsCOMPtr<nsIDOMRange> range;        PRInt32 offset;#ifdef DEBUG_TABLE_SELECTIONprintf("HandleTableSelection: Unselecting mUnselectCellOnMouseUp; rangeCount=%d\n", rangeCount);#endif        for( PRInt32 i = 0; i < rangeCount; i++)        {          result = mDomSelections[index]->GetRangeAt(i, getter_AddRefs(range));          if (NS_FAILED(result)) return result;          if (!range) return NS_ERROR_NULL_POINTER;          nsCOMPtr<nsIDOMNode> parent;          result = range->GetStartContainer(getter_AddRefs(parent));          if (NS_FAILED(result)) return result;          if (!parent) return NS_ERROR_NULL_POINTER;          range->GetStartOffset(&offset);          // Be sure previous selection is a table cell          nsCOMPtr<nsIContent> parentContent = do_QueryInterface(parent);          nsCOMPtr<nsIContent> childContent;          result = parentContent->ChildAt(offset, *getter_AddRefs(childContent));          if (NS_FAILED(result)) return result;          if (childContent && IsCell(childContent))            previousCellParent = parent;          // We're done if we didn't find parent of a previously-selected cell          if (!previousCellParent) break;                  if (previousCellParent == parentNode && offset == aContentOffset)          {            // Cell is already selected            if (rangeCount == 1)            {#ifdef DEBUG_TABLE_SELECTIONprintf("HandleTableSelection: Unselecting single selected cell\n");#endif              // This was the only cell selected.              // Collapse to "normal" selection inside the cell              mSelectingTableCells = PR_FALSE;              mStartSelectedCell = nsnull;              mEndSelectedCell = nsnull;              mSelectingTableCellMode = 0;              //TODO: We need a "Collapse to just before deepest child" routine              // Even better, should we collapse to just after the LAST deepest child              //  (i.e., at the end of the cell's contents)?              return mDomSelections[index]->Collapse(childNode, 0);            }#ifdef DEBUG_TABLE_SELECTIONprintf("HandleTableSelection: Removing cell from multi-cell selection\n");#endif            //TODO: Should we try to reassign to a different existing cell?            //mStartSelectedCell = nsnull;            //mEndSelectedCell = nsnull;            // Other cells are selected:            // Deselect cell by removing its range from selection            return mDomSelections[index]->RemoveRange(range);          }        }        mUnselectCellOnMouseUp = nsnull;        // Should we just return here?        // (we failed to unselect the cell)      }      // We have mouse up in a cell that was just selected on mouse down,      //  (and no drag or shift-extend action intervened)      //  Use it as the start of a block that       //  we may append by using Shift+click in another cell      mAppendStartSelectedCell = childContent;#ifdef DEBUG_TABLE_SELECTIONprintf("HandleTableSelection: Setting mAppendStartSelectedCell for append block\n");#endif    }  }  return result;}