Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

Element.cpp

Go to the documentation of this file.
00001 
00002 // MathCore = a WYSIWYG equation editor + a powerful math engine     //
00003 // Copyright (C) 2003 by Francesco Montorsi                          //
00004 //                                                                   //
00005 // This library is free software; you can redistribute it and/or     //
00006 // modify it under the terms of the GNU Lesser General Public        //
00007 // License as published by the Free Software Foundation; either      //
00008 // version 2.1 of the License, or (at your option) any later         //
00009 // version.                                                          //
00010 //                                                                   //
00011 // This library is distributed in the hope that it will be useful,   //
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of    //
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the      //
00014 // GNU Lesser General Public License for more details.               //
00015 //                                                                   //
00016 // You should have received a copy of the GNU Lesser General Public  //
00017 // License along with this program; if not, write to the Free        //
00018 // Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,   //
00019 // MA 02111-1307, USA.                                               //
00020 //                                                                   //
00021 // For any comment, suggestion or feature request, please contact    //
00022 // the administrator of the project at frm@users.sourceforge.net     //
00023 //                                                                   //
00031 
00032 
00033 
00034 // optimization for GCC compiler
00035 #ifdef __GNUG__
00036 #pragma implementation "Element.cpp"
00037 #endif
00038 
00039 // includes
00040 #include "mc/mcprec.h"
00041 #ifdef __BORLANDC__
00042     #pragma hdrstop
00043 #endif
00044 
00045 #ifndef mcPRECOMP
00046     #include <wx/dcscreen.h>
00047 
00048  #include "mc/EmptyBox.h"
00049  #include "mc/Number.h"
00050  #include "mc/Bracket.h"
00051  #include "mc/Fraction.h"
00052  #include "mc/Function.h"
00053  #include "mc/Radical.h"
00054  #include "mc/Text.h"
00055  #include "mc/Symbol.h"
00056  #include "mc/Operator.h"
00057  #include "mc/AddSubOp.h" 
00058  #include "mc/MultDivOp.h" 
00059  #include "mc/Monomial.h"
00060  #include "mc/Parenthesis.h"
00061 #endif
00062 
00063 
00064 // setup customizable variables
00065 wxBrush *mcElementHelpers::sgui_pSelectionBrush = NULL;
00066 wxBrush *mcElementHelpers::sgui_pActivationBrush = NULL;
00067 mcStyleArray *mcElementHelpers::sgui_pDefaultStyles = NULL;
00068 int mcElementHelpers::sgui_nAdditionalActivationSpaceLeftRight = 2;
00069 mcElement *mcElementHelpers::sdata_pElem[];
00070 
00071 // global objects
00072 mcElement mcEmptyElement;
00073 
00074 
00075 
00076 
00077 
00078 // -------------------------
00079 // mcELEMENTHELPERS
00080 // -------------------------
00081 
00082 #ifdef __MCDEBUG__
00083 
00084 void mcElementHelpers::data_Check() const
00085 {
00086  //mcASSERT(m_nExpDepth >= 0, "Not valid");
00087  mcASSERT(mdata_nProperties >= 0, wxT("Not valid"));
00088  mcASSERT(mdata_nID >= 0, wxT("Not valid"));
00089 
00090  // now check childrens (recursive check)...
00091  for (int i=0,max=data_GetChildrenCount(); i < max; i++) {
00092 
00093   const mcElement &tocheck = data_GetConstChild(i);
00094 
00095   // be sure that this child has set this element as its parent
00096   /*mcASSERT(tocheck.GetParent() == this, 
00097    wxT("One of our children is out of sync"));*/
00098 
00099   // recurse
00100   tocheck.data_Check();
00101  }
00102 }
00103 
00104 wxString mcElementHelpers::data_GetDebug(int indent, long flags) const
00105 {
00106  wxString str, tmp;
00107 
00108  // get debug info from this element
00109  //tmp = data_Debug();
00110  //tmp = Indent(tmp, indent); // indent it
00111 
00112  // leave some spaces
00113  str += wxString(wxT(' '), indent);
00114 
00115  // include some additional info if required
00116  if (flags & mcELEMENT_DBG_EXPDEPTH)
00117   str += wxString::Format(wxT("EXPDEPTH: %2d  "), gui_GetExpDepth());
00118 
00119  if (flags & mcELEMENT_DBG_SELECTION &&
00120   mcMathCore::Get()->isGUIEnabled())
00121   str += wxString::Format(wxT("SELECTED: %s  "), 
00122     (gui_isSelected() ? wxT("YES") : wxT("NO ")));
00123 
00124  if (flags & mcELEMENT_DBG_ID)
00125   str += wxString::Format(wxT("ID: %2d  "), data_GetID());
00126 
00127  // add the string
00128  str += data_Debug(flags);
00129  str = wxIndent(str, indent);
00130 
00131  // return the result 
00132  return str;
00133 }
00134 
00135 void mcElement::data_CheckContainer() const
00136 {
00137  // first of all, check if this is a valid container for the
00138  // current shared data
00139  if (data_GetRefData()) {
00140   mcElementHelpers *helpers = (mcElementHelpers *)data_GetRefData();
00141   mcUNUSED(helpers);  // just to avoid a stupid warning
00142  
00143   // we cannot mix helpers of some type with elements of another
00144   // type: mcNumber cannot reference a mcBracketHelper class...
00145   mcASSERT(data_isValidContainerFor(helpers->data_GetType()), 
00146    wxT("Invalid container (this is a ") +
00147    data_GetDebugName() + 
00148    wxT(") for the given helper class (") + 
00149    helpers->data_GetDebugName() +
00150    wxT("Helpers) !!"));
00151  }
00152 }
00153 
00154 void mcElement::data_Check() const
00155 {
00156  // check if we contain valid data
00157  data_CheckContainer();
00158 
00159  // then, check the helper (if present) & its children
00160  if (chlp()) chlp()->data_Check();
00161 }
00162 
00163 #endif  // __MCDEBUG__
00164 
00165 
00166 mcElementHelpers::mcElementHelpers()
00167 {
00168  // this variable should be decided by derived classes
00169  //mdata_nType = mcET_INVALID;
00170  
00171  // create the ID for this element
00172  mdata_nID = mcElementHelpers::data_GenID();
00173  
00174  // set up flags and member variables
00175  mdata_nProperties = mcEP_NOPROPERTIES;
00176  mgui_nExpDepth = 0;
00177 }
00178 
00179 void mcElementHelpers::data_Init()
00180 {
00181  // init only required sections
00182  if (mcMathCore::Get()->isGUIEnabled()) gui_Init();
00183  if (mcMathCore::Get()->isMathEnabled()) math_Init();
00184  if (mcMathCore::Get()->isIOEnabled()) io_Init();
00185 }
00186 
00187 bool mcElementHelpers::io_Init(const wxString &str)
00188 {
00189  wxString err;
00190  int n;
00191  
00192  // just check the string begins with the begin-char for this class
00193  if (!mcMathCore::Get()->isIOEnabled())
00194   return FALSE;
00195  if (io_isBeginChar(str) == FALSE)
00196   return FALSE;
00197  return io_ImportInlinedExpr(str, &n, err);
00198 }
00199 
00200 void mcElementHelpers::gui_OnRecalcSize(wxSize old)
00201 {
00202  // if there were no changes, do nothing...
00203  if (old == mgui_sz)
00204   return;
00205  
00206  // if this object's size has changed, notify children 
00207  // with the correct properties...
00208  //for (int i=0; i < data_GetChildrenCount(); i++)
00209  // data_GetChild(i).gui_OnParentSizeChange();
00210 } 
00211 
00212 void mcElementHelpers::gui_SetStyleArray(const mcStyleArray *p)
00213 {
00214  // change the style for this class
00215  if (!mcMathCore::Get()->isGUIEnabled())
00216   return;
00217  
00218  mgui_pStyleArray = p;
00219  
00220  // and its children...
00221  for (int i=0; i < data_GetChildrenCount(); i++)
00222   data_GetChild(i).gui_SetStyleArray(p);
00223 }
00224 
00225 mcElement &mcElementHelpers::data_GetElemFromID(int id) const 
00226 {
00227  // do not check for ourselves (since this is a CONST function)
00228  
00229  // search among children
00230  for (int i=0; i < data_GetChildrenCount(); i++) {
00231   mcElement &p = data_GetConstChild(i).data_GetElemFromID(id);
00232   if (p != mcEmptyElement)
00233    return p;
00234  }
00235  
00236  return mcEmptyElement;
00237 }
00238 
00239 
00240 void mcElementHelpers::data_AddRecursiveProperty(mcElementType t, int p, void *val1, void *val2)
00241 {
00242  if (data_GetType() == t)
00243   data_AddProperty(p, val1, val2);
00244  
00245  // add this property to all the childrens...
00246  for (int i=0; i < data_GetChildrenCount(); i++)
00247   data_GetChild(i).data_AddRecursiveProperty(t, p, val1, val2);
00248 }
00249 
00250 bool mcElementHelpers::data_hasRecursiveProperty(mcElementType t, int p) const
00251 {
00252  if (data_GetType() == t)
00253   return ((mdata_nProperties & p) != 0);
00254  
00255  // check if at least one of the children has the property...
00256  for (int i=0; i < data_GetChildrenCount(); i++)
00257   if (data_GetConstChild(i).data_hasRecursiveProperty(t, p))
00258    return TRUE;
00259   return FALSE;
00260 }
00261 
00262 void mcElementHelpers::data_RemoveRecursiveProperty(mcElementType t, int p)
00263 {
00264  if (data_GetType() == t)
00265   mdata_nProperties &= ~p;
00266  
00267  // remove this property from all the childrens...
00268  for (int i=0; i < data_GetChildrenCount(); i++)
00269   data_GetChild(i).data_RemoveRecursiveProperty(t, p);
00270 }
00271 
00272 void mcElementHelpers::data_Update()
00273 {
00274  // nothing to do....
00275 
00276  // just update children
00277  for (int i=0; i < data_GetChildrenCount(); i++)
00278   data_GetChild(i).data_Update(); 
00279 }
00280 
00281 bool mcElementHelpers::data_AddChildrenTo(mcElement p)
00282 {
00283  if (p.data_GetType() != data_GetType())
00284   return FALSE;
00285   
00286  for (int i=0, max=data_GetChildrenCount(); i < max; i++)
00287   p.data_SetChild(i, data_GetChild(i));
00288  return TRUE; // non container elements should have no child to add...
00289 }
00290 
00291 int mcElementHelpers::data_GetChildIdx(const mcElement &p) const
00292 {  
00293  for (int i=0,max=data_GetChildrenCount(); i < max; i++)
00294   if (data_GetConstChild(i) == p)
00295    return i; // found...
00296   
00297  return -1;
00298 }
00299 
00300 mcElement &mcElementHelpers::data_GetChild(int n)
00301 { return (mcElement &)data_GetConstChild(n);}
00302 
00303 const mcElement &mcElementHelpers::data_GetConstChild(int) const
00304 { return mcEmptyElement;}
00305 
00306 
00307 
00308 
00309 
00310 // ----------------------------------------
00311 // mcELEMENT - various
00312 // ----------------------------------------
00313 
00314 mcElement::mcElement(const mcElementHelpers *helpers)
00315 { 
00316  //mcLOG("mcElementHelpers::mcElement - wrapping"); 
00317  data_SetRefData((mcObjectRefData *)helpers);
00318  
00319  // increment the reference count since we've now wrapped the given class
00320  if (data_GetRefData())
00321   data_GetRefData()->data_IncRefCount();
00322 #ifndef mcENABLE_COW
00323  if (data_GetRefData())
00324   data_MakePrivateCopy();  // no sharing allowed
00325 #endif
00326 }
00327 
00328 mcElement::~mcElement()
00329 { 
00330 #ifdef mcENABLE_COW_DEBUG
00331  if (data_GetRefData() && mcMathCore::isOk())
00332   mcMathCore::Get()->m_nMaxSharing = 
00333   mcMAX(mcMathCore::Get()->m_nMaxSharing, chlp()->data_GetRefCount());
00334 #endif
00335 }
00336 
00337 void mcElement::data_Ref(const mcObject &toclone)
00338 {
00339  mcObject::data_Ref(toclone);
00340 
00341  // check this is a valid container for the just
00342  // referenced data.... we can do it here because
00343  // this function is called when the element
00344  // has been completely built and thus, if present,
00345  // the overloaded version of CheckContainer will be
00346  // called...
00347 #ifdef __MCDEBUG__
00348  wxLogNull logNo;
00349  data_CheckContainer();
00350 #endif
00351 }
00352 
00353 void mcElementHelpers::Init()
00354 {
00355  for (int t=0; t < mcNUM_ELEMENT_TYPES; t++)
00356   sdata_pElem[t] = NULL;
00357 
00358  // this will create an instance for each registered MathCore element
00359  data_UpdateElemArray();
00360 }
00361 
00362 void mcElementHelpers::Cleanup()
00363 {  
00364  for (int t=0; t < mcNUM_ELEMENT_TYPES; t++)
00365   mcSAFE_DELETE(sdata_pElem[t]);
00366 }
00367 
00368 void mcElementHelpers::data_UpdateElemArray()
00369 {
00370  // create one instance of each class; required by the
00371  // mcElementHelpers::isCharBeginChar & mcElementHelpers::isTagBeginTag
00372  // functions...
00373  for (int t=0; t < mcNUM_ELEMENT_TYPES; t++) {
00374   mcSAFE_DELETE(sdata_pElem[t]);
00375 
00376   // if at least one of the mcElement sections is enabled,
00377   // build this element
00378   sdata_pElem[t] = new mcElement(data_NewElem((mcElementType)t));
00379  }
00380 }
00381 
00382 
00383 #define mcDEFINE_ALLOCATOR(x)       \
00384  if (towrap)           \
00385   return x(towrap);        \
00386  else            \
00387   return x(); 
00388 
00389 #define mcDEFINE_SPECIAL_ALLOCATOR(x, param1)   \
00390  if (towrap)           \
00391   return x(towrap);        \
00392  else            \
00393   return x(param1); 
00394 
00395 mcElement mcElementHelpers::data_NewElem(mcElementType type, const mcElementHelpers *towrap)
00396 {
00397  //mcElement pnew = mcEmptyElement;
00398 
00399  // create a new MathCore class; the following switch should contain
00400  // one case label for each value declared in mcElementType
00401  switch (type) {
00402  case mcET_NUMBER:
00403   mcDEFINE_ALLOCATOR(mcNumber)
00404  case mcET_PARENTHESIS:
00405   mcDEFINE_ALLOCATOR(mcParenthesis)
00406  case mcET_BRACKET:
00407   mcDEFINE_ALLOCATOR(mcBracket)
00408  case mcET_RADICAL:
00409   mcDEFINE_ALLOCATOR(mcRadical)
00410  case mcET_FRACTION:
00411   mcDEFINE_ALLOCATOR(mcFraction)
00412  case mcET_SYMBOL:
00413   mcDEFINE_ALLOCATOR(mcSymbol)
00414  case mcET_FUNCTION:
00415   mcDEFINE_ALLOCATOR(mcFunction)
00416  case mcET_TEXT:
00417   mcDEFINE_ALLOCATOR(mcText)
00418  case mcET_EMPTYBOX:
00419   mcDEFINE_ALLOCATOR(mcEmptyBox)
00420  case mcET_ADDOP:
00421   mcDEFINE_SPECIAL_ALLOCATOR(mcAddSubOp, mcET_ADDOP);
00422  case mcET_SUBOP:
00423   mcDEFINE_SPECIAL_ALLOCATOR(mcAddSubOp, mcET_SUBOP);
00424  case mcET_MULTOP:
00425   mcDEFINE_SPECIAL_ALLOCATOR(mcMultDivOp, mcET_MULTOP);
00426  case mcET_DIVOP:
00427   mcDEFINE_SPECIAL_ALLOCATOR(mcMultDivOp, mcET_DIVOP);
00428  case mcET_POLYNOMIAL:
00429   mcDEFINE_ALLOCATOR(mcPolynomial)
00430  case mcET_MONOMIAL:
00431   mcDEFINE_ALLOCATOR(mcMonomial)
00432  default:
00433   mcASSERT(0, wxT("The allocation of an undefined class was requested"));
00434  }
00435 
00436  return NULL;
00437 }
00438 
00439 // a macro used to avoid the repetion of specialized code in the
00440 // following functions
00441 #define SCAN_REGISTERED_CLASSES(fnc, params)     \
00442  /* for each MathCore registered element class */   \
00443  for (int i=0; i < mcNUM_ELEMENT_TYPES; i++) {  \
00444   if (sdata_pElem[i]->fnc(params) != FALSE) {    \
00445                 \
00446    /* found the class we were searching for */   \
00447    return (mcElementType)i;       \
00448   }              \
00449  }               \
00450                 \
00451  /* there is no class with that char as begin char */  \
00452  return mcET_INVALID;
00453 
00454 
00455 
00456 mcElementType mcElementHelpers::gui_isKeyBeginKey(const mcKey &key) {
00457  SCAN_REGISTERED_CLASSES(gui_isBeginKey, key);
00458 }
00459 
00460 mcElementType mcElementHelpers::io_isCharBeginChar(const wxString &str) {
00461  SCAN_REGISTERED_CLASSES(io_isBeginChar, str);
00462 }
00463 
00464 mcElementType mcElementHelpers::io_isTagBeginTag(const wxXml2Node &tag) {
00465  SCAN_REGISTERED_CLASSES(io_isBeginTag, tag);
00466 }
00467 
00468 wxString mcElementHelpers::data_GetGlobalMemoryInfo()
00469 {
00470  wxString res;
00471 
00472  for (int i=0; i < mcNUM_ELEMENT_TYPES; i++) {
00473 
00474   res += wxString::Format(wxT("Class number #%d: %d\n"), 
00475    i,//GetClassInfo()->GetClassName(),
00476    sdata_pElem[i]->data_GetMemoryInfo());
00477  }
00478 
00479  return res;
00480 }
00481 
00482 int mcElementHelpers::data_GenID(bool bFirstMember)
00483 {
00484  // use both time and random generator to compute our ID
00485  static int l=0, r=0xFFFF;
00486  if (bFirstMember)
00487   return l++;
00488  return r++;//(rand()+wxGetLocalTime())/rand();
00489 }
00490 
00491 mcObjectRefData *mcElement::data_MakePrivateCopy()  // implements COW
00492 {
00493  const mcElementHelpers *h = chlp();
00494 
00495  // if the mcElement-derived class we reference is owned only
00496  // by this mcElement, then we can just return it
00497  if (h->data_GetRefCount() == 1)
00498   return (mcElementHelpers *)h;
00499 
00500  // we need to unshare: unreference the old data
00501 #ifdef mcENABLE_COW_DEEPDEBUG
00502  mcLOG(wxT("mcElementHelpers::data_MakePrivateCopy"));
00503 #endif
00504  data_UnRef();
00505 
00506  // set as reference data a clone of current referenced data 
00507  data_SetRefData(h->data_Clone());
00508 
00509  // return our brand-new referenced data
00510  return (mcElementHelpers *)data_GetRefData(); 
00511 }
00512 
00513 void mcElementHelpers::gui_UpdateExpDepth()
00514 {
00515  // DO NOT UPDATE CHILDREN:
00516  //   for (int i=0; i < data_GetChildrenCount(); i++)
00517  //      data_GetChild(i).gui_UpdateExpDepth();
00518  // default implementation does nothing because it doesn't know
00519  // anything about the relationships between this object and
00520  // its children... plus, the overloaded versions of this function
00521  // should have already updated (maybe calling the #gui_SetAsExpOf
00522  // or #gui_SetAtSameLevelOf functions) the expdepth of our
00523  // children; so, also UPDATE IS NOT NECESSARY !
00524  
00525  // we can just recalc our size: all the exponent updates
00526  // should have been already done !!
00527  gui_RecalcSize();
00528 }
00529 
00530 /*
00531 void mcElementHelpers::SetExpDepth(int n)
00532 {
00533  hlp()->m_nExpDepth = n;
00534  
00535  // update derived class variables
00536  data_UpdateExpDepth();
00537  
00538  // size should be changed because the style is chosen
00539  // basing on exponent depth and, if exponent depth has
00540  // changed, also style has changed...
00541  // the following piece of code is used to avoid that
00542  // this function, called during the mcElement creation,
00543  // calls the pure virtual mcElement function #gui_RecalcSize()...
00544  // mcElement uses m_nType variable to check whether this
00545  // mcElement class has already been constructed.. so it's
00546  // essential to change the value of that variable as
00547  // the first thing in derived classes' constructors...
00548  if (data_GetType() != mcET_INVALID && mcMathCore::Get()->isGUIEnabled())
00549   gui_RecalcSize();
00550 }
00551 */
00552 
00553 
00554 
00555 
00556 
00557 
00558 // ----------------------------------------
00559 // mcELEMENTDATA
00560 // ----------------------------------------
00561 
00562 bool mcElementHelpers::data_isSameAs(const mcElementHelpers *p) const
00563 {
00564  bool b = TRUE;
00565 
00566  // The ID must *not* be checked...
00567  // b &= (mdata_nID == p->mdata_nID);
00568 
00569  // check basic data
00570  b &= (data_GetType() == p->data_GetType());
00571  b &= (mdata_nProperties == p->mdata_nProperties);
00572  if (!b) return FALSE;
00573 
00574  // check also the children, recursively
00575  for (int i=0; i < data_GetChildrenCount(); i++)
00576   if (!data_GetConstChild(i).data_isSameAs(p->data_GetConstChild(i)))
00577    return FALSE;
00578 
00579  return TRUE;
00580 }
00581 
00582 //bool mcElementHelpers::data_hasSameChildren(c
00583 
00584 void mcElementHelpers::data_DeepCopy(const mcElementHelpers *p)
00585 {
00586  // types should already be the same (anyway, we could not copy them, since 
00587  // they are not stored in mcElementHelpers)
00588  mcASSERT(data_GetType() == p->data_GetType(), wxT("Cannot perform deep copy !!"));
00589 
00590  // copy basic data (except for ID !)
00591  mdata_nProperties = p->mdata_nProperties;
00592  
00593  mgui_bSelected = p->mgui_bSelected;
00594  mgui_sz = p->mgui_sz;
00595  mgui_pStyleArray = p->mgui_pStyleArray;
00596  mgui_nExpDepth = p->mgui_nExpDepth;
00597 }
00598 
00599 
00600 
00601 
00602 
00603 
00604 // ----------------------------------------
00605 // mcELEMENTGUI
00606 // ----------------------------------------
00607 
00608 void mcElementHelpers::gui_Init() 
00609 {
00610  // mark the size as dirty: it will be recalculated as soon as
00611  // gui_GetSize() or directly gui_RecalcSize() is called
00612  mgui_sz.Set(-1, -1);
00613  
00614  // as default, the element is not selected
00615  mgui_bSelected = FALSE;
00616  
00617  // set the style array (if gui is enabled)...
00618  if (!mcMathCore::Get()->isGUIEnabled())
00619   return;
00620  
00621  // We cannot check our parent for a valid style since we are still
00622  // in mcElementGUI constructor (and accessing helper classes is
00623  // *not* allowed during construction), so we choose default styles, by now.
00624  // Anyway, our parent can call SyncStyleWithParent() once construction has been
00625  // completed...
00626  mcASSERT(sgui_pDefaultStyles != NULL,
00627   wxT("pDefaultStyles must always be a valid array !!!"));
00628  
00629  // the style array *must* always be valid: mcElementGUI holds a static
00630  // array of styles which is the default for ALL elements...
00631  mgui_pStyleArray = sgui_pDefaultStyles;
00632 
00633  gui_RecalcSize();
00634 }
00635 /*
00636 bool mcElementHelpers::gui_SyncStyleWithParent()
00637 {
00638  const mcStyleArray *old = mgui_pStyleArray;
00639 
00640  // climb the tree searching for a valid style...
00641  const mcElement &p = hlp()->GetConstParent();
00642  if (p) {
00643   
00644   // set this element's style to be the same of the parent's
00645   // NOTE: maybe that the caller of this constructor is
00646   //       a mcElementData-derived class: in this case,
00647   //       the parent GUI pointer could be not set yet...
00648   //       but we need to set the style anyway, so we go
00649   //       on searching for a valid GUI parent...
00650   while (p) {
00651   
00652    if (p.gui()) {
00653 
00654     // ok, we have found a valid pointer to a style array;
00655     // stop here; climbing further the tree is not useful...
00656     mgui_pStyleArray = p.gui_mgui_pStyleArray;
00657     if (mgui_pStyleArray)
00658      break;
00659    }
00660 
00661    // go up one level...
00662    p = p.GetConstParent();
00663   }
00664  }
00665  mcASSERT(0, wxT(""));
00666 
00667  // if current style is different from the old one which was set
00668  // at the beginning of this function, then we managed to find a
00669  // valid style among parent's styles...
00670  return (old != mgui_pStyleArray);
00671 }*/
00672 
00673 mcElement mcElementHelpers::gui_GetSelection() const
00674 {
00675  // return a copy of the element which is assumed to be entirely selected:
00676  // this should work for all non-container classes
00677  return mcElement(this);
00678 }
00679 
00680 mcElement &mcElementHelpers::gui_GetActiveElem(int x, int y, const wxPoint &pt) const
00681 {
00682  wxScreenDC tmp;
00683 
00684  // use the gui_Draw() function to do the most important part of the work... 
00685  int n = gui_Draw(tmp, x, y, mcDRW_USEPOINT, pt);
00686 
00687  // and then, just convert the result of the gui_Draw() call to an element
00688  // pointer using the mcElementHelpers::data_GetElemFromID()
00689  if (n != mcDRW_NOACTIVEELEM && n != mcDRW_ONSELECTION)
00690   return data_GetElemFromID(n);
00691  return mcEmptyElement;
00692 }
00693 
00694 void mcElementHelpers::gui_RecalcSize()
00695 {
00696  wxSize old = mgui_sz;
00697  gui_DoRecalcSize();
00698 
00699  // notify the element section...
00700  gui_OnRecalcSize(old);
00701 }
00702 
00703 void mcElementHelpers::gui_DeepRecalcSize()
00704 {
00705  mcGUILOG(wxT("mcElementHelpers::gui_DeepRecalcSize [%s]"), mcTXTTHIS);
00706 
00707  // recalc children sizes...
00708  for (int i=0; i < data_GetChildrenCount(); i++)
00709   data_GetChild(i).gui_DeepRecalcSize();
00710 
00711  // finally recalc also our size....
00712  gui_RecalcSize();
00713 }
00714 
00715 void mcElementHelpers::gui_SelectAll()
00716 {
00717  // select our children
00718  for (int i=0; i < data_GetChildrenCount(); i++)
00719   data_GetChild(i).gui_SelectAll();
00720 
00721  // select ourselves
00722  gui_Select();
00723 }
00724 
00725 void mcElementHelpers::gui_DeSelect()
00726 {
00727  // deselect children
00728  for (int i=0; i < data_GetChildrenCount(); i++)
00729   data_GetChild(i).gui_DeSelect();
00730 
00731  // change also our selection state !!!
00732  mgui_bSelected = FALSE;
00733 }
00734 
00735 bool mcElementHelpers::gui_isAllSelected() const
00736 {
00737  // are all our children selected ?
00738  for (int i=0; i < data_GetChildrenCount(); i++)
00739   if (!data_GetConstChild(i).gui_isAllSelected())
00740    return FALSE;
00741 
00742  // yes, they are... just check we are selected too...
00743  return gui_isSelected();
00744 }
00745 
00746 void mcElementHelpers::gui_DeleteSelection()
00747 {
00748  mcASSERT(!gui_isAllSelected(), 
00749   wxT("This element is completely selected: it should be removed by the caller"));
00750 
00751  // delete the selection inside our children
00752  for (int i=0; i < data_GetChildrenCount(); i++)
00753   data_GetChild(i).gui_DeleteSelection();
00754 
00755  // size should have changed...
00756  gui_RecalcSize();
00757 }
00758 
00759 
00760 
00761 
00762 
00763 // ----------------------------------------
00764 // mcELEMENTGUI - styles functions
00765 // ----------------------------------------
00766 
00767 void mcElementHelpers::gui_SetAsExpOf(const mcElement &p)
00768 {
00769  if (p != mcEmptyElement)
00770   mgui_nExpDepth = p.gui_GetExpDepth()+1;
00771 
00772  // update exponent depth of the children
00773  gui_UpdateExpDepth();
00774 }
00775 
00776 void mcElementHelpers::gui_SetAtSameLevelOf(const mcElement &p)
00777 {
00778  if (p != mcEmptyElement)
00779   mgui_nExpDepth = p.gui_GetExpDepth();
00780 
00781  // update exponent depth of the children
00782  gui_UpdateExpDepth();
00783 }
00784 
00785 void mcElementHelpers::gui_InitDefaultStyles()
00786 {
00787  mcGUILOG(wxT("mcElementHelpers::gui_InitDefaultStyles"));
00788 
00789  // remove the previous existing styles (if present)
00790  gui_DeleteDefaultStyles();
00791  
00792  // create the style array
00793  sgui_pDefaultStyles = new mcStyleArray();
00794  mcStyle *p = new mcStyle();
00795 
00796  // and init it
00797  for (int j=0; j < sgui_pDefaultStyles->GetCount(); j++) {
00798   
00799   
00800   // choose different facenames on different platforms
00801   //
00802   // VERY IMPORTANT: all the facenames should be chosen among
00803   //                 the facenames which are installed by default
00804   //                 on that plaftform. Otherwise a default (ugly)
00805   //                 font will be chosen...
00806   //
00807   // NOTE: these fontfaces are NOT the font faces you will see if
00808   //       your program is using MathGUI library: it automatically
00809   //       change them...
00810   //
00811 #if defined(__WXMSW__)
00812   
00813   
00814   wxString face1 = wxT("Lucida Sans Unicode");  //Trebuchet MS
00815   wxString face2 = wxT("Tahoma");
00816   wxString face3 = wxT("Verdana");
00817   const int size = 25;
00818   const int size2 = 20;
00819   /*wxString face1 = wxT("Times New Roman");  //Trebuchet MS
00820   wxString face2 = wxT("Tahoma");
00821   wxString face3 = wxT("Verdana");
00822   const int size = 12;
00823   const int size2 = 14;*/
00824   
00825 #else
00826   
00827   wxString face1 = wxT("Lucida");
00828   wxString face2 = wxT("Lucida");
00829   wxString face3 = wxT("Lucida");//"Helvetica";
00830   const int size = 25;
00831   const int size2 = 25;
00832   
00833 #endif
00834   
00835   // set up the font strings
00836   wxString num = wxString::Format(wxT("%d-%s-%d-%d-%d"), wxSWISS,
00837    face1.c_str(), size/(j+1), wxNORMAL, wxNORMAL);
00838   
00839   wxString fnc = wxString::Format(wxT("%d-%s-%d-%d-%d"), wxSWISS,
00840    face2.c_str(), size/(j+1), wxNORMAL, wxITALIC);
00841   
00842   wxString sym = wxString::Format(wxT("%d-%s-%d-%d-%d"), wxROMAN,
00843    face3.c_str(), size/(j+1), wxNORMAL, wxITALIC);
00844   
00845   wxString text = wxString::Format(wxT("%d-%s-%d-%d-%d"), wxSWISS,
00846    face2.c_str(), size2/(j+1), wxBOLD, wxNORMAL);
00847   
00848   wxString spec = wxString::Format(wxT("%d-%s-%d-%d-%d"), wxSWISS,
00849    wxT("MathStudio Special"), size/(j+1), wxBOLD, wxNORMAL);
00850   
00851   // sets the textsettings
00852   p->SetTextSettingsFor(mcET_NUMBER, mcINITWX(0xFF0000), *wxWHITE, num);
00853   p->SetTextSettingsFor(mcET_FUNCTION, mcINITWX(0x4080FF), *wxWHITE, fnc);
00854   p->SetTextSettingsFor(mcET_SYMBOL, mcINITWX(0x14A03C), *wxWHITE, sym);
00855   p->SetTextSettingsFor(mcET_TEXT, mcINITWX(0x329C7A), *wxWHITE, text);
00856   
00857   // mcET_ADDOP and all other operators use the same style, so we can
00858   // avoid to call SetTextSettingsFor(mcET_SUBOP, ....
00859   p->SetTextSettingsFor(mcET_ADDOP, mcINITWX(0x0), *wxWHITE, num);
00860   
00861   // these special settings are used to draw some special symbols...
00862   p->SetSpecialTextSettings(mcINITWX(0x0), *wxWHITE, spec);
00863   
00864   // be sure we built correctly everything
00865   mcASSERT(p->Ok(), wxT("Problems in style creation"));
00866   
00867   // store the style which has been just built
00868   sgui_pDefaultStyles->Set(p, j); // mcStyleArray::Set will *copy* the given style
00869  }
00870 
00871  // now, we can delete the temporary class we created to make
00872  // styles initialization easier...
00873  delete p;
00874 }
00875 
00876 double mcElementHelpers::gui_GetPointSize()
00877 {
00878  // pxperpoint contains the point size in pixels; this variable is
00879  // calculated only once, the first time it's required.
00880  static double pxperpoint = 0;
00881 
00882  if (pxperpoint == 0) {
00883 
00884   wxScreenDC dc;
00885 
00886   // get the same result we would obtain calling GetDeviceCaps(),
00887   // using cross platform functions
00888   dc.SetMapMode(wxMM_POINTS);
00889   pxperpoint = dc.LogicalToDeviceYRel(72);
00890  }
00891 
00892  return pxperpoint;
00893 }
00894 
00895 void mcElementHelpers::gui_DeleteDefaultStyles()
00896 {
00897  // this is an useful macro...
00898  mcSAFE_DELETE(sgui_pDefaultStyles);
00899 }
00900 
00901 double mcElementHelpers::gui_PointSize2Pixels(double pointsize)
00902 {
00903  // use the formula taken from Win32 Platform SDK under CreateFont help:
00904  // nHeight = -MulDiv(PointSize, GetDeviceCaps(hDC, LOGPIXELSY), 72);
00905  //
00906  // here, we do not use the MulDiv & GetDeviceCaps functions because
00907  // they are Win32-specific; we need cross-platformness ... :-)
00908  return (pointsize * gui_GetPointSize());
00909 }
00910 
00911 double mcElementHelpers::gui_Pixels2PointSize(double pixels)
00912 {
00913  // see #gui_PointSize2Pixels for more info about the formula used here
00914  return (72.0 * pixels / gui_GetPointSize());
00915 }
00916 
00917 int mcElementHelpers::gui_GetBaseOffsety(int exph) const
00918 {
00919  // force the exponent to overlap the base (only on y axis) by half the
00920  // height of a character in exp style
00921  return (int)((exph/100.0)*50.);
00922 }
00923 
00924 int mcElementHelpers::gui_GetSubscriptOffsety(int baseh) const
00925 {
00926  // force the exponent to overlap the base (only on y axis) by half the
00927  // height of a character in exp style
00928  return (int)((baseh/100.0)*60.);
00929 }
00930 
00931 const mcStyle *mcElementHelpers::gui_GetStyleForThis() const {
00932  // just to avoid the following line repeated one million times...
00933  return mgui_pStyleArray->gui_GetStyleFor(this);
00934 }
00935 
00936 const mcStyle *mcElementHelpers::gui_GetDefaultStyle(int n) {  // static
00937  return sgui_pDefaultStyles->Get(n);
00938 }
00939 
00940 const mcStyle *mcElementHelpers::gui_GetStyle(int n) const {
00941  // just to hide mgui_pStyleArray variable...
00942  return mgui_pStyleArray->Get(n);
00943 }
00944 /*
00945 void mcElementHelpers::gui_SetGlobalStyleArray(const mcStyleArray *p) {
00946  // just to hide mgui_pStyleArray variable...
00947  mgui_pStyleArray = p;
00948 }*/
00949 
00950 void mcElementHelpers::gui_SelectStyle(wxDC &hDC) const {
00951  const mcStyle *p = gui_GetStyleForThis();
00952 
00953  // in this function it doesn't make sense to use a
00954  // wxScreenDC to select the style; it would be destroyed
00955  // when this function returns and it could not be used
00956  mcASSERT(hDC.Ok(), wxT("Invalid DC"));
00957 
00958  // select text fg/bk colors basing on element type
00959  p->gui_Select(hDC, this);
00960 }
00961 
00962 int mcElementHelpers::gui_GetThickness(wxDC *dc) const {
00963  mcGUILOG(wxT("mcElementHelpers::gui_GetThickness"));
00964  bool bClean = FALSE;
00965 
00966  if (dc == NULL) {
00967   dc = new wxScreenDC();
00968   bClean = TRUE;
00969  }
00970 
00971  // select the style for the given element and retrieve its attributes
00972  gui_SelectStyle(*dc);
00973  int nWeight = dc->GetFont().GetWeight();
00974  int nHeight = dc->GetFont().GetPointSize();
00975 
00976  // clean up
00977  if (bClean)
00978   delete dc;
00979 
00980  // empirical formula; it works good with "normal" fonts such as
00981  // Tahoma, Times New Roman...
00982  return (int)(nWeight/527.5 + nHeight/12.8);
00983 }
00984 
00985 wxSize mcElementHelpers::gui_GetSizeOf(wxDC *hDC, const wxString &str) {
00986  mcGUILOG(wxT("mcElementHelpers::gui_GetSizeOf [%s]"), str.c_str());
00987  bool bClean=FALSE;
00988  int w=0, h=0;
00989  
00990  // if user doesn't provide a valid DC, use MathCore default one
00991  if (hDC == NULL) {
00992   hDC = new wxScreenDC();
00993   bClean = TRUE;
00994  }
00995 
00996  // if user provided an empty string, no problem
00997  if (str.IsEmpty()) return wxSize(0,0);
00998 
00999  // be sure to get right size
01000 #ifdef __WXGTK20__
01001  mcGUILOG(wxT("------------------ Using the buggy wxScreenDC function -----------------"));
01002  hDC->GetTextExtent(str, &w, &h);//, NULL, NULL, &current);
01003 #else
01004  hDC->GetTextExtent(str, &w, &h);
01005 #endif
01006  mcASSERT(w != 0 && h != 0, wxT("Cannot retrieve character size"));
01007 
01008  // clean up
01009  if (bClean)
01010   delete hDC; 
01011 
01012  // and return
01013  return wxSize(w, h);
01014 }
01015 
01016 int mcElementHelpers::gui_GetWidthOf(wxDC *h, const wxString &str) {
01017  return gui_GetSizeOf(h, str).GetWidth();
01018 }
01019 
01020 int mcElementHelpers::gui_GetHeightOf(wxDC *h, const wxString &str) {
01021  return gui_GetSizeOf(h, str).GetHeight();
01022 }
01023 
01024 wxSize mcElementHelpers::gui_GetSizeOfChar(wxDC *hDC, const mcElement &p) const {
01025  return wxSize(mcElementHelpers::gui_GetWidthOfChar(hDC, p),
01026       mcElementHelpers::gui_GetHeightOfChar(hDC, p));
01027 }
01028 
01029 int mcElementHelpers::gui_GetWidthOfChar(wxDC *hDC, const mcElement &p) const {
01030  mcGUILOG(wxT("mcElementHelpers::gui_GetWidthOfChar"));
01031  bool bClean=FALSE;
01032  int w;
01033 
01034  // if user doesn't provide a valid DC, use MathCore default one
01035  if (hDC == NULL) {
01036   hDC = new wxScreenDC();
01037   bClean = TRUE;
01038  }
01039 
01040  // if the given pointer is NULL, use the font which is
01041  // already selected in the DC
01042  if (p != NULL)
01043   p.gui_SelectStyle(*hDC);
01044 
01045  // be sure to get right size
01046  w = hDC->GetCharWidth();
01047  mcASSERT(w != 0, wxT("Cannot retrieve character size"));
01048 
01049  // clean up
01050  if (bClean)
01051   delete hDC;
01052 
01053  // and return
01054  return w;
01055 }
01056 
01057 int mcElementHelpers::gui_GetHeightOfChar(wxDC *hDC, const mcElement &p) const {
01058  mcGUILOG(wxT("mcElementHelpers::sgui_GetHeightOfChar"));
01059  bool bClean=FALSE;
01060  int h;
01061 
01062  // if user doesn't provide a valid DC, use MathCore default one
01063  if (hDC == NULL) {
01064   hDC = new wxScreenDC();
01065   bClean = TRUE;
01066  }
01067 
01068  // if the given pointer is NULL, use the font which is
01069  // already selected in the DC
01070  if (p != NULL)
01071   p.gui_SelectStyle(*hDC);
01072 
01073  // be sure to get right size
01074  h = hDC->GetCharHeight();
01075  mcASSERT(h != 0, wxT("Cannot retrieve character size"));
01076 
01077  // clean up
01078  if (bClean)
01079   delete hDC;
01080 
01081  // and return
01082  return h;
01083 }
01084 
01085 
01086 
01087 
01088 
01089 // ----------------------------------------
01090 // mcELEMENTIO - miscellaneous
01091 // ----------------------------------------
01092 
01093 void mcElementHelpers::io_PostProcessChildren()
01094 {
01095  for (int i=0; i < data_GetChildrenCount(); i++)
01096   data_GetChild(i).hlp()->io_PostProcess();
01097 }
01098 
01099 
01100 
01101 
01102 
01103 // ----------------------------------------
01104 // mcELEMENTMATH - basic functions
01105 // ----------------------------------------
01106 
01107 mcElement mcElement::operator^(const mcRealValue &r) const
01108 { mcElement ret(*this); ret.math_RaiseTo(mcPolynomial(r)); return ret; }
01109 
01110 void mcElementHelpers::math_SimpleAdd(const mcElement &p, bool add)
01111 {
01112  mcMATHLOG(wxT("mcElementHelpers::math_SimpleAdd [%s] - simple adding with [%s]"),
01113     mcTXTTHIS, mcTXT(p));
01114  mcBasicOpRes r = math_Add(p, NULL, add);
01115  mcASSERT(r == mcBOR_REMOVE_OPERAND, 
01116    wxT("The operation could not be completely performed: ")
01117    wxT("the given operand has not been completely merged in *this"));
01118  mcUNUSED(r);  // avoid dummy warnings
01119 }
01120 
01121 void mcElementHelpers::math_SimpleMultiplyBy(const mcElement &p)
01122 {
01123  mcMATHLOG(wxT("mcElementHelpers::math_SimpleMultiplyBy [%s] - simple multiplying by [%s]"),
01124     mcTXTTHIS, mcTXT(p));
01125  mcBasicOpRes r = math_MultiplyBy(p, NULL);
01126  mcASSERT(r == mcBOR_REMOVE_OPERAND, 
01127    wxT("The operation could not be completely performed: ")
01128    wxT("the given operand has not been completely merged in *this"));
01129  mcUNUSED(r);  // avoid dummy warnings
01130 }
01131 
01132 void mcElementHelpers::math_SimpleDivideBy(const mcElement &p)
01133 {
01134  mcMATHLOG(wxT("mcElementHelpers::math_SimpleDivideBy [%s] - simple dividing by [%s]"),
01135     mcTXTTHIS, mcTXT(p));
01136  mcBasicOpRes r = math_DivideBy(p, NULL);
01137  mcASSERT(r == mcBOR_REMOVE_OPERAND, 
01138    wxT("The operation could not be completely performed: ")
01139    wxT("the given operand has not been completely merged in *this"));
01140  mcUNUSED(r);  // avoid dummy warnings
01141 }
01142 
01143 void mcElementHelpers::math_SimpleRaiseTo(const mcPolynomial &p)
01144 {
01145  mcMATHLOG(wxT("mcElementHelpers::math_SimpleRaiseTo [%s] - simple raising by [%s]"),
01146     mcTXTTHIS, mcTXT(p));
01147  mcBasicOpRes r = math_RaiseTo(p);
01148  mcASSERT(r == mcBOR_REMOVE_OPERAND, 
01149    wxT("The operation could not be completely performed: ")
01150    wxT("the given operand has not been completely merged in *this"));
01151  mcUNUSED(r);  // avoid dummy warnings
01152 }
01153 
01154 bool mcElementHelpers::math_isExpAllowed(mcElement p) 
01155 {
01156  // check if the exponent level is under the limit
01157  //if (p.GetExpDepth()+1 < mcELEMENTMATH_MAX_EXPDEPTH)
01158   return TRUE;
01159  //return FALSE;
01160 }
01161 
01162 bool mcElementHelpers::math_isSubAllowed(mcElement )
01163 {
01164  // allow nested subscripts to a undefined depth...
01165  return TRUE;
01166 }
01167 
01168 void mcElementHelpers::math_SetExp(const mcPolynomial &pol)
01169 {
01170  // just call recursively the math_SetExp on our children...
01171  // this behaviour is right for those elements not-derived
01172  // from mcExpElement and which does not own an exponent
01173  // and thus are obliged to set the exponents of their children
01174  for (int i=0; i<data_GetChildrenCount(); i++)
01175   data_GetChild(i).math_SetExp(pol);
01176 }
01177 
01178 mcBasicOpRes mcElementHelpers::math_MakeReciprocal(mcElement *replacement)
01179 {
01180  mcFraction f;
01181  f.data_GetNum().math_WrapNumber(1);
01182  f.data_GetDen().math_WrapSimple(mcElement(this));
01183  *replacement = f;
01184 
01185  return mcBOR_REPLACE_BOTH;
01186 }
01187 
01188 mcExpSimRes mcElementHelpers::math_MaxSimplify(long flags)
01189 {
01190  mcExpSimRes retflag = mcESR_NOTFINISHED;
01191  int cycles=0;
01192 
01193  // call mcElementHelpers::math_Simplify(long flags) until everything is completely
01194  // simplified....
01195  while (retflag != mcESR_DONE) {
01196   retflag = math_Simplify(flags, NULL);  // NULL is just to compile but it's wrong
01197   cycles++;
01198   
01199   if (cycles >= mcELEMENTMATH_MAX_PROCESS_CYCLES)  // avoid to block the program
01200    return mcESR_NOTFINISHED;  // cannot finish !!!
01201  }
01202 
01203  return mcESR_DONE;
01204 }
01205 
01206 bool mcElementHelpers::math_isMaxSimplified(long flags) const
01207 {
01208  mcExpSimRes retflag = mcESR_NOTFINISHED;
01209  int cycles=0;
01210 
01211  // work on a backup copy
01212  mcElementHelpers *backup = data_Clone();
01213 
01214  // call mcElementHelpers::math_Simplify(long flags) until everything is completely
01215  // simplified....
01216  while (retflag != mcESR_DONE) {
01217   retflag = backup->math_Simplify(flags, NULL);  // NULL is just to compile but it's wrong
01218   cycles++;
01219 
01220   if (cycles >= mcELEMENTMATH_MAX_PROCESS_CYCLES)  // avoid to block the program
01221    break;
01222  }
01223 
01224  // if the function returned mcESR_DONE at the first math_Simplify call, then
01225  // it should be completely simplified...
01226  return (cycles == 1);
01227 }
01228 
01229 mcRealValue mcElementHelpers::math_GetTotalLenght() const
01230 {
01231  // to compute the lenght of this element we must take in count:
01232  // 1) the lenght of the children
01233  // 2) the lenght of this element itself (without its children)
01234  //    using the #math_GetLenght() function
01235  mcRealValue l = math_GetLenght();
01236  
01237  for (int i=0; i < data_GetChildrenCount(); i++)
01238   l += data_GetConstChild(i).math_GetTotalLenght();
01239   
01240  return l;
01241 }
01242 
01243 bool mcElementHelpers::math_isFinite() const
01244 {
01245  mcRealValue res = math_Evaluate();
01246  if (res.math_isFinite())
01247   return TRUE;
01248  return FALSE;
01249 }
01250 
01251 bool mcElementHelpers::math_isValidMath() const
01252 {
01253  switch (data_GetType()) {
01254  case mcET_INVALID:
01255  case mcET_PARENTHESIS:
01256  case mcET_EMPTYBOX:
01257 /* case mcET_ADDOP:
01258  case mcET_SUBOP:
01259  case mcET_MULTOP:
01260  case mcET_DIVOP:*/
01261  case mcET_TEXT:
01262   return FALSE;  // a mcDecoration-derived class
01263 
01264  default:
01265   break;
01266  }
01267 
01268  // we are valid but we have to check our children...
01269  for (int i=0; i < data_GetChildrenCount(); i++)
01270   if (!data_GetConstChild(i).math_isValidMath())
01271    return FALSE;
01272 
01273  // ok; we are fully valid
01274  return TRUE;
01275 }
01276 
01277 bool mcElementHelpers::math_isListedBeforeOf(const mcElement &p) const
01278 {
01279  if (math_GetOrderPos() < p.math_GetOrderPos())
01280   return TRUE;
01281  return FALSE;
01282 }
01283 
01284 mcMonomial mcElementHelpers::math_GetFactors() const
01285 {
01286  mcMonomial pol;
01287  pol.math_WrapSimple(this);
01288 
01289  return pol;
01290 }
01291 
01292 
01293 
01294 
01295 // -------------------------------------------------------------------
01296 // mcELEMENTMATH - search, comparison & replace functions
01297 // -------------------------------------------------------------------
01298 
01299 bool mcElementHelpers::math_Contains(const mcElement &p, long flags) const
01300 { return math_Find(0, p, flags) != mcEmptyElement; }
01301 
01302 bool mcElementHelpers::math_ContainsNumber(const mcRealValue &num,
01303              const mcPolynomial &exp) const
01304 {
01305  mcNumber n(num);
01306 
01307  // use the given polynomial as exponent, if required
01308  if (exp != mcEmptyPolynomial)
01309   n.data_SetExpSub(TRUE, exp);
01310 
01311  return math_Contains(n);
01312 }
01313 
01314 bool mcElementHelpers::math_ContainsSymbol(const mcSymbolProperties *prop,
01315              const mcPolynomial &exp) const
01316 {
01317  mcSymbol safe(prop->data_GetSafeLinkedSym());
01318  mcASSERT(safe.data_isOk(), wxT("Invalid safe symbol ?"));
01319 
01320  // use the given polynomial as exponent, if required
01321  if (exp != mcEmptyPolynomial)
01322   safe.data_SetExpSub(TRUE, exp);
01323 
01324  return math_Contains(safe);
01325 }
01326 
01327 bool mcElementHelpers::math_ContainsOneOf(const mcSymbolArray *arr) const
01328 {
01329  int max = arr->data_GetCount();
01330  for (int i=0; i < max; i++) {
01331 
01332   // this element will be used to contain the properties of
01333   // the symbol we are searching for in this element
01334   //mcSymbol sym;
01335 
01336   // try to search all the symbols in the given array...
01337   const mcSymbolProperties *curr = arr->data_GetSymbol(i);
01338 
01339   // BAD CAST FROM CONST TO NON-CONST !!!!
01340   //sym.data_LinkWith((mcSymbolProperties *)curr);
01341 
01342   if (math_Contains(curr->data_GetSafeLinkedSym())) {
01343 
01344    // ok; we contain one of the array's symbol
01345    return TRUE;
01346   }
01347  }
01348 
01349  // we do not contain any of the symbol listed in arrUnknowns
01350  return FALSE;
01351 }
01352 
01353 bool mcElementHelpers::math_ContainsUnknowns() const
01354 { return math_ContainsOneOf(&mcSymbol::arrUnknowns); }
01355 
01356 bool mcElementHelpers::math_ContainsConstants() const
01357 { return math_ContainsOneOf(&mcSymbol::arrConstants); }
01358 
01359 bool mcElementHelpers::math_ContainsParameters() const
01360 { return math_ContainsOneOf(&mcSymbol::arrParameters); }
01361 
01362 bool mcElementHelpers::math_ContainsSymbols() const
01363 {
01364  // just check if contains any of the three supported type of symbols...
01365  return math_ContainsUnknowns() || 
01366    math_ContainsConstants() ||
01367    math_ContainsParameters();
01368 }
01369 
01370 bool mcElementHelpers::math_ContainsInvalidSymbols() const
01371 {
01372  // just scan for unregistered symbols...
01373  return math_ContainsOneOf(&mcSymbol::arrUnregistered);
01374 }
01375 
01376 bool mcElementHelpers::math_isConstant() const
01377 {
01378  // since the only non-container elements are mcSymbols and mcNumbers
01379  // we just need to check them; since mcNumbers are allowed in any
01380  // case, we just have to check mcSymbols...
01381  return !math_ContainsParameters() && !math_ContainsUnknowns();
01382 }
01383 
01384 int mcElementHelpers::math_GetSymbolList(mcSymbol **arr, int size, const mcSymbol &tofind) const
01385 {
01386  int n = 0;
01387  //if (arr == NULL) return -math_GetCountOf(&tofind);
01388 
01389  // start to search the first symbol...
01390  const mcElement p = math_Find(n, tofind);
01391 /*
01392  while (p) {
01393 
01394   if (size <= n) return -math_GetCountOf(&tofind);
01395 
01396   // store this entry
01397   arr[n] = (mcSymbol *)p;
01398 
01399   // and search the next...
01400   p = math_Find(++n, tofind);
01401  }*/
01402 
01403  return n;
01404 }
01405 
01406 int mcElementHelpers::math_GetSymbolList(mcSymbol **arr, int size, mcSymbolProperties &tofind) const
01407 {
01408  mcSymbol tmp;
01409  tmp.data_LinkWith(&tofind);
01410 
01411  return math_GetSymbolList(arr, size, tmp);
01412 }
01413 
01414 bool mcElementHelpers::math_CompareThisOnly(const mcElement &p, long) const
01415 {
01416  // we just need to compare types for simple elements
01417  // which are just containers of other elements (like
01418  // mcFraction)
01419  return (data_GetType() == p.data_GetType());
01420 }
01421 
01422 mcElement mcElementHelpers::math_Find(int n, const mcElement &p, long flags) const
01423 {
01424  mcASSERT(n >= 0, wxT("Invalid occurrence to find"));
01425  int k = n;
01426 
01427  // search recursively
01428  return math_RecursiveFind(k, p, flags);
01429 }
01430 
01431 mcElement mcElementHelpers::math_FindInChildrenOnly(int n, const mcElement &p, long flags) const
01432 {
01433  mcASSERT(n >= 0, wxT("Invalid occurrence to find"));
01434  int k = n;
01435 
01436  // search recursively
01437  return math_RecursiveFindInChildrenOnly(k, p, flags);
01438 }
01439 
01440 int mcElementHelpers::math_NonRecursiveFindInChildren(int n, 
01441      const mcElement &p, long flags) const
01442 {
01443  mcASSERT(n >= 0, wxT("Invalid occurrence to find"));
01444 
01445  // scan all the children
01446  for (int i=0,max=data_GetChildrenCount(); i<max; i++) {
01447     
01448   if (data_GetConstChild(i).math_Compare(p, flags)) {
01449    
01450    // did we find it ?  
01451    if (--n == -1)
01452     return i;
01453 
01454    // wait for next
01455   }
01456  }
01457  
01458  // could not find anything
01459  return -1;
01460 }
01461 
01462 mcElement mcElementHelpers::math_RecursiveFindInChildrenOnly(int &n, 
01463         const mcElement &p, long flags) const
01464 {
01465  mcASSERT(n >= 0, wxT("Invalid occurrence to find"));
01466 
01467  // scan all the children
01468  for (int i=0,max=data_GetChildrenCount(); i<max; i++) {
01469 
01470   // and recursively search in each of them the element p
01471   const mcElement &res = data_GetConstChild(i).chlp()->math_RecursiveFind(n, p, flags);
01472 
01473   // did we find it ?
01474   // NOTE: since we passed a reference of n, something like
01475   //            if (res != mcEmptyElement) n--;
01476   //       is not necessary 
01477   if (n == -1) {
01478 
01479    // if the given pointer is valid...
01480    if (res != mcEmptyElement) 
01481     return res;
01482 
01483    // if it's not it must be because the data_GetConstChild(i)
01484    // is the parent of the element to find and "flags" contain
01485    // the mcFIND_PARENT flag...
01486    mcASSERT(flags & mcFIND_PARENT, wxT("Something wrong"));
01487 
01488    // NOTE: perform this check
01489    //       1) without the mcFIND_PARENT flag since we don't need it
01490    //       2) with "n+1" since n is now -1 and thus it's invalid.
01491    mcASSERT(math_NonRecursiveFindInChildren(n+1, p, flags & ~mcFIND_PARENT) != -1,
01492     wxT("Cannot find the element tofind in the children of *this..."));
01493    return mcElement(this);
01494   }
01495  }
01496 
01497  return mcEmptyElement;
01498 }
01499 /*
01500 mcElement mcElementHelpers::math_FindParent(const mcElement &p, long flags) const
01501 {
01502 
01503 }*/
01504 
01505 mcElement mcElementHelpers::math_RecursiveFind(int &n, 
01506         const mcElement &p, long flags) const
01507 {
01508  mcASSERT(n >= 0, wxT("Invalid occurrence to find"));
01509 
01510  // if we are of the same type of p and we have enough children,
01511  // the it maybe that we are identic to "p"...
01512  if (math_CompareThisOnly(p, flags) &&
01513   data_GetChildrenCount() >= p.data_GetChildrenCount()) {
01514 
01515   // to be sure that this element matches "p", we must
01516   // compare all p's children with our children in the right
01517   // order: if one or more child is different from the relative
01518   // p's child, then we can just try to search "p" in our children
01519   // recursively...
01520   for (int i=0,max=p.data_GetChildrenCount(); i<max; i++)
01521    if (!data_GetConstChild(i).math_Compare(p.data_GetConstChild(i), flags))
01522     return math_RecursiveFindInChildrenOnly(n, p, flags); // we don't match p
01523 
01524   // we are identic to p and this is true also for ours
01525   // first p.data_GetChildrenCount() children; we can thus
01526   // return ourselves as result or just decrement 'n' (it's a
01527   // reference, so the caller's "n" is automatically sync)
01528   // if this is not the occurrence we are searching for...
01529   if (--n == -1) {
01530 
01531    // if we have to return not the element itself but its parent,
01532    // then we have to return with "n" set to -1 and with a NULL element:
01533    // math_RecursiveFindInChildrenOnly will then understand what
01534    // happened and will return the parent of "p" (which we do not hold
01535    // and thus we cannot return it directly).
01536    if (flags & mcFIND_PARENT)
01537     return mcEmptyElement;
01538 
01539    return mcElement(this);
01540   }
01541  }
01542 
01543  // *this does not match "p"; just search in our children
01544  return math_RecursiveFindInChildrenOnly(n, p, flags);
01545 }
01546 
01547 int mcElementHelpers::math_GetCountOfChildrenOnly(const mcElement &p, long flags) const
01548 {
01549  int total = 0;
01550 
01551  for (int i=0,max=data_GetChildrenCount(); i<max; i++)
01552   total += data_GetConstChild(i).math_GetCountOf(p, flags);
01553 
01554  return total;
01555 }
01556 
01557 int mcElementHelpers::math_GetCountOf(const mcElement &p, long flags) const
01558 {
01559  int total = 0;
01560 
01561  if (math_CompareThisOnly(p, flags) &&
01562   data_GetChildrenCount() >= p.data_GetChildrenCount()) {     
01563 
01564   for (int i=0,max=p.data_GetChildrenCount(); i<max; i++)
01565    if (!data_GetConstChild(i).math_Compare(p.data_GetConstChild(i), flags))
01566     return math_GetCountOfChildrenOnly(p, flags);
01567 
01568   total++;
01569  }
01570 
01571  return total+math_GetCountOfChildrenOnly(p, flags);
01572 }
01573 
01574 int mcElementHelpers::math_GetCountOf(const mcSymbolProperties *p, long flags) const
01575 {
01576  mcSymbol safe(p->data_GetSafeLinkedSym());
01577  mcASSERT(safe.data_isOk(), wxT("Invalid safe symbol ?"));
01578 
01579  return math_GetCountOf(safe, flags);
01580 }
01581 
01582 int mcElementHelpers::math_GetCountOf(const mcSymbolArray *p, long flags) const
01583 {
01584  int total = 0;
01585 
01586  // slow but easy to code... 
01587  for (int i=0; i<p->data_GetCount(); i++)
01588   total += math_GetCountOf(p->data_GetSymbol(i), flags);
01589 
01590  return total;
01591 }
01592 
01593 int mcElementHelpers::math_GetCountOfSymbolsType(const mcSymbolArray *p, long flags) const
01594 {
01595  int total = 0;
01596 
01597  // unlike math_GetCountOf(const mcSymbolArray *p, ...) we don't
01598  // want to take the total number of symbols contained: we want
01599  // to know how many *types* of symbols of the given array are
01600  // contained...
01601  for (int i=0; i<p->data_GetCount(); i++)
01602   total += (int)math_ContainsSymbol(p->data_GetSymbol(i));
01603 
01604  return total;
01605 }
01606 
01607 int mcElementHelpers::math_Replace(const mcElement &tofind, int n, long flags,
01608        const mcElement &replacement, bool addchildren)
01609 {
01610  mcMATHLOG(wxT("mcElementHelpers::math_Replace [%s] - going to replace [%s] with [%s]"),
01611     mcTXTTHIS, mcTXT(tofind), mcTXT(replacement));
01612  mcElement p(mcEmptyElement);
01613  int ntotal = 0;
01614  bool onlyone = (n != -1);
01615  int occ = (onlyone ? n : 0);
01616 
01617  // we have to find the first unshared parent of the element tofind
01618  mcElement parent = math_Find(occ, tofind, flags | mcFIND_PARENT);
01619  if (parent == mcEmptyElement) return 0;
01620  const mcElement *currtofind = &parent;
01621 
01622  mcElement currparent(mcEmptyElement);
01623  while (currtofind) {
01624 
01625   // calling the math_Find() function, we ask "parent" to share
01626   // the same reference data of the actually found element...  
01627   currparent = math_Find(0, *currtofind, flags | mcFIND_PARENT);
01628   if (currparent == mcEmptyElement) break;
01629 
01630   // ... thus, if that element is shared only by an element, then
01631   // it should have a reference count == 2
01632   if (currparent.data_GetRefData()->data_GetRefCount() > 2)
01633    currtofind = &currparent;
01634   else
01635    currtofind = NULL;
01636  }
01637 
01638  // "currparent" is not shared by anyone...
01639  /*while (currparent != parent) {
01640   currparent.math_Find(
01641  }
01642  
01643  // if we have to replace all the occurrences, start from the first
01644  int occ = (onlyone ? n : 0);
01645  
01646  // first of all, find the element
01647  mcElement p = math_Find(occ, tofind, flags);
01648 
01649  mcElement &parent = p;
01650  while (parent 
01651  mcElement parent = math_Find(occ, tofind, flags | mcFIND_PARENT);
01652  mcASSERT(parent != mcEmptyElement, 
01653    wxT("Cannot replace an element which does not have a parent"));
01654  while (parent != mcEmptyElement) {
01655   
01656   // now search in the parent we've just found, the element to find...
01657   int idx = parent.math_NonRecursiveFindInChildren(occ, tofind, flags);
01658   mcASSERT(idx != -1, wxT("We've found an invalid parent !")
01659        wxT("The parent does not have a pointer to its child ?"));
01660   p = parent.data_GetConstChild(idx);
01661   
01662   mcMATHLOG(wxT("mcElementHelpers::math_Replace - the parent of [%s] is [%s]"), 
01663    mcTXT(p), mcTXT(parent));
01664   
01665   // if we want to add the children of "p" to the replacement...
01666   mcElement rep(replacement);
01667   if (addchildren) {
01668 
01669    // create a new instance of the replacement
01670    // with the children attached...
01671    mcElement tmp(replacement);
01672    bool b = p.data_AddChildrenTo(tmp);
01673  
01674    // if we've been called with addchilren = TRUE, then this
01675    // operation should always work; otherwise, some elements
01676    // (the children of p) would be lost...
01677    mcASSERT(b, wxT("Cannot add children... check function call"));
01678 
01679    // don't use normal replacement for this replace operation;
01680    // use the replacement+children
01681    rep = tmp;
01682   }
01683   
01684   // then replace it (data_SetChild will make a copy)
01685      parent.data_SetChild(idx, rep);
01686   mcMATHLOG(wxT("mcElementHelpers::math_Replace - replaced occ #%d: [%s]"), 
01687    ntotal, mcTXT(parent));
01688   
01689   // another substitution has been done...
01690   ntotal++;  
01691   if (onlyone) break;
01692 
01693   // find next first occurrence of TOFIND...
01694   // we'll search the first occurrence since the one we've just
01695   // found has been replaced and thus does not exist anymore.
01696   parent = math_Find(0, tofind, flags | mcFIND_PARENT);
01697 
01698  }*/
01699  
01700  return ntotal;
01701 }
01702 
01703 
01704 // some wrappers which must be implemented in the source file...
01705 
01706 mcMonomial mcElement::math_GetLCM(const mcElement &p) const
01707 { return hlp()->math_GetLCM(p); }
01708 
01709 mcMonomial mcElement::math_GetGCD(const mcElement &p) const
01710 { return hlp()->math_GetGCD(p); }
01711 
01712 mcMonomial mcElement::math_GetFactors() const
01713 { return hlp()->math_GetFactors(); }
01714 
01715 
01716 
01717 
01718 mcRealValue mcElementHelpers::math_EvaluateAt(const mcSymbolProperties *sym,
01719             const mcRealValue &symvalue) const
01720 {
01721  mcMATHLOG(wxT("mcElementHelpers::math_EvaluateAt [%s] - evaluating at [%s]=%s"),
01722     mcTXTTHIS, mcTXTP(sym), mcTXTV(symvalue));
01723 
01724 #if 0
01725  mcSymbol symtorep;
01726  symtorep.data_LinkWith(&sym);
01727  mcNumber replacement;
01728  replacement.math_Set(symvalue);
01729  
01730  // or we should move sym to constants temporarily ?
01731  
01732  mcMathMng *clone = this->Clone();
01733  clone.math_Replace(&symtorep, -1, &replacement, TRUE);
01734  mcRealValue res = clone.math_Evaluate();
01735  delete clone;
01736 #endif
01737 
01738  // FIXME: thread unsafe ???
01739 /*
01740  int entry = -1;
01741  const mcSymbolProperties *sym = psym;
01742 
01743  // find the array containing the given symbol (should be arrParameters
01744  // or arrUnknowns)...
01745  mcSymbolArray *oldarr = mcSymbol::math_FindSymbol(mcSYMFIND_MATCH_ALL, *sym, 0, &entry);
01746  if (oldarr == NULL || entry == mcSYM_NOTFOUND) return *mcRealValue::pNAN;
01747 
01748  // save its old value
01749  mcRealValue old = sym->m_fValue;
01750  
01751  // temporary move it to mcSymbol::arrConstants
01752  mcSymbolProperties *newsym = oldarr->data_MoveSymbols(entry, &mcSymbol::arrConstants);
01753  if (newsym == NULL) return *mcRealValue::pNAN;
01754 
01755  // and sets a new value
01756  newsym->m_fValue = symvalue;
01757 
01758  // evaluate with the symbol's new value
01759  mcRealValue res = math_Evaluate();
01760 
01761  // now, undo what we did
01762  newsym->m_fValue = old;
01763  entry = mcSymbol::arrConstants.data_FindSymbol(mcSYMFIND_MATCH_ALL, *newsym);
01764  psym = mcSymbol::arrConstants.data_MoveSymbols(entry, oldarr); 
01765 */
01766  // NOTE: this should not be done, generally; however, here we can do
01767  //       it because we are going to modify the given mcSymbolProperties
01768  //       but we are also going to undo our changes... :-)
01769  mcSymbolProperties *psym = (mcSymbolProperties *)sym;
01770 
01771  // temporary set the "evaluation mode"
01772  psym->m_bEvaluating = TRUE;
01773  psym->m_fValue = symvalue;
01774 
01775  // evaluate ourselves
01776  mcRealValue res = math_Evaluate();
01777 
01778  // then revert everything to normal mode
01779  psym->m_bEvaluating = FALSE;
01780  psym->m_fValue = *mcRealValue::pNAN;
01781 
01782  mcMATHLOG(wxT("mcElementHelpers::math_EvaluateAt - result is %s"), mcTXTV(res));
01783  return res;
01784 }


Documentation generated with Doxygen on Sun Feb 6 17:10:45 2005
Visit MathStudio home page for more info

[ Top ]