Back to index

lightning-sunbird  0.9+nobinonly
TypeInState.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Pierre Phaneuf <pp@ludusdesign.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 
00040 #include "TypeInState.h"
00041 #include "nsEditor.h"
00042 
00043 /********************************************************************
00044  *                     XPCOM cruft 
00045  *******************************************************************/
00046 
00047 NS_IMPL_ISUPPORTS1(TypeInState, nsISelectionListener)
00048 
00049 /********************************************************************
00050  *                   public methods
00051  *******************************************************************/
00052  
00053 TypeInState::TypeInState() :
00054  mSetArray()
00055 ,mClearedArray()
00056 ,mRelativeFontSize(0)
00057 ,mLastSelectionOffset(0)
00058 {
00059   Reset();
00060 }
00061 
00062 TypeInState::~TypeInState()
00063 {
00064   // Call Reset() to release any data that may be in
00065   // mClearedArray and mSetArray.
00066 
00067   Reset();
00068 }
00069 
00070 nsresult TypeInState::UpdateSelState(nsISelection *aSelection)
00071 {
00072   if (!aSelection) return NS_ERROR_NULL_POINTER;
00073   
00074   PRBool isCollapsed = PR_FALSE;
00075   nsresult result = aSelection->GetIsCollapsed(&isCollapsed);
00076 
00077   if (NS_FAILED(result)) return result;
00078 
00079   if (isCollapsed)
00080   {
00081     result = nsEditor::GetStartNodeAndOffset(aSelection, address_of(mLastSelectionContainer), &mLastSelectionOffset);
00082   }
00083   return result;
00084 }
00085 
00086 
00087 NS_IMETHODIMP TypeInState::NotifySelectionChanged(nsIDOMDocument *, nsISelection *aSelection, PRInt16)
00088 {
00089   // XXX: Selection currently generates bogus selection changed notifications
00090   // XXX: (bug 140303). It can notify us when the selection hasn't actually
00091   // XXX: changed, and it notifies us more than once for the same change.
00092   // XXX:
00093   // XXX: The following code attempts to work around the bogus notifications,
00094   // XXX: and should probably be removed once bug 140303 is fixed.
00095   // XXX:
00096   // XXX: This code temporarily fixes the problem where clicking the mouse in
00097   // XXX: the same location clears the type-in-state.
00098 
00099   if (aSelection)
00100   {
00101     PRBool isCollapsed = PR_FALSE;
00102     nsresult result = aSelection->GetIsCollapsed(&isCollapsed);
00103 
00104     if (NS_FAILED(result)) return result;
00105 
00106     if (isCollapsed)
00107     {
00108       nsCOMPtr<nsIDOMNode> selNode;
00109       PRInt32 selOffset = 0;
00110 
00111       result = nsEditor::GetStartNodeAndOffset(aSelection, address_of(selNode), &selOffset);
00112 
00113       if (NS_FAILED(result)) return result;
00114 
00115       if (selNode && selNode == mLastSelectionContainer && selOffset == mLastSelectionOffset)
00116       {
00117         // We got a bogus selection changed notification!
00118         return NS_OK;
00119       }
00120 
00121       mLastSelectionContainer = selNode;
00122       mLastSelectionOffset = selOffset;
00123     }
00124     else
00125     {
00126       mLastSelectionContainer = nsnull;
00127       mLastSelectionOffset = 0;
00128     }
00129   }
00130 
00131   Reset(); 
00132   return NS_OK;
00133 }
00134 
00135 void TypeInState::Reset()
00136 {
00137   PRInt32 count;
00138   PropItem *propItemPtr;
00139   
00140   while ((count = mClearedArray.Count()))
00141   {
00142     // go backwards to keep nsVoidArray from memmoving everything each time
00143     count--; // nsVoidArray is zero based
00144     propItemPtr = (PropItem*)mClearedArray.ElementAt(count);
00145     mClearedArray.RemoveElementAt(count);
00146     if (propItemPtr) delete propItemPtr;
00147   }
00148   while ((count = mSetArray.Count()))
00149   {
00150     // go backwards to keep nsVoidArray from memmoving everything each time
00151     count--; // nsVoidArray is zero based
00152     propItemPtr = (PropItem*)mSetArray.ElementAt(count);
00153     mSetArray.RemoveElementAt(count);
00154     if (propItemPtr) delete propItemPtr;
00155   }
00156 }
00157 
00158 
00159 nsresult TypeInState::SetProp(nsIAtom *aProp)
00160 {
00161   return SetProp(aProp,EmptyString(),EmptyString());
00162 }
00163 
00164 nsresult TypeInState::SetProp(nsIAtom *aProp, const nsString &aAttr)
00165 {
00166   return SetProp(aProp,aAttr,EmptyString());
00167 }
00168 
00169 nsresult TypeInState::SetProp(nsIAtom *aProp, const nsString &aAttr, const nsString &aValue)
00170 {
00171   // special case for big/small, these nest
00172   if (nsEditProperty::big == aProp)
00173   {
00174     mRelativeFontSize++;
00175     return NS_OK;
00176   }
00177   if (nsEditProperty::small == aProp)
00178   {
00179     mRelativeFontSize--;
00180     return NS_OK;
00181   }
00182 
00183   PRInt32 index;
00184   PropItem *item;
00185 
00186   if (IsPropSet(aProp,aAttr,nsnull,index))
00187   {
00188     // if it's already set, update the value
00189     item = (PropItem*)mSetArray[index];
00190     item->value = aValue;
00191   }
00192   else 
00193   {
00194     // make a new propitem
00195     item = new PropItem(aProp,aAttr,aValue);
00196     if (!item) return NS_ERROR_OUT_OF_MEMORY;
00197     
00198     // add it to the list of set properties
00199     mSetArray.AppendElement((void*)item);
00200     
00201     // remove it from the list of cleared properties, if we have a match
00202     RemovePropFromClearedList(aProp,aAttr);  
00203   }
00204     
00205   return NS_OK;
00206 }
00207 
00208 
00209 nsresult TypeInState::ClearAllProps()
00210 {
00211   // null prop means "all" props
00212   return ClearProp(nsnull,EmptyString());
00213 }
00214 
00215 nsresult TypeInState::ClearProp(nsIAtom *aProp)
00216 {
00217   return ClearProp(aProp,EmptyString());
00218 }
00219 
00220 nsresult TypeInState::ClearProp(nsIAtom *aProp, const nsString &aAttr)
00221 {
00222   // if it's already cleared we are done
00223   if (IsPropCleared(aProp,aAttr)) return NS_OK;
00224   
00225   // make a new propitem
00226   PropItem *item = new PropItem(aProp,aAttr,EmptyString());
00227   if (!item) return NS_ERROR_OUT_OF_MEMORY;
00228   
00229   // remove it from the list of set properties, if we have a match
00230   RemovePropFromSetList(aProp,aAttr);
00231   
00232   // add it to the list of cleared properties
00233   mClearedArray.AppendElement((void*)item);
00234   
00235   return NS_OK;
00236 }
00237 
00238 
00239 /***************************************************************************
00240  *    TakeClearProperty: hands back next property item on the clear list.
00241  *                       caller assumes ownership of PropItem and must delete it.
00242  */  
00243 nsresult TypeInState::TakeClearProperty(PropItem **outPropItem)
00244 {
00245   if (!outPropItem) return NS_ERROR_NULL_POINTER;
00246   *outPropItem = nsnull;
00247   PRInt32 count = mClearedArray.Count();
00248   if (count) // go backwards to keep nsVoidArray from memmoving everything each time
00249   {
00250     count--; // nsVoidArray is zero based
00251     *outPropItem = (PropItem*)mClearedArray[count];
00252     mClearedArray.RemoveElementAt(count);
00253   }
00254   return NS_OK;
00255 }
00256 
00257 /***************************************************************************
00258  *    TakeSetProperty: hands back next poroperty item on the set list.
00259  *                     caller assumes ownership of PropItem and must delete it.
00260  */  
00261 nsresult TypeInState::TakeSetProperty(PropItem **outPropItem)
00262 {
00263   if (!outPropItem) return NS_ERROR_NULL_POINTER;
00264   *outPropItem = nsnull;
00265   PRInt32 count = mSetArray.Count();
00266   if (count) // go backwards to keep nsVoidArray from memmoving everything each time
00267   {
00268     count--; // nsVoidArray is zero based
00269     *outPropItem = (PropItem*)mSetArray[count];
00270     mSetArray.RemoveElementAt(count);
00271   }
00272   return NS_OK;
00273 }
00274 
00275 //**************************************************************************
00276 //    TakeRelativeFontSize: hands back relative font value, which is then
00277 //                          cleared out.
00278 nsresult TypeInState::TakeRelativeFontSize(PRInt32 *outRelSize)
00279 {
00280   if (!outRelSize) return NS_ERROR_NULL_POINTER;
00281   *outRelSize = mRelativeFontSize;
00282   mRelativeFontSize = 0;
00283   return NS_OK;
00284 }
00285 
00286 nsresult TypeInState::GetTypingState(PRBool &isSet, PRBool &theSetting, nsIAtom *aProp)
00287 {
00288   return GetTypingState(isSet, theSetting, aProp, EmptyString(), nsnull);
00289 }
00290 
00291 nsresult TypeInState::GetTypingState(PRBool &isSet, 
00292                                      PRBool &theSetting, 
00293                                      nsIAtom *aProp, 
00294                                      const nsString &aAttr)
00295 {
00296   return GetTypingState(isSet, theSetting, aProp, aAttr, nsnull);
00297 }
00298 
00299 
00300 nsresult TypeInState::GetTypingState(PRBool &isSet, 
00301                                      PRBool &theSetting, 
00302                                      nsIAtom *aProp,
00303                                      const nsString &aAttr, 
00304                                      nsString *aValue)
00305 {
00306   if (IsPropSet(aProp, aAttr, aValue))
00307   {
00308     isSet = PR_TRUE;
00309     theSetting = PR_TRUE;
00310   }
00311   else if (IsPropCleared(aProp, aAttr))
00312   {
00313     isSet = PR_TRUE;
00314     theSetting = PR_FALSE;
00315   }
00316   else
00317   {
00318     isSet = PR_FALSE;
00319   }
00320   return NS_OK;
00321 }
00322 
00323 
00324 
00325 /********************************************************************
00326  *                   protected methods
00327  *******************************************************************/
00328  
00329 nsresult TypeInState::RemovePropFromSetList(nsIAtom *aProp, 
00330                                             const nsString &aAttr)
00331 {
00332   PRInt32 index;
00333   PropItem *item;
00334   if (!aProp)
00335   {
00336     // clear _all_ props
00337     mRelativeFontSize=0;
00338     while ((index = mSetArray.Count()))
00339     {
00340       // go backwards to keep nsVoidArray from memmoving everything each time
00341       index--; // nsVoidArray is zero based
00342       item = (PropItem*)mSetArray.ElementAt(index);
00343       mSetArray.RemoveElementAt(index);
00344       if (item) delete item;
00345     }
00346   }
00347   else if (FindPropInList(aProp, aAttr, nsnull, mSetArray, index))
00348   {
00349     item = (PropItem*)mSetArray.ElementAt(index);
00350     mSetArray.RemoveElementAt(index);
00351     if (item) delete item;
00352   }
00353   return NS_OK;
00354 }
00355 
00356 
00357 nsresult TypeInState::RemovePropFromClearedList(nsIAtom *aProp, 
00358                                             const nsString &aAttr)
00359 {
00360   PRInt32 index;
00361   if (FindPropInList(aProp, aAttr, nsnull, mClearedArray, index))
00362   {
00363     PropItem *item = (PropItem*)mClearedArray.ElementAt(index);
00364     mClearedArray.RemoveElementAt(index);
00365     if (item) delete item;
00366   }
00367   return NS_OK;
00368 }
00369 
00370 
00371 PRBool TypeInState::IsPropSet(nsIAtom *aProp, 
00372                               const nsString &aAttr,
00373                               nsString* outValue)
00374 {
00375   PRInt32 i;
00376   return IsPropSet(aProp, aAttr, outValue, i);
00377 }
00378 
00379 
00380 PRBool TypeInState::IsPropSet(nsIAtom *aProp, 
00381                               const nsString &aAttr,
00382                               nsString *outValue,
00383                               PRInt32 &outIndex)
00384 {
00385   // linear search.  list should be short.
00386   PRInt32 i, count = mSetArray.Count();
00387   for (i=0; i<count; i++)
00388   {
00389     PropItem *item = (PropItem*)mSetArray[i];
00390     if ( (item->tag == aProp) &&
00391          (item->attr == aAttr) )
00392     {
00393       if (outValue) *outValue = item->value;
00394       outIndex = i;
00395       return PR_TRUE;
00396     }
00397   }
00398   return PR_FALSE;
00399 }
00400 
00401 
00402 PRBool TypeInState::IsPropCleared(nsIAtom *aProp, 
00403                                   const nsString &aAttr)
00404 {
00405   PRInt32 i;
00406   return IsPropCleared(aProp, aAttr, i);
00407 }
00408 
00409 
00410 PRBool TypeInState::IsPropCleared(nsIAtom *aProp, 
00411                                   const nsString &aAttr,
00412                                   PRInt32 &outIndex)
00413 {
00414   if (FindPropInList(aProp, aAttr, nsnull, mClearedArray, outIndex))
00415     return PR_TRUE;
00416   if (FindPropInList(0, EmptyString(), nsnull, mClearedArray, outIndex))
00417   {
00418     // special case for all props cleared
00419     outIndex = -1;
00420     return PR_TRUE;
00421   }
00422   return PR_FALSE;
00423 }
00424 
00425 PRBool TypeInState::FindPropInList(nsIAtom *aProp, 
00426                                    const nsAString &aAttr,
00427                                    nsAString *outValue,
00428                                    nsVoidArray &aList,
00429                                    PRInt32 &outIndex)
00430 {
00431   // linear search.  list should be short.
00432   PRInt32 i, count = aList.Count();
00433   for (i=0; i<count; i++)
00434   {
00435     PropItem *item = (PropItem*)aList[i];
00436     if ( (item->tag == aProp) &&
00437          (item->attr == aAttr) ) 
00438     {
00439       if (outValue) *outValue = item->value;
00440       outIndex = i;
00441       return PR_TRUE;
00442     }
00443   }
00444   return PR_FALSE;
00445 }
00446 
00447 
00448 
00449 /********************************************************************
00450  *    PropItem: helper struct for TypeInState
00451  *******************************************************************/
00452 
00453 PropItem::PropItem(nsIAtom *aTag, const nsAString &aAttr, const nsAString &aValue) :
00454  tag(aTag)
00455 ,attr(aAttr)
00456 ,value(aValue)
00457 {
00458 }
00459 
00460 PropItem::~PropItem()
00461 {
00462 }