~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/editor/libeditor/base/IMETextTxn.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 
2
/* ***** BEGIN LICENSE BLOCK *****
 
3
 * Version: NPL 1.1/GPL 2.0/LGPL 2.1
 
4
 *
 
5
 * The contents of this file are subject to the Netscape Public License
 
6
 * Version 1.1 (the "License"); you may not use this file except in
 
7
 * compliance with the License. You may obtain a copy of the License at
 
8
 * http://www.mozilla.org/NPL/
 
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-1999
 
20
 * the Initial Developer. All Rights Reserved.
 
21
 *
 
22
 * Contributor(s):
 
23
 *   Pierre Phaneuf <pp@ludusdesign.com>
 
24
 *
 
25
 *
 
26
 * Alternatively, the contents of this file may be used under the terms of
 
27
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 
28
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
29
 * in which case the provisions of the GPL or the LGPL are applicable instead
 
30
 * of those above. If you wish to allow use of your version of this file only
 
31
 * under the terms of either the GPL or the LGPL, and not to allow others to
 
32
 * use your version of this file under the terms of the NPL, indicate your
 
33
 * decision by deleting the provisions above and replace them with the notice
 
34
 * and other provisions required by the GPL or the LGPL. If you do not delete
 
35
 * the provisions above, a recipient may use your version of this file under
 
36
 * the terms of any one of the NPL, the GPL or the LGPL.
 
37
 *
 
38
 * ***** END LICENSE BLOCK ***** */
 
39
 
 
40
#include "IMETextTxn.h"
 
41
#include "nsIDOMCharacterData.h"
 
42
#include "nsIDOMRange.h"
 
43
#include "nsIPrivateTextRange.h"
 
44
#include "nsISelection.h"
 
45
#include "nsISelectionPrivate.h"
 
46
#include "nsISelectionController.h"
 
47
#include "nsComponentManagerUtils.h"
 
48
 
 
49
// #define DEBUG_IMETXN
 
50
 
 
51
nsIAtom *IMETextTxn::gIMETextTxnName = nsnull;
 
52
 
 
53
nsresult IMETextTxn::ClassInit()
 
54
{
 
55
  if (!gIMETextTxnName)
 
56
    gIMETextTxnName = NS_NewAtom("NS_IMETextTxn");
 
57
  return NS_OK;
 
58
}
 
59
 
 
60
nsresult IMETextTxn::ClassShutdown()
 
61
{
 
62
  NS_IF_RELEASE(gIMETextTxnName);
 
63
  return NS_OK;
 
64
}
 
65
 
 
66
IMETextTxn::IMETextTxn()
 
67
  : EditTxn()
 
68
{
 
69
}
 
70
 
 
71
IMETextTxn::~IMETextTxn()
 
72
{
 
73
  mRangeList = do_QueryInterface(nsnull);
 
74
}
 
75
 
 
76
NS_IMETHODIMP IMETextTxn::Init(nsIDOMCharacterData     *aElement,
 
77
                               PRUint32                 aOffset,
 
78
                               PRUint32                 aReplaceLength,
 
79
                               nsIPrivateTextRangeList *aTextRangeList,
 
80
                               const nsAString         &aStringToInsert,
 
81
                               nsWeakPtr                aSelConWeak)
 
82
{
 
83
  NS_ASSERTION(aElement, "illegal value- null ptr- aElement");
 
84
  NS_ASSERTION(aTextRangeList, "illegal value- null ptr - aTextRangeList");
 
85
  if (!aElement || !aTextRangeList)
 
86
     return NS_ERROR_NULL_POINTER;
 
87
  mElement = do_QueryInterface(aElement);
 
88
  mOffset = aOffset;
 
89
  mReplaceLength = aReplaceLength;
 
90
  mStringToInsert = aStringToInsert;
 
91
  mSelConWeak = aSelConWeak;
 
92
  mRangeList = do_QueryInterface(aTextRangeList);
 
93
  mFixed = PR_FALSE;
 
94
  return NS_OK;
 
95
}
 
96
 
 
97
NS_IMETHODIMP IMETextTxn::DoTransaction(void)
 
98
{
 
99
 
 
100
#ifdef DEBUG_IMETXN
 
101
  printf("Do IME Text element = %p replace = %d len = %d\n", mElement.get(), mReplaceLength, mStringToInsert.Length());
 
102
#endif
 
103
 
 
104
  nsCOMPtr<nsISelectionController> selCon = do_QueryReferent(mSelConWeak);
 
105
  if (!selCon) return NS_ERROR_NOT_INITIALIZED;
 
106
 
 
107
  // advance caret: This requires the presentation shell to get the selection.
 
108
  nsresult result;
 
109
  if (mReplaceLength == 0) {
 
110
    result = mElement->InsertData(mOffset, mStringToInsert);
 
111
  } else {
 
112
    result = mElement->ReplaceData(mOffset, mReplaceLength, mStringToInsert);
 
113
  }
 
114
  if (NS_SUCCEEDED(result)) {
 
115
    result = CollapseTextSelection();
 
116
  }
 
117
 
 
118
  return result;
 
119
}
 
120
 
 
121
NS_IMETHODIMP IMETextTxn::UndoTransaction(void)
 
122
{
 
123
#ifdef DEBUG_IMETXN
 
124
  printf("Undo IME Text element = %p\n", mElement.get());
 
125
#endif
 
126
 
 
127
  nsCOMPtr<nsISelectionController> selCon = do_QueryReferent(mSelConWeak);
 
128
  if (!selCon) return NS_ERROR_NOT_INITIALIZED;
 
129
 
 
130
  nsresult result = mElement->DeleteData(mOffset, mStringToInsert.Length());
 
131
  if (NS_SUCCEEDED(result))
 
132
  { // set the selection to the insertion point where the string was removed
 
133
    nsCOMPtr<nsISelection> selection;
 
134
    result = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
 
135
    if (NS_SUCCEEDED(result) && selection) {
 
136
      result = selection->Collapse(mElement, mOffset);
 
137
      NS_ASSERTION((NS_SUCCEEDED(result)), "selection could not be collapsed after undo of IME insert.");
 
138
    }
 
139
  }
 
140
  return result;
 
141
}
 
142
 
 
143
NS_IMETHODIMP IMETextTxn::Merge(nsITransaction *aTransaction, PRBool *aDidMerge)
 
144
{
 
145
  NS_ASSERTION(aDidMerge, "illegal vaule- null ptr- aDidMerge");
 
146
  NS_ASSERTION(aTransaction, "illegal vaule- null ptr- aTransaction");
 
147
  if (!aDidMerge || !aTransaction)
 
148
    return NS_ERROR_NULL_POINTER;
 
149
    
 
150
#ifdef DEBUG_IMETXN
 
151
  printf("Merge IME Text element = %p\n", mElement.get());
 
152
#endif
 
153
 
 
154
  // 
 
155
  // check to make sure we aren't fixed, if we are then nothing get's absorbed
 
156
  //
 
157
  if (mFixed) {
 
158
    *aDidMerge = PR_FALSE;
 
159
    return NS_OK;
 
160
  }
 
161
 
 
162
  //
 
163
  // if aTransaction is another IMETextTxn then absorb it
 
164
  //
 
165
  IMETextTxn*  otherTxn = nsnull;
 
166
  nsresult result = aTransaction->QueryInterface(IMETextTxn::GetCID(),(void**)&otherTxn);
 
167
  if (otherTxn && NS_SUCCEEDED(result))
 
168
  {
 
169
    //
 
170
    //  we absorb the next IME transaction by adopting its insert string as our own
 
171
    //
 
172
    nsIPrivateTextRangeList* newTextRangeList;
 
173
    otherTxn->GetData(mStringToInsert,&newTextRangeList);
 
174
    mRangeList = do_QueryInterface(newTextRangeList);
 
175
    *aDidMerge = PR_TRUE;
 
176
#ifdef DEBUG_IMETXN
 
177
    printf("IMETextTxn assimilated IMETextTxn:%p\n", aTransaction);
 
178
#endif
 
179
    NS_RELEASE(otherTxn);
 
180
    return NS_OK;
 
181
  }
 
182
 
 
183
  *aDidMerge = PR_FALSE;
 
184
  return NS_OK;
 
185
}
 
186
 
 
187
NS_IMETHODIMP IMETextTxn::MarkFixed(void)
 
188
{
 
189
  mFixed = PR_TRUE;
 
190
  return NS_OK;
 
191
}
 
192
 
 
193
NS_IMETHODIMP IMETextTxn::GetTxnDescription(nsAString& aString)
 
194
{
 
195
  aString.Assign(NS_LITERAL_STRING("IMETextTxn: "));
 
196
  aString += mStringToInsert;
 
197
  return NS_OK;
 
198
}
 
199
 
 
200
/* ============= nsISupports implementation ====================== */
 
201
 
 
202
NS_IMETHODIMP
 
203
IMETextTxn::QueryInterface(REFNSIID aIID, void** aInstancePtr)
 
204
{
 
205
  if (nsnull == aInstancePtr) {
 
206
    return NS_ERROR_NULL_POINTER;
 
207
  }
 
208
  if (aIID.Equals(IMETextTxn::GetCID())) {
 
209
    *aInstancePtr = (void*)(IMETextTxn*)this;
 
210
    NS_ADDREF_THIS();
 
211
    return NS_OK;
 
212
  }
 
213
  return (EditTxn::QueryInterface(aIID, aInstancePtr));
 
214
}
 
215
 
 
216
/* ============ protected methods ================== */
 
217
static SelectionType TextRangeToSelection(int aTextRangeType)
 
218
{
 
219
   switch(aTextRangeType)
 
220
   {
 
221
      case nsIPrivateTextRange::TEXTRANGE_RAWINPUT:
 
222
           return nsISelectionController::SELECTION_IME_RAWINPUT;
 
223
      case nsIPrivateTextRange::TEXTRANGE_SELECTEDRAWTEXT:
 
224
           return nsISelectionController::SELECTION_IME_SELECTEDRAWTEXT;
 
225
      case nsIPrivateTextRange::TEXTRANGE_CONVERTEDTEXT:
 
226
           return nsISelectionController::SELECTION_IME_CONVERTEDTEXT;
 
227
      case nsIPrivateTextRange::TEXTRANGE_SELECTEDCONVERTEDTEXT:
 
228
           return nsISelectionController::SELECTION_IME_SELECTEDCONVERTEDTEXT;
 
229
      case nsIPrivateTextRange::TEXTRANGE_CARETPOSITION:
 
230
      default:
 
231
           return nsISelectionController::SELECTION_NORMAL;
 
232
   };
 
233
}
 
234
 
 
235
NS_IMETHODIMP IMETextTxn::GetData(nsString& aResult,nsIPrivateTextRangeList** aTextRangeList)
 
236
{
 
237
  NS_ASSERTION(aTextRangeList, "illegal value- null ptr- aTextRangeList");
 
238
  if (!aTextRangeList)
 
239
    return NS_ERROR_NULL_POINTER;
 
240
  aResult = mStringToInsert;
 
241
  *aTextRangeList = mRangeList;
 
242
  return NS_OK;
 
243
}
 
244
 
 
245
static SelectionType sel[4]=
 
246
{
 
247
  nsISelectionController::SELECTION_IME_RAWINPUT,
 
248
  nsISelectionController::SELECTION_IME_SELECTEDRAWTEXT,
 
249
  nsISelectionController::SELECTION_IME_CONVERTEDTEXT,
 
250
  nsISelectionController::SELECTION_IME_SELECTEDCONVERTEDTEXT
 
251
};
 
252
 
 
253
NS_IMETHODIMP IMETextTxn::CollapseTextSelection(void)
 
254
{
 
255
    nsresult      result;
 
256
    PRUint16      i;
 
257
 
 
258
#ifdef DEBUG_IMETXN
 
259
    PRUint16 listlen,start,stop,type;
 
260
    result = mRangeList->GetLength(&listlen);
 
261
    printf("nsIPrivateTextRangeList[%p]\n",mRangeList);
 
262
    nsIPrivateTextRange* rangePtr;
 
263
    for (i=0;i<listlen;i++) {
 
264
      (void)mRangeList->Item(i,&rangePtr);
 
265
      rangePtr->GetRangeStart(&start);
 
266
      rangePtr->GetRangeEnd(&stop);
 
267
      rangePtr->GetRangeType(&type);
 
268
      printf("range[%d] start=%d end=%d type=",i,start,stop,type);
 
269
      if (type==nsIPrivateTextRange::TEXTRANGE_RAWINPUT)
 
270
                             printf("TEXTRANGE_RAWINPUT\n");
 
271
      else if (type==nsIPrivateTextRange::TEXTRANGE_SELECTEDRAWTEXT)
 
272
                                  printf("TEXTRANGE_SELECTEDRAWTEXT\n");
 
273
      else if (type==nsIPrivateTextRange::TEXTRANGE_CONVERTEDTEXT)
 
274
                                  printf("TEXTRANGE_CONVERTEDTEXT\n");
 
275
      else if (type==nsIPrivateTextRange::TEXTRANGE_SELECTEDCONVERTEDTEXT)
 
276
                                  printf("TEXTRANGE_SELECTEDCONVERTEDTEXT\n");
 
277
      else if (type==nsIPrivateTextRange::TEXTRANGE_CARETPOSITION)
 
278
                                  printf("TEXTRANGE_CARETPOSITION\n");
 
279
      else printf("unknown constant\n");
 
280
    }
 
281
#endif
 
282
        
 
283
    //
 
284
    // run through the text range list, if any
 
285
    //
 
286
    nsCOMPtr<nsISelectionController> selCon = do_QueryReferent(mSelConWeak);
 
287
    if (!selCon) return NS_ERROR_NOT_INITIALIZED;
 
288
 
 
289
    PRUint16      textRangeListLength,selectionStart,selectionEnd,
 
290
                  textRangeType;
 
291
    
 
292
    result = mRangeList->GetLength(&textRangeListLength);
 
293
    if(NS_FAILED(result))
 
294
        return result;
 
295
    nsCOMPtr<nsISelection> selection;
 
296
    result = selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(selection));
 
297
    if(NS_SUCCEEDED(result))
 
298
    {
 
299
      nsCOMPtr<nsISelectionPrivate> selPriv(do_QueryInterface(selection));
 
300
      result = selPriv->StartBatchChanges();
 
301
      if (NS_SUCCEEDED(result))
 
302
      {
 
303
        nsCOMPtr<nsISelection> imeSel;
 
304
        for(PRInt8 selIdx = 0; selIdx < 4;selIdx++)
 
305
        {
 
306
          result = selCon->GetSelection(sel[selIdx], getter_AddRefs(imeSel));
 
307
          if (NS_SUCCEEDED(result))
 
308
          {
 
309
            result = imeSel->RemoveAllRanges();
 
310
            NS_ASSERTION(NS_SUCCEEDED(result), "Cannot ClearSelection");
 
311
            // we just ignore the result and clean up the next one here
 
312
          }
 
313
        }
 
314
 
 
315
        nsIPrivateTextRange*  textRange;
 
316
        PRBool setCaret=PR_FALSE;
 
317
        for(i=0;i<textRangeListLength;i++)
 
318
        {
 
319
          result = mRangeList->Item(i,&textRange);
 
320
          NS_ASSERTION(NS_SUCCEEDED(result), "cannot get item");
 
321
          if(NS_FAILED(result))
 
322
               break;
 
323
 
 
324
          result = textRange->GetRangeType(&textRangeType);
 
325
          NS_ASSERTION(NS_SUCCEEDED(result), "cannot get range type");
 
326
          if(NS_FAILED(result))
 
327
               break;
 
328
 
 
329
          result = textRange->GetRangeStart(&selectionStart);
 
330
          NS_ASSERTION(NS_SUCCEEDED(result), "cannot get range start");
 
331
          if(NS_FAILED(result))
 
332
               break;
 
333
          result = textRange->GetRangeEnd(&selectionEnd);
 
334
          NS_ASSERTION(NS_SUCCEEDED(result), "cannot get range end");
 
335
          if(NS_FAILED(result))
 
336
               break;
 
337
 
 
338
          if(nsIPrivateTextRange::TEXTRANGE_CARETPOSITION == textRangeType)
 
339
          {
 
340
             // Set the caret....
 
341
             result = selection->Collapse(mElement,
 
342
                      mOffset+selectionStart);
 
343
             NS_ASSERTION(NS_SUCCEEDED(result), "Cannot Collapse");
 
344
             if(NS_SUCCEEDED(result))
 
345
             setCaret = PR_TRUE;
 
346
          } else {
 
347
             // NS_ASSERTION(selectionStart != selectionEnd, "end == start");
 
348
             if(selectionStart == selectionEnd)
 
349
                continue;
 
350
 
 
351
             result= selCon->GetSelection(TextRangeToSelection(textRangeType),
 
352
                     getter_AddRefs(imeSel));
 
353
             NS_ASSERTION(NS_SUCCEEDED(result), "Cannot get selction");
 
354
             if(NS_FAILED(result))
 
355
                break;
 
356
 
 
357
             nsCOMPtr<nsIDOMRange> newRange = do_CreateInstance(
 
358
                                      "@mozilla.org/content/range;1", &result);
 
359
             NS_ASSERTION(NS_SUCCEEDED(result), "Cannot create new nsIDOMRange");
 
360
             if(NS_FAILED(result))
 
361
                break;
 
362
 
 
363
             newRange->SetStart(mElement,mOffset+selectionStart);
 
364
             NS_ASSERTION(NS_SUCCEEDED(result), "Cannot SetStart");
 
365
             if(NS_FAILED(result))
 
366
                break;
 
367
 
 
368
             newRange->SetEnd(mElement,mOffset+selectionEnd);
 
369
             NS_ASSERTION(NS_SUCCEEDED(result), "Cannot SetEnd");
 
370
             if(NS_FAILED(result))
 
371
                break;
 
372
 
 
373
             imeSel->AddRange(newRange);
 
374
             NS_ASSERTION(NS_SUCCEEDED(result), "Cannot AddRange");
 
375
             if(NS_FAILED(result))
 
376
                break;
 
377
 
 
378
          } // if GetRangeEnd
 
379
        } // for textRangeListLength
 
380
        if(! setCaret) {
 
381
          // set cursor
 
382
          result = selection->Collapse(mElement,mOffset+mStringToInsert.Length());
 
383
          NS_ASSERTION(NS_SUCCEEDED(result), "Cannot Collapse");
 
384
        }
 
385
        result = selPriv->EndBatchChanges();
 
386
        NS_ASSERTION(NS_SUCCEEDED(result), "Cannot EndBatchChanges");
 
387
      } // if StartBatchChanges
 
388
    } // if GetSelection
 
389
 
 
390
    return result;
 
391
}
 
392