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

ExpContainer.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 "ExpContainer.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 "mc/Element.h"
00047  #include "mc/ExpContainer.h"
00048 #endif
00049 
00050 
00051 
00052 mcIMPLEMENT_ABSTRACT_CLASS(mcExpContainer, mcExpElement);
00053 
00054 
00055 
00056 // ----------------------------------------
00057 // mcExpContainerGUI
00058 // ----------------------------------------
00059 
00060 bool mcExpContainerHelpers::gui_isBaseEndKey(const mcKey &ev) const
00061 {
00062  // using cursor position, decide if the given character is okay
00063  switch (mgui_nCursorPos) {
00064  case mcEXPCONTAINER_LEFTMOST:
00065  case mcEXPCONTAINER_RIGHTMOST:
00066   if (mcMathCore::Get()->MatchEditKeys(ev))
00067    return FALSE;
00068   return TRUE;
00069  }
00070  
00071  // mgui_nCursorPos must be mcEXPCONTAINER_INSIDEEXPR
00072  mcASSERT(mgui_nCursorPos == mcEXPCONTAINER_INSIDEEXPR, wxT("Invalid cursor position"));
00073  return FALSE;
00074 }
00075 
00076 void mcExpContainerHelpers::gui_EditBase()
00077 {  
00078  // set cursor on the base
00079  mgui_nCursorPos = mcEXPCONTAINER_INSIDEEXPR;
00080  mgui_nCursorLoc = mcECL_INSIDEBASE;
00081 }
00082 
00083 void mcExpContainerHelpers::gui_OnBaseSelect(wxDC &dc, wxRect &rc)
00084 {
00085  // be sure that the selection rectangle is not inside the left
00086  // or right bracket
00087  wxPoint orig(gui_GetContentOffsetX(), gui_GetContentOffsetY());
00088  wxRect content(orig, data_GetContent().gui_GetSize());
00089 
00090  // the parent has got an extended selection; cannot select only a part of
00091  // the bracket....
00092 /* if (hlp()->GetParent().data_GetType() == mcET_POLYNOMIAL) {
00093   if (((mcElementArray *)(hlp()->GetParent())).gui_GetSelElemCount() > 0) {
00094    gui_SelectAll();
00095    return;
00096   }
00097  }*/
00098  //mcASSERT(0, "");
00099  
00100  // just recall the mcPolynomial's gui_OnSelect function: it will find the
00101  // element whose bounding box intersects with the selection rectangle
00102  // and it will select it; ignore the selection if it intersects the
00103  // brackets only.
00104  if (content.Intersects(rc)) {
00105 
00106   rc.Offset(-content.x, -content.y);
00107   data_GetContent().gui_OnSelect(dc, rc);
00108  }
00109 
00110  // if our contents are selected, we are too
00111  if (data_GetContent().gui_isSelected())
00112   gui_Select();
00113 }
00114 
00115 int mcExpContainerHelpers::gui_DrawBase(wxDC &dc, int x, int y, long flags, 
00116           const wxPoint &pt) const
00117 {
00118  wxPoint org(x+gui_GetContentOffsetX(), y+gui_GetContentOffsetY()), mypt=pt;
00119  wxRect rc(org, data_GetContent().gui_GetSize());
00120  bool ret = FALSE;
00121  int r;
00122  
00123  if (flags & mcDRW_USEPOINT) {
00124   
00125   if (rc.Inside(pt)) {
00126   
00127    // the mouse cursor is inside the math content: we must return the ID
00128    // of the active element contained inside it, not our ID...
00129    ret = TRUE;
00130 
00131   } else {
00132 
00133    // the cursor is not inside the contents: it's useless to tell
00134    // them to check the point coords we give them...
00135    flags &= ~mcDRW_USEPOINT;
00136   }
00137  }
00138  
00139  // should we allot to the contents to draw itself as entirely
00140  // selected, if it is ?
00141  flags &= ~mcDRW_ALLOW_TOTAL_SELECTION;
00142  if (!data_GetContent().gui_isAllSelected())
00143   flags |= mcDRW_ALLOW_TOTAL_SELECTION; 
00144 
00145  // draw the content
00146  r = data_GetContent().gui_Draw(dc, org.x, org.y, flags, mypt);
00147  
00148  // draw the container graphic
00149  gui_DrawContainer(dc, x, y, flags, pt);
00150  
00151  // choose which ID must be returned
00152  return (ret == TRUE) ? r : data_GetID();
00153 }
00154 
00155 mcInputRes mcExpContainerHelpers::gui_BaseInput(const mcKey &key, mcElement *pnew)
00156 {
00157  // discard the begin character used to create this element
00158  if (gui_isBeginKey(key) != FALSE && 
00159   !data_hasProperty(mcEP_INITIALIZED)) {
00160 
00161   // create an empty box in the contained expression
00162   data_GetContent().gui_AddNewEmptyMonomial();
00163  
00164   // this element is now ready for input
00165   data_AddProperty(mcEP_INITIALIZED);
00166   gui_RecalcSize();
00167 
00168   return mcIR_OKAY;
00169  }
00170 
00171  // handle the EDITEXP and EDITSUBSCRIPT keypresses, if the cursor
00172  // is not placed inside the contained expression...
00173  if (mgui_nCursorPos == mcEXPCONTAINER_LEFTMOST || 
00174   mgui_nCursorPos == mcEXPCONTAINER_RIGHTMOST) {
00175 
00176   if (gui_HandleSubExpEditKeys(key) == mcIR_OKAY)
00177    return mcIR_OKAY;
00178  }
00179  
00180  switch (mgui_nCursorPos) {
00181  case mcEXPCONTAINER_LEFTMOST:
00182   
00183   if (mcMathCore::Get()->m_pDeleteKey->MatchKey(key)) {
00184    
00185    // delete previous elements
00186    return mcIR_DELETE_PREVIOUS;
00187    
00188   } else if (mcMathCore::Get()->m_pCancelKey->MatchKey(key)) {
00189    
00190    // delete this class
00191    return mcIR_DELETE_THIS; 
00192   } 
00193   
00194   mcMathCore::Get()->SyntaxError(wxT("Cannot type here"));
00195   break;
00196 
00197  case mcEXPCONTAINER_RIGHTMOST:
00198 
00199   if (mcMathCore::Get()->m_pDeleteKey->MatchKey(key)) {
00200    
00201    // delete this class
00202    return mcIR_DELETE_THIS; 
00203    
00204   } else if (mcMathCore::Get()->m_pCancelKey->MatchKey(key)) {
00205    
00206    // delete next elements
00207    return mcIR_DELETE_NEXT;
00208   } 
00209   
00210   mcMathCore::Get()->SyntaxError(wxT("Cannot type here"));
00211   break;
00212   
00213  case mcEXPCONTAINER_INSIDEEXPR:
00214 
00215   // let the contained expression process the input
00216   mcInputRes r = data_GetContent().gui_Input(key, pnew);
00217   return gui_HandleContentInput(r, pnew);
00218  }
00219  
00220  return mcIR_OKAY;
00221 }
00222 
00223 mcInsertRes mcExpContainerHelpers::gui_BaseInsert(const mcElement &toinsert, mcElement *)
00224 {
00225  mcASSERT(mgui_nCursorPos != mcEXPCONTAINER_LEFTMOST &&
00226   mgui_nCursorPos != mcEXPCONTAINER_RIGHTMOST,
00227   wxT("Invalid position"));
00228 
00229  return data_GetContent().gui_Insert(toinsert, NULL);
00230 }
00231 
00232 mcInputRes mcExpContainerHelpers::gui_HandleContentInput(mcInputRes r, mcElement *)
00233 {
00234  switch (r) {
00235  case mcIR_OKAY:
00236   break;
00237   
00238  case mcIR_DELETE_THIS:
00239  case mcIR_DELETE_PREVIOUS:
00240  case mcIR_DELETE_NEXT:
00241   return mcIR_DELETE_THIS;
00242   
00243  default:
00244   mcASSERT(0, wxT("Unhandled return flag"));
00245  }
00246  
00247  // size should have changed
00248  gui_RecalcSize();
00249  return mcIR_OKAY;
00250 }
00251 
00252 mcMoveCursorRes mcExpContainerHelpers::gui_BaseMoveCursor(mcMoveCursorFlag flag, long modifiers)
00253 {
00254  mcMoveCursorRes result;
00255 
00256  // handle up/down flags for both the cursor positions which 
00257  // are completely under our control
00258  if (mgui_nCursorPos == mcEXPCONTAINER_LEFTMOST || 
00259   mgui_nCursorPos == mcEXPCONTAINER_RIGHTMOST) {
00260 
00261   if (flag == mcMCF_UP)
00262    return mcMCR_SETFOCUS_ABOVE;
00263   if (flag == mcMCF_DOWN)
00264    return mcMCR_SETFOCUS_BELOW;
00265  }
00266  
00267  switch (mgui_nCursorPos) {
00268  case mcEXPCONTAINER_LEFTMOST:
00269   mcASSERT(gui_isLeftPosEnabled(), wxT("Cursor position is wrong"));
00270   
00271   // cursor position (cursor=|):
00272   //    ...+ | (....)+...
00273   if (flag == mcMCF_LEFT) {
00274 
00275    // there is nothing on the left of this position,
00276    // which belongs to the element...
00277    return mcMCR_SETFOCUS_PREVIOUS;
00278 
00279   } else if (flag == mcMCF_RIGHT) {
00280 
00281    // set the cursor on the leftmost position inside the
00282    // content
00283    mgui_nCursorPos = mcEXPCONTAINER_INSIDEEXPR;
00284    data_GetContent().gui_SetCursorPos(mcCP_BEGIN);
00285   }
00286   break;
00287   
00288  case mcEXPCONTAINER_INSIDEEXPR:
00289   // cursor position (cursor=|):
00290   //    ...+(... | ...)+...
00291   
00292   // drop request to the expression
00293   result = data_GetContent().gui_MoveCursor(flag, modifiers);
00294   
00295   // check if cursor is still inside the expression
00296   if (result == mcMCR_SETFOCUS_PREVIOUS) {
00297    if (gui_isLeftPosEnabled())
00298     mgui_nCursorPos = mcEXPCONTAINER_LEFTMOST;
00299    else
00300     return mcMCR_SETFOCUS_PREVIOUS;
00301 
00302   } else if (result == mcMCR_SETFOCUS_NEXT) {
00303    if (gui_isRightPosEnabled())
00304     mgui_nCursorPos = mcEXPCONTAINER_RIGHTMOST;
00305    else
00306     return mcMCR_SETFOCUS_NEXT;
00307 
00308   } else if (result == mcMCR_SETFOCUS_BELOW || result == mcMCR_SETFOCUS_ABOVE) {
00309    
00310    // return the setfocus request to the caller
00311    return result;
00312   }
00313   break;
00314   
00315  case mcEXPCONTAINER_RIGHTMOST:
00316   mcASSERT(gui_isRightPosEnabled(), wxT("Cursor position is wrong"));
00317 
00318   // cursor position (cursor=|):
00319   //    ...+(....) | +...
00320   if (flag == mcMCF_RIGHT) {
00321 
00322    // there is nothing beyond this cursor position...
00323    return mcMCR_SETFOCUS_NEXT;
00324 
00325   } else if (flag == mcMCF_LEFT) {
00326 
00327    // set the cursor on the rightmost position inside
00328    // the content
00329    mgui_nCursorPos = mcEXPCONTAINER_INSIDEEXPR;
00330    data_GetContent().gui_SetCursorPos(mcCP_END);
00331   }
00332   break;
00333 
00334  default:
00335   mcASSERT(0, wxT("Unhandled cursor position"));
00336  }
00337  
00338  return mcMCR_OKAY;
00339 }
00340 
00341 int mcExpContainerHelpers::gui_BaseMoveCursorUsingPoint(wxDC &hDC, const wxPoint &pt)
00342 {
00343  wxRect rc(wxPoint(0, 0), data_GetContent().gui_GetSize());  
00344  wxPoint mypt(pt);
00345  
00346  // user should have clicked on the content
00347  if (rc.Inside(mypt)) {
00348   
00349   mypt.x -= gui_GetContentOffsetX();
00350   mypt.y -= gui_GetContentOffsetY();
00351 
00352   // ask the contained polynomial to set the cursor
00353   int r = data_GetContent().gui_MoveCursorUsingPoint(hDC, mypt);
00354   if (r == mcMCR_CANNOT_SETFOCUS)
00355    return mcMCR_CANNOT_SETFOCUS;
00356 
00357   // ok, now the cursor is inside content
00358   mgui_nCursorPos = mcEXPCONTAINER_INSIDEEXPR;  
00359   return mcMCR_OKAY;
00360  }
00361  
00362  // do we have to set cursor on the container symbols ?
00363  if (mypt.x < gui_GetContentOffsetX() && gui_isLeftPosEnabled()) {
00364   mgui_nCursorPos = mcEXPCONTAINER_LEFTMOST;
00365   return mcMCR_OKAY;
00366  }
00367  if (mypt.x > gui_GetContentOffsetX()+rc.GetWidth() && gui_isRightPosEnabled()) {
00368   mgui_nCursorPos = mcEXPCONTAINER_RIGHTMOST;
00369   return mcMCR_OKAY;
00370  }
00371 
00372  return mcMCR_CANNOT_SETFOCUS;
00373 }
00374 
00375 int mcExpContainerHelpers::gui_GetBaseRelCursorPos(wxDC &hDC, wxPoint *pt) const
00376 {
00377  int n;
00378  
00379  switch (mgui_nCursorPos) {
00380  case mcEXPCONTAINER_LEFTMOST:
00381   pt->x = 0;
00382   pt->y = 0;
00383 
00384   // use global obj height as cursor height
00385   return gui_GetBaseSize().GetHeight();
00386   
00387  case mcEXPCONTAINER_INSIDEEXPR:
00388   n = data_GetContent().gui_GetRelCursorPos(hDC, pt);
00389   pt->x += gui_GetContentOffsetX();
00390   pt->y += gui_GetContentOffsetY();
00391 
00392   // use content height as cursor height
00393   return n;
00394   
00395  case mcEXPCONTAINER_RIGHTMOST:
00396   pt->x = gui_GetBaseSize().GetWidth();
00397   pt->y = 0;
00398 
00399   // use global obj height as cursor height
00400   return gui_GetBaseSize().GetHeight();
00401  }
00402  
00403  // when cursor is inside exponent, mcExpElement functions
00404  // handle the gui_GetRelCursorPos function call
00405  mcASSERT(0, wxT("Unhandled cursor position"));
00406  
00407  // just to make compiler happy
00408  return 0;
00409 }
00410 
00411 void mcExpContainerHelpers::gui_GetBaseCursorPos(mcCursorPos &cp) const
00412 {
00413  if (mgui_nCursorPos == mcEXPCONTAINER_LEFTMOST)
00414   cp.gui_Push(mcCP_BEGIN);
00415  else if (mgui_nCursorPos == mcEXPCONTAINER_RIGHTMOST)
00416   cp.gui_Push(mcCP_END);
00417  else
00418   cp.gui_Push(mgui_nCursorPos);
00419 }
00420 
00421 void mcExpContainerHelpers::gui_SetBaseCursorPos(const mcCursorPos &n)
00422 {
00423  if (n.isBegin()) {
00424   if (gui_isLeftPosEnabled())
00425    mgui_nCursorPos = mcEXPCONTAINER_LEFTMOST;
00426   else {
00427    mgui_nCursorPos = mcEXPCONTAINER_INSIDEEXPR;
00428    data_GetContent().gui_SetCursorPos(mcCP_BEGIN);
00429   }
00430  }
00431 
00432  if (n.isEnd()) {
00433   if (gui_isRightPosEnabled())
00434    mgui_nCursorPos = mcEXPCONTAINER_RIGHTMOST; 
00435   else {
00436    mgui_nCursorPos = mcEXPCONTAINER_INSIDEEXPR;
00437    data_GetContent().gui_SetCursorPos(mcCP_END);
00438   }
00439  }
00440 }
00441 
00442 int mcExpContainerHelpers::gui_GetYAnchor() const
00443 {
00444  return gui_GetContentOffsetY() + gui_GetBaseOffsety() + 
00445   data_GetContent().gui_GetYAnchor();
00446 }
00447 
00448 
00449 
00450 
00451 // ----------------------------------------
00452 // mcEXPCONTAINERIO
00453 // ----------------------------------------
00454 
00455 wxXml2Node mcExpContainerHelpers::io_GetBaseMathML(bool bGetPresentation) const
00456 {
00457  wxXml2Node maintag(wxXML_ELEMENT_NODE, wxXml2EmptyDoc, io_GetMathMLPresentationTag());
00458  wxXml2Node child = data_GetContent().io_GetMathML(bGetPresentation);
00459  maintag.AddChild(child);
00460 
00461  return maintag;
00462 }
00463 
00464 bool mcExpContainerHelpers::io_ImportPresentationMathML(wxXml2Node tag, wxString &pErr)
00465 {
00466  mcASSERT(tag.GetName() == io_GetMathMLPresentationTag(), 
00467       wxT("Error in mcExpContainerHelpers::io_isBeginTag"));
00468  
00469  // the child of this node should be imported by m_eContent
00470  wxXml2Node child = tag.GetChildren();
00471  if (child.GetNext() != wxXml2EmptyNode) {
00472   
00473   // this tag contains more than one child; pack them in an MROW
00474   child.Encapsulate(wxT("mrow"));
00475   }
00476  
00477  return data_GetContent().io_ImportPresentationMathML(child, pErr);
00478 }
00479 
00480 
00481 
00482 
00483 
00484 // ----------------------------------------
00485 // mcEXPCONTAINERMATH
00486 // ----------------------------------------
00487 
00488 bool mcExpContainerHelpers::math_CompareThisOnly(const mcElement &p, long flags) const
00489 {
00490  if (p.data_GetType() == data_GetType()) {
00491 
00492   // ok, the given element has this same type...
00493   // now check contents
00494   const mcPolynomial &pcontents = mcExpContainer(p).data_GetConstContent();
00495 
00496   if (pcontents.math_Compare(data_GetContent(), flags))
00497    return TRUE;
00498  }
00499 
00500  return FALSE;
00501 }
00502 
00503 bool mcExpContainerHelpers::math_CanBeAddedWith(const mcElement &p) const
00504 {
00505  // first of all, check the element type
00506  if (p.data_GetType() != data_GetType())
00507   return FALSE;
00508 
00509  mcExpContainer e(p);
00510  const mcPolynomial &content = e.data_GetContent();
00511  return data_GetContent().math_CanBeAddedWith(content);
00512 }
00513 
00514 bool mcExpContainerHelpers::math_CanBeDivBy(const mcElement &p) const
00515 {
00516  // first of all, check the element type
00517  if (p.data_GetType() != data_GetType())
00518   return FALSE;
00519 
00520  mcExpContainer e(p);
00521  const mcPolynomial &content = e.data_GetConstContent();
00522  return data_GetContent().math_CanBeDivBy(content);
00523 }
00524 
00525 bool mcExpContainerHelpers::math_CanBeMultWith(const mcElement &p) const
00526 {
00527  // first of all, check the element type
00528  if (p.data_GetType() != data_GetType())
00529   return FALSE;
00530 
00531  mcExpContainer e(p);
00532  const mcPolynomial &content = e.data_GetContent();
00533  return data_GetContent().math_CanBeMultWith(content);
00534 }
00535 
00536 mcPolynomial mcExpContainerHelpers::math_GetRaisedContents() const
00537 {
00538  mcPolynomial res(data_GetContent());
00539  if (!math_hasExp()) return res;
00540 
00541  // raise the polynomial to the exponent we contain:
00542  // mcPolynomial implements the full algorithm
00543  res.math_RaiseTo(math_GetExp()); 
00544  
00545  return res;
00546 }
00547 
00548 mcExpSimRes mcExpContainerHelpers::math_SimplifyBaseExp(long flags, mcElement *pnew)
00549 {
00550  mcMATHLOG(wxT("mcExpContainerHelpers::math_SimplifyBaseExp [%s]"), mcTXTTHIS);
00551 
00552  // it does make sense to raise our contents only if they can
00553  // be raised by our exponent: if they cannot and we still
00554  // call the mcPolynomialHelpers::math_RaiseTo function,
00555  // the polynomial would create a mcBracket inside it with
00556  // the exponent we gave it... this would be useless !
00557  if (!data_GetContent().math_CanBeRaisedTo(math_GetExp()) ||
00558   (flags & mcEXPSIM_KEEP_FACTORIZATION))
00559   return mcESR_DONE;
00560 
00561  // if contents are completely simplified, we can remove this
00562  // container and replace it with its contents raised to the
00563  // exponent of this container
00564  data_GetContent().math_RaiseTo(math_GetExp());
00565  data_DestroyExpSub(TRUE);
00566 
00567  return mcESR_NOTFINISHED;
00568 }
00569 
00570 mcExpSimRes mcExpContainerHelpers::math_SimplifyBase(long flags, mcElement *newelem)
00571 {
00572  // simplify contents
00573  mcExpSimRes res = data_GetContent().math_Simplify(flags, newelem);
00574  if (res != mcESR_DONE) return res;
00575 
00576  // now, try to simplify this element with the simplified contents...
00577  return math_SimplifyContents(flags, newelem);
00578 }
00579 
00580 mcExpSimRes mcExpContainerHelpers::math_ExpandBase(long flags, mcElement *newelem)
00581 {
00582  // expand contents
00583  mcExpSimRes res = data_GetContent().math_Expand(flags, newelem);
00584  if (res != mcESR_DONE) return res;
00585 
00586  // now, try to simplify this element with the simplified contents...
00587  return math_ExpandContents(flags, newelem);
00588 }
00589 
00590 mcBasicOpRes mcExpContainerHelpers::math_DivideBaseOnlyBy(const mcElement &p, mcElement *pp)
00591 {
00592  if (p.data_GetType() != data_GetType()) return mcBOR_INVALID;
00593  mcExpContainer e(p);
00594  return data_GetContent().math_DivideBy(e.data_GetContent(), pp);
00595 }
00596 
00597 mcBasicOpRes mcExpContainerHelpers::math_Add(const mcElement &p, mcElement *pp, bool add)
00598 {
00599  if (p.data_GetType() != data_GetType()) return mcBOR_INVALID;
00600  mcExpContainer e(p);
00601  return data_GetContent().math_Add(e.data_GetContent(), pp, add);
00602 }
00603 /*
00604 mcBasicOpRes mcExpContainerHelpers::math_Subtract(const mcElement &p, mcElement *pp)
00605 {
00606  if (p.data_GetType() != hlp().data_GetType()) return mcBOR_INVALID;
00607  mcExpContainer *e = (mcExpContainer *)p;
00608  return data_GetContent().math_Subtract(e.data_GetContent(), pp);
00609 }*/
00610 
00611 mcBasicOpRes mcExpContainerHelpers::math_MultiplyBaseOnlyBy(const mcElement &p, mcElement *pp)
00612 {
00613  if (p.data_GetType() != data_GetType()) return mcBOR_INVALID;
00614  mcExpContainer e(p);
00615  return data_GetContent().math_MultiplyBy(e.data_GetContent(), pp);
00616 }
00617 
00618 mcMonomial mcExpContainerHelpers::math_GetFactors() const
00619 { return data_GetContent().math_GetFactors(); }
00620 


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

[ Top ]