LCOV - code coverage report
Current view: directory - editor/libeditor/text - nsPlaintextDataTransfer.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 179 0 0.0 %
Date: 2012-06-02 Functions: 9 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is mozilla.org code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Netscape Communications Corporation.
      19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      26                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : #include "mozilla/Util.h"
      39                 : 
      40                 : #include "nsPlaintextEditor.h"
      41                 : 
      42                 : #include "nsIDOMDocument.h"
      43                 : #include "nsIDocument.h"
      44                 : #include "nsIContent.h"
      45                 : #include "nsIFormControl.h"
      46                 : #include "nsIDOMEventTarget.h" 
      47                 : #include "nsIDOMNSEvent.h"
      48                 : #include "nsIDOMMouseEvent.h"
      49                 : #include "nsIDOMDragEvent.h"
      50                 : #include "nsISelection.h"
      51                 : #include "nsCRT.h"
      52                 : #include "nsServiceManagerUtils.h"
      53                 : 
      54                 : #include "nsIDOMRange.h"
      55                 : #include "nsIDOMDOMStringList.h"
      56                 : #include "nsIDocumentEncoder.h"
      57                 : #include "nsISupportsPrimitives.h"
      58                 : 
      59                 : // Drag & Drop, Clipboard
      60                 : #include "nsIClipboard.h"
      61                 : #include "nsITransferable.h"
      62                 : #include "nsIDragService.h"
      63                 : #include "nsIDOMUIEvent.h"
      64                 : #include "nsCopySupport.h"
      65                 : #include "nsITransferable.h"
      66                 : 
      67                 : // Misc
      68                 : #include "nsEditorUtils.h"
      69                 : #include "nsContentCID.h"
      70                 : #include "nsISelectionPrivate.h"
      71                 : #include "nsFrameSelection.h"
      72                 : #include "nsEventDispatcher.h"
      73                 : #include "nsContentUtils.h"
      74                 : 
      75                 : using namespace mozilla;
      76                 : 
      77               0 : NS_IMETHODIMP nsPlaintextEditor::PrepareTransferable(nsITransferable **transferable)
      78                 : {
      79                 :   // Create generic Transferable for getting the data
      80               0 :   nsresult rv = CallCreateInstance("@mozilla.org/widget/transferable;1", transferable);
      81               0 :   NS_ENSURE_SUCCESS(rv, rv);
      82                 : 
      83                 :   // Get the nsITransferable interface for getting the data from the clipboard
      84               0 :   if (transferable) {
      85               0 :     (*transferable)->AddDataFlavor(kUnicodeMime);
      86               0 :     (*transferable)->AddDataFlavor(kMozTextInternal);
      87                 :   };
      88               0 :   return NS_OK;
      89                 : }
      90                 : 
      91               0 : nsresult nsPlaintextEditor::InsertTextAt(const nsAString &aStringToInsert,
      92                 :                                          nsIDOMNode *aDestinationNode,
      93                 :                                          PRInt32 aDestOffset,
      94                 :                                          bool aDoDeleteSelection)
      95                 : {
      96               0 :   if (aDestinationNode)
      97                 :   {
      98                 :     nsresult res;
      99               0 :     nsCOMPtr<nsISelection>selection;
     100               0 :     res = GetSelection(getter_AddRefs(selection));
     101               0 :     NS_ENSURE_SUCCESS(res, res);
     102                 : 
     103               0 :     nsCOMPtr<nsIDOMNode> targetNode = aDestinationNode;
     104               0 :     PRInt32 targetOffset = aDestOffset;
     105                 : 
     106               0 :     if (aDoDeleteSelection)
     107                 :     {
     108                 :       // Use an auto tracker so that our drop point is correctly
     109                 :       // positioned after the delete.
     110               0 :       nsAutoTrackDOMPoint tracker(mRangeUpdater, &targetNode, &targetOffset);
     111               0 :       res = DeleteSelection(eNone);
     112               0 :       NS_ENSURE_SUCCESS(res, res);
     113                 :     }
     114                 : 
     115               0 :     res = selection->Collapse(targetNode, targetOffset);
     116               0 :     NS_ENSURE_SUCCESS(res, res);
     117                 :   }
     118                 : 
     119               0 :   return InsertText(aStringToInsert);
     120                 : }
     121                 : 
     122               0 : NS_IMETHODIMP nsPlaintextEditor::InsertTextFromTransferable(nsITransferable *aTransferable,
     123                 :                                                             nsIDOMNode *aDestinationNode,
     124                 :                                                             PRInt32 aDestOffset,
     125                 :                                                             bool aDoDeleteSelection)
     126                 : {
     127               0 :   FireTrustedInputEvent trusted(this);
     128                 : 
     129               0 :   nsresult rv = NS_OK;
     130               0 :   char* bestFlavor = nsnull;
     131               0 :   nsCOMPtr<nsISupports> genericDataObj;
     132               0 :   PRUint32 len = 0;
     133               0 :   if (NS_SUCCEEDED(aTransferable->GetAnyTransferData(&bestFlavor, getter_AddRefs(genericDataObj), &len))
     134               0 :       && bestFlavor && (0 == nsCRT::strcmp(bestFlavor, kUnicodeMime) ||
     135               0 :                         0 == nsCRT::strcmp(bestFlavor, kMozTextInternal)))
     136                 :   {
     137               0 :     nsAutoTxnsConserveSelection dontSpazMySelection(this);
     138               0 :     nsCOMPtr<nsISupportsString> textDataObj ( do_QueryInterface(genericDataObj) );
     139               0 :     if (textDataObj && len > 0)
     140                 :     {
     141               0 :       nsAutoString stuffToPaste;
     142               0 :       textDataObj->GetData(stuffToPaste);
     143               0 :       NS_ASSERTION(stuffToPaste.Length() <= (len/2), "Invalid length!");
     144                 : 
     145                 :       // Sanitize possible carriage returns in the string to be inserted
     146               0 :       nsContentUtils::PlatformToDOMLineBreaks(stuffToPaste);
     147                 : 
     148               0 :       nsAutoEditBatch beginBatching(this);
     149               0 :       rv = InsertTextAt(stuffToPaste, aDestinationNode, aDestOffset, aDoDeleteSelection);
     150                 :     }
     151                 :   }
     152               0 :   NS_Free(bestFlavor);
     153                 :       
     154                 :   // Try to scroll the selection into view if the paste/drop succeeded
     155                 : 
     156               0 :   if (NS_SUCCEEDED(rv))
     157               0 :     ScrollSelectionIntoView(false);
     158                 : 
     159               0 :   return rv;
     160                 : }
     161                 : 
     162               0 : nsresult nsPlaintextEditor::InsertFromDataTransfer(nsIDOMDataTransfer *aDataTransfer,
     163                 :                                                    PRInt32 aIndex,
     164                 :                                                    nsIDOMDocument *aSourceDoc,
     165                 :                                                    nsIDOMNode *aDestinationNode,
     166                 :                                                    PRInt32 aDestOffset,
     167                 :                                                    bool aDoDeleteSelection)
     168                 : {
     169               0 :   nsCOMPtr<nsIVariant> data;
     170               0 :   aDataTransfer->MozGetDataAt(NS_LITERAL_STRING("text/plain"), aIndex,
     171               0 :                               getter_AddRefs(data));
     172               0 :   if (data) {
     173               0 :     nsAutoString insertText;
     174               0 :     data->GetAsAString(insertText);
     175               0 :     nsContentUtils::PlatformToDOMLineBreaks(insertText);
     176                 : 
     177               0 :     nsAutoEditBatch beginBatching(this);
     178               0 :     return InsertTextAt(insertText, aDestinationNode, aDestOffset, aDoDeleteSelection);
     179                 :   }
     180                 : 
     181               0 :   return NS_OK;
     182                 : }
     183                 : 
     184               0 : nsresult nsPlaintextEditor::InsertFromDrop(nsIDOMEvent* aDropEvent)
     185                 : {
     186               0 :   ForceCompositionEnd();
     187                 : 
     188               0 :   nsCOMPtr<nsIDOMDragEvent> dragEvent(do_QueryInterface(aDropEvent));
     189               0 :   NS_ENSURE_TRUE(dragEvent, NS_ERROR_FAILURE);
     190                 : 
     191               0 :   nsCOMPtr<nsIDOMDataTransfer> dataTransfer;
     192               0 :   nsresult rv = dragEvent->GetDataTransfer(getter_AddRefs(dataTransfer));
     193               0 :   NS_ENSURE_SUCCESS(rv, rv);
     194                 : 
     195                 :   // Current doc is destination
     196               0 :   nsCOMPtr<nsIDOMDocument> destdomdoc; 
     197               0 :   rv = GetDocument(getter_AddRefs(destdomdoc)); 
     198               0 :   NS_ENSURE_SUCCESS(rv, rv);
     199                 : 
     200               0 :   PRUint32 numItems = 0;
     201               0 :   rv = dataTransfer->GetMozItemCount(&numItems);
     202               0 :   NS_ENSURE_SUCCESS(rv, rv);
     203               0 :   if (numItems < 1) return NS_ERROR_FAILURE;  // nothing to drop?
     204                 : 
     205                 :   // Combine any deletion and drop insertion into one transaction
     206               0 :   nsAutoEditBatch beginBatching(this);
     207                 : 
     208               0 :   bool deleteSelection = false;
     209                 : 
     210                 :   // We have to figure out whether to delete and relocate caret only once
     211                 :   // Parent and offset are under the mouse cursor
     212               0 :   nsCOMPtr<nsIDOMUIEvent> uiEvent = do_QueryInterface(aDropEvent);
     213               0 :   NS_ENSURE_TRUE(uiEvent, NS_ERROR_FAILURE);
     214                 : 
     215               0 :   nsCOMPtr<nsIDOMNode> newSelectionParent;
     216               0 :   rv = uiEvent->GetRangeParent(getter_AddRefs(newSelectionParent));
     217               0 :   NS_ENSURE_SUCCESS(rv, rv);
     218               0 :   NS_ENSURE_TRUE(newSelectionParent, NS_ERROR_FAILURE);
     219                 : 
     220                 :   PRInt32 newSelectionOffset;
     221               0 :   rv = uiEvent->GetRangeOffset(&newSelectionOffset);
     222               0 :   NS_ENSURE_SUCCESS(rv, rv);
     223                 : 
     224               0 :   nsCOMPtr<nsISelection> selection;
     225               0 :   rv = GetSelection(getter_AddRefs(selection));
     226               0 :   NS_ENSURE_SUCCESS(rv, rv);
     227               0 :   NS_ENSURE_TRUE(selection, NS_ERROR_FAILURE);
     228                 : 
     229                 :   bool isCollapsed;
     230               0 :   rv = selection->GetIsCollapsed(&isCollapsed);
     231               0 :   NS_ENSURE_SUCCESS(rv, rv);
     232                 : 
     233               0 :   nsCOMPtr<nsIDOMNode> sourceNode;
     234               0 :   dataTransfer->GetMozSourceNode(getter_AddRefs(sourceNode));
     235                 : 
     236               0 :   nsCOMPtr<nsIDOMDocument> srcdomdoc;
     237               0 :   if (sourceNode) {
     238               0 :     sourceNode->GetOwnerDocument(getter_AddRefs(srcdomdoc));
     239               0 :     NS_ENSURE_TRUE(sourceNode, NS_ERROR_FAILURE);
     240                 :   }
     241                 : 
     242                 :   // Only the nsHTMLEditor::FindUserSelectAllNode returns a node.
     243               0 :   nsCOMPtr<nsIDOMNode> userSelectNode = FindUserSelectAllNode(newSelectionParent);
     244               0 :   if (userSelectNode)
     245                 :   {
     246                 :     // The drop is happening over a "-moz-user-select: all"
     247                 :     // subtree so make sure the content we insert goes before
     248                 :     // the root of the subtree.
     249                 :     //
     250                 :     // XXX: Note that inserting before the subtree matches the
     251                 :     //      current behavior when dropping on top of an image.
     252                 :     //      The decision for dropping before or after the
     253                 :     //      subtree should really be done based on coordinates.
     254                 : 
     255                 :     rv = GetNodeLocation(userSelectNode, address_of(newSelectionParent),
     256               0 :                          &newSelectionOffset);
     257                 : 
     258               0 :     NS_ENSURE_SUCCESS(rv, rv);
     259               0 :     NS_ENSURE_TRUE(newSelectionParent, NS_ERROR_FAILURE);
     260                 :   }
     261                 : 
     262                 :   // Check if mouse is in the selection
     263                 :   // if so, jump through some hoops to determine if mouse is over selection (bail)
     264                 :   // and whether user wants to copy selection or delete it
     265               0 :   if (!isCollapsed)
     266                 :   {
     267                 :     // We never have to delete if selection is already collapsed
     268               0 :     bool cursorIsInSelection = false;
     269                 : 
     270                 :     PRInt32 rangeCount;
     271               0 :     rv = selection->GetRangeCount(&rangeCount);
     272               0 :     NS_ENSURE_SUCCESS(rv, rv);
     273                 : 
     274               0 :     for (PRInt32 j = 0; j < rangeCount; j++)
     275                 :     {
     276               0 :       nsCOMPtr<nsIDOMRange> range;
     277               0 :       rv = selection->GetRangeAt(j, getter_AddRefs(range));
     278               0 :       if (NS_FAILED(rv) || !range) 
     279               0 :         continue;  // don't bail yet, iterate through them all
     280                 : 
     281               0 :       rv = range->IsPointInRange(newSelectionParent, newSelectionOffset, &cursorIsInSelection);
     282               0 :       if (cursorIsInSelection)
     283                 :         break;
     284                 :     }
     285                 : 
     286               0 :     if (cursorIsInSelection)
     287                 :     {
     288                 :       // Dragging within same doc can't drop on itself -- leave!
     289               0 :       if (srcdomdoc == destdomdoc)
     290               0 :         return NS_OK;
     291                 : 
     292                 :       // Dragging from another window onto a selection
     293                 :       // XXX Decision made to NOT do this,
     294                 :       //     note that 4.x does replace if dropped on
     295                 :       //deleteSelection = true;
     296                 :     }
     297                 :     else 
     298                 :     {
     299                 :       // We are NOT over the selection
     300               0 :       if (srcdomdoc == destdomdoc)
     301                 :       {
     302                 :         // Within the same doc: delete if user doesn't want to copy
     303                 :         PRUint32 dropEffect;
     304               0 :         dataTransfer->GetDropEffectInt(&dropEffect);
     305               0 :         deleteSelection = !(dropEffect & nsIDragService::DRAGDROP_ACTION_COPY);
     306                 :       }
     307                 :       else
     308                 :       {
     309                 :         // Different source doc: Don't delete
     310               0 :         deleteSelection = false;
     311                 :       }
     312                 :     }
     313                 :   }
     314                 : 
     315               0 :   if (IsPlaintextEditor()) {
     316               0 :     nsCOMPtr<nsIContent> content = do_QueryInterface(newSelectionParent);
     317               0 :     while (content) {
     318               0 :       nsCOMPtr<nsIFormControl> formControl(do_QueryInterface(content));
     319               0 :       if (formControl && !formControl->AllowDrop()) {
     320                 :         // Don't allow dropping into a form control that doesn't allow being
     321                 :         // dropped into.
     322               0 :         return NS_OK;
     323                 :       }
     324               0 :       content = content->GetParent();
     325                 :     }
     326                 :   }
     327                 : 
     328               0 :   for (PRUint32 i = 0; i < numItems; ++i) {
     329                 :     InsertFromDataTransfer(dataTransfer, i, srcdomdoc, newSelectionParent,
     330               0 :                            newSelectionOffset, deleteSelection);
     331                 :   }
     332                 : 
     333               0 :   if (NS_SUCCEEDED(rv))
     334               0 :     ScrollSelectionIntoView(false);
     335                 : 
     336               0 :   return rv;
     337                 : }
     338                 : 
     339               0 : NS_IMETHODIMP nsPlaintextEditor::Paste(PRInt32 aSelectionType)
     340                 : {
     341               0 :   if (!FireClipboardEvent(NS_PASTE))
     342               0 :     return NS_OK;
     343                 : 
     344                 :   // Get Clipboard Service
     345                 :   nsresult rv;
     346               0 :   nsCOMPtr<nsIClipboard> clipboard(do_GetService("@mozilla.org/widget/clipboard;1", &rv));
     347               0 :   if ( NS_FAILED(rv) )
     348               0 :     return rv;
     349                 : 
     350                 :   // Get the nsITransferable interface for getting the data from the clipboard
     351               0 :   nsCOMPtr<nsITransferable> trans;
     352               0 :   rv = PrepareTransferable(getter_AddRefs(trans));
     353               0 :   if (NS_SUCCEEDED(rv) && trans)
     354                 :   {
     355                 :     // Get the Data from the clipboard  
     356               0 :     if (NS_SUCCEEDED(clipboard->GetData(trans, aSelectionType)) && IsModifiable())
     357                 :     {
     358                 :       // handle transferable hooks
     359               0 :       nsCOMPtr<nsIDOMDocument> domdoc;
     360               0 :       GetDocument(getter_AddRefs(domdoc));
     361               0 :       if (!nsEditorHookUtils::DoInsertionHook(domdoc, nsnull, trans))
     362               0 :         return NS_OK;
     363                 : 
     364               0 :       rv = InsertTextFromTransferable(trans, nsnull, nsnull, true);
     365                 :     }
     366                 :   }
     367                 : 
     368               0 :   return rv;
     369                 : }
     370                 : 
     371               0 : NS_IMETHODIMP nsPlaintextEditor::PasteTransferable(nsITransferable *aTransferable)
     372                 : {
     373               0 :   if (!FireClipboardEvent(NS_PASTE))
     374               0 :     return NS_OK;
     375                 : 
     376               0 :   if (!IsModifiable())
     377               0 :     return NS_OK;
     378                 : 
     379                 :   // handle transferable hooks
     380               0 :   nsCOMPtr<nsIDOMDocument> domdoc;
     381               0 :   GetDocument(getter_AddRefs(domdoc));
     382               0 :   if (!nsEditorHookUtils::DoInsertionHook(domdoc, nsnull, aTransferable))
     383               0 :     return NS_OK;
     384                 : 
     385               0 :   return InsertTextFromTransferable(aTransferable, nsnull, nsnull, true);
     386                 : }
     387                 : 
     388               0 : NS_IMETHODIMP nsPlaintextEditor::CanPaste(PRInt32 aSelectionType, bool *aCanPaste)
     389                 : {
     390               0 :   NS_ENSURE_ARG_POINTER(aCanPaste);
     391               0 :   *aCanPaste = false;
     392                 : 
     393                 :   // can't paste if readonly
     394               0 :   if (!IsModifiable())
     395               0 :     return NS_OK;
     396                 : 
     397                 :   nsresult rv;
     398               0 :   nsCOMPtr<nsIClipboard> clipboard(do_GetService("@mozilla.org/widget/clipboard;1", &rv));
     399               0 :   NS_ENSURE_SUCCESS(rv, rv);
     400                 :   
     401                 :   // the flavors that we can deal with
     402               0 :   const char* textEditorFlavors[] = { kUnicodeMime };
     403                 : 
     404                 :   bool haveFlavors;
     405               0 :   rv = clipboard->HasDataMatchingFlavors(textEditorFlavors,
     406                 :                                          ArrayLength(textEditorFlavors),
     407               0 :                                          aSelectionType, &haveFlavors);
     408               0 :   NS_ENSURE_SUCCESS(rv, rv);
     409                 :   
     410               0 :   *aCanPaste = haveFlavors;
     411               0 :   return NS_OK;
     412                 : }
     413                 : 
     414                 : 
     415               0 : NS_IMETHODIMP nsPlaintextEditor::CanPasteTransferable(nsITransferable *aTransferable, bool *aCanPaste)
     416                 : {
     417               0 :   NS_ENSURE_ARG_POINTER(aCanPaste);
     418                 : 
     419                 :   // can't paste if readonly
     420               0 :   if (!IsModifiable()) {
     421               0 :     *aCanPaste = false;
     422               0 :     return NS_OK;
     423                 :   }
     424                 : 
     425                 :   // If |aTransferable| is null, assume that a paste will succeed.
     426               0 :   if (!aTransferable) {
     427               0 :     *aCanPaste = true;
     428               0 :     return NS_OK;
     429                 :   }
     430                 : 
     431               0 :   nsCOMPtr<nsISupports> data;
     432                 :   PRUint32 dataLen;
     433                 :   nsresult rv = aTransferable->GetTransferData(kUnicodeMime,
     434               0 :                                                getter_AddRefs(data),
     435               0 :                                                &dataLen);
     436               0 :   if (NS_SUCCEEDED(rv) && data)
     437               0 :     *aCanPaste = true;
     438                 :   else
     439               0 :     *aCanPaste = false;
     440                 :   
     441               0 :   return NS_OK;
     442                 : }

Generated by: LCOV version 1.7