Main Page | Namespace List | Class Hierarchy | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

CSHTMLPanel.cpp

Go to the documentation of this file.
00001 // next todo:
00002 // try to display only the stuff that might actually go on the screen
00003 // (Performance upgrade tha is)
00004 
00005 #ifdef WIN32
00006 #pragma warning(disable : 4786 )
00007 #endif
00008 
00009 #include "CSHTMLPanel.h"
00010 #include "CSFont.h"
00011 #include "CSDesktop.h"
00012 #include "CSWindow.h"
00013 #include "CSLAF.h"
00014 #include "CSHelper.h"
00015 #include "CSHTMLElement.h"
00016 
00017 const char *CSHTMLPanel::CLASS = "CSHTMLPanel";
00018 
00019 // htmlPanel
00020 // to possible uses - 
00021 // 1. as a "static" sized "texarea"-like field within some other component
00022 //    eg: //    CSHTMLPanel *html2 = new CSHTMLPanel(100, 100, "index.html");
00023 //              window->addElement(html2, 200,20);
00024 //    a mini sized htmlarea (100x100)
00025 //
00026 // 2. or autosizing within a window
00027 //      CSHTMLPanel *html = new CSHTMLPanel(150, 300, "index.html");
00028 //      html->setElementAutoSizing(true);
00029 //      window->addElement(html, POSITION_CENTER);
00030 //
00031 //      (The given size in the constructor is ignored!)
00032 //      (Remember to switch autosizing on!)
00033 //      (Remember also to tell the window the kind of posotioning, absolut
00034 //       positioning is not supported with autosizing)
00035 //
00036 // Only Files on a local system are supported
00037 // no http: ... 
00038 // without protokoll, just plain and simple the filename!
00039 CSHTMLPanel::CSHTMLPanel(int height, int width, const std::string &filename) 
00040 : CSGrafikElement(height, width)
00041 {
00042     static char *functionName="CSHTMLPanel";
00043     LOG_ENTER 
00044     initHTMLPanel();
00045     setPage(filename);
00046     LOG_EXIT
00047 }
00048 
00049 CSHTMLPanel::~CSHTMLPanel() 
00050 {
00051     if (mMessageBox)
00052     {
00053         delete mMessageBox;
00054         mMessageBox = 0;
00055     }
00056     deleteOldPage();
00057 }
00058 
00059 void CSHTMLPanel::initHTMLPanel()
00060 {
00061     static char *functionName="initHTMLPanel";
00062     LOG_ENTER 
00063     CSLAF *laf = CSLAF::getCurrentLAF();
00064     mMessageBox = 0;
00065     mBaseDirectory = "";
00066     mHelper = 0;
00067     mHTMLHeightInPixel = 0;
00068     mHTMLWidthInPixel = 0;
00069     mCleared = true;
00070     addMessageListener(this, GUI_MESSAGE);
00071 
00072     CSLayoutManagerXY *layoutManager = new CSLayoutManagerXY();
00073 
00074     
00075     // only accept changes if component is resized
00076     // all other changes are discarded
00077     // adding components does not trigger resize!
00078     // therefore we can build html elements
00079     // inside without triggering changes
00080     // which would result in an etnernal changes - loop
00081     layoutManager->setPropagateSizeChangesOnly(true);
00082     setLayoutManager(layoutManager);
00083     
00084     rebuildElement();
00085 
00086     CSLayoutData layout = getLayoutData();
00087     layout.setCenteredHorizontal(true);
00088     layout.setCenteredVertical(true);
00089     layout.setStretchedHorizontal(true);
00090     layout.setStretchedVertical(true);
00091     layout.setPosition(POSITION_CENTER);
00092     setLayoutData(layout);
00093     setInset(CSInset(0));
00094     LOG_EXIT
00095 }
00096 
00097 void CSHTMLPanel::deleteOldPage()
00098 {
00099     if (mHelper != 0)
00100     {
00101         delete mHelper;
00102         mHelper = 0;
00103     }
00104     HTMLElements::iterator iter;
00105     for (iter = mHTMLElements.begin(); iter != mHTMLElements.end();)
00106     {
00107         HTMLElement *element = *iter;
00108         mHTMLElements.erase(iter);
00109         delete element;
00110         iter = mHTMLElements.begin();
00111     }
00112     mHTMLHeightInPixel = 0;
00113     mHTMLWidthInPixel = 0;
00114 }
00115 
00116 // extracts leading PATHs from a filename and rememebers the
00117 // path (for relative links to work correctly)
00118 std::string CSHTMLPanel::getBaseDirectory(const std::string &filename)
00119 {
00120     // searching for "/"
00121     char *posStart = strrchr(filename.c_str(), '/');
00122     if (posStart != 0)
00123     {
00124         std::string newText = filename.substr(0, (posStart - filename.c_str()+1));
00125         return newText;
00126     }
00127     posStart = strrchr(filename.c_str(), '\\');
00128     if (posStart != 0)
00129     {
00130         std::string newText = filename.substr(0, (posStart - filename.c_str()+1));
00131         return newText;
00132     }
00133     return "";
00134 }
00135 
00136 // extract the anker from a given filename (startinng with # after the filename)
00137 // the filename is truncated!
00138 std::string CSHTMLPanel::extractAnker(std::string &filename)
00139 {
00140     // searching for "#"
00141     char *posStart = strrchr(filename.c_str(), '#');
00142     if (posStart != 0)
00143     {
00144         std::string newFilename = filename.substr(0, (posStart - filename.c_str()));
00145         std::string anker = filename.substr((posStart - filename.c_str())+1, filename.size());
00146         filename = newFilename;
00147         return anker;
00148     }
00149     return "";
00150 }
00151 
00152 // load a new page
00153 // or keep the old one upon an error
00154 void CSHTMLPanel::setPage(const std::string &filename)
00155 {
00156     static char *functionName="setPage";
00157 
00158     // filename handling
00159     // Anker and Bases...
00160     CSHTMLHelper *helper;
00161     std::string newFilename = filename;
00162     std::string anker = extractAnker(newFilename);
00163     helper = new CSHTMLHelper(newFilename);
00164     if (helper->getError() != CSHTML_OK)
00165     {
00166         delete helper;
00167         helper = 0;
00168         
00169         newFilename = mBaseDirectory + filename;
00170         anker = extractAnker(newFilename);
00171         helper = new CSHTMLHelper(newFilename);
00172         if (helper->getError() != CSHTML_OK)
00173         {
00174             delete helper;
00175             helper = 0;
00176             if (mMessageBox)
00177             {
00178                 removeFrontElement(mMessageBox);
00179                 delete mMessageBox;
00180                 mMessageBox = 0;
00181             }
00182             mMessageBox = new CSMessageBox("Error loading Page:\n"+filename, "Error loading html page!", ERROR_ICON);
00183             if (mMessageBox)
00184             {
00185                 addFrontElementCenter(mMessageBox);
00186                 mMessageBox->setVisible(true);
00187             }
00188 
00189             return;
00190         }
00191     }
00192     mBaseDirectory = getBaseDirectory(newFilename);
00193     deleteOldPage();
00194     mHelper = helper;
00195     mFilename = filename;
00196     CSHTMLNode node = mHelper->getRootNode();
00197 
00198     // from the root node
00199     // all other nodes are recursivly created!
00200     HTMLElement *element = new HTMLElement(node);
00201     mHTMLElements.push_back(element);
00202     mHTMLHeightInPixel = 0;
00203     mHTMLWidthInPixel = 0;
00204     CSWindow *window = getParentWindow();
00205 
00206     // if we have an anker we start there
00207     // by setting the scroll offsets likewise
00208 //  if (anker.size()>0)
00209 //  {
00210 //      startAtAnker(anker);
00211 //  }
00212 //  else
00213     {
00214         if (window)
00215         {
00216             window->setVerticalDisplayStart(0);
00217             window->setHorizontalDisplayStart(0);
00218 //          setViewportOffset(0,0);
00219 //          getParent()->setViewportOffset(0,0);
00220         }
00221     }
00222     layoutChanged(true);
00223 }
00224 
00225 //! \todo html area only painting in the specified region, not everything and clippin!
00226 // paint with 0 surface means no painting, just counting!
00227 void CSHTMLPanel::paint(SDL_Surface *destination, SDL_Rect *parentViewport)
00228 {
00229     static char *functionName="paint";
00230     paintChildren(destination, parentViewport);
00231 }
00232 
00233 void CSHTMLPanel::reactOnMessage(CSMessage *message)
00234 {
00235     reactOnMessageHTMLPanel(message);
00236 }
00237 
00238 void CSHTMLPanel::reactOnMessageHTMLPanel(CSMessage *message)
00239 {
00240     static char *functionName="reactOnMessage";
00241     if (message->mIsHandled)
00242     {
00243         reactOnMessageGrafikElement(message);
00244         return;
00245     }
00246     switch (message->getType())
00247     {
00248         case GUI_MESSAGE:
00249         {
00250             GuiMessage *gm = (GuiMessage *) message;
00251             if (gm->receiver != this)
00252             {
00253             }
00254             else // receiver == this
00255             {
00256                 switch (message->getSubtype())
00257                 {
00258                     // some link to set?
00259                     case MOUSE_BUTTON_PRESSED_MESSAGE:
00260                     {
00261                         int x,y;
00262                         x = gm->receiverX;
00263                         y = gm->receiverY;
00264                         
00265                         HTMLElements::iterator iter;
00266                         for (iter = mHTMLElements.begin(); iter != mHTMLElements.end(); iter++)
00267                         {
00268                             HTMLElement *checked = (*iter)->checkPostion(x - getViewportX() ,y - getViewportY());
00269                             if (checked != 0)
00270                             {
00271                                 // clicked on a link?
00272                                 HTMLElement *linkNode = checked->getAncestorType(HTML_A);
00273                                 if (linkNode)
00274                                 {
00275                                     // yop - try trying to get it!
00276                                     // open new page
00277                                     std::string linkValue = linkNode->getAttributValue("HREF");
00278                                     if (linkValue.size() != 0)
00279                                     {
00280                                         setPage(linkValue);
00281                                         break;
00282                                     }
00283                                 }
00284                             }
00285                         }
00286                         gm->mIsHandled = true;
00287                         break;
00288                     }
00289                 }
00290             }                       
00291         }
00292     }
00293     reactOnMessageGrafikElement(message);
00294 }
00295 
00296 // search thru all nodes for the body and extact
00297 // the background color information
00298 // not REALLY nice - but have you got an better idea?
00299 // -1 is not set
00300 // -2 is error in BODY (or not found at all)
00301 int CSHTMLPanel::getBackgroundColorHTML()
00302 {
00303     HTMLElement *bodyElement = 0;
00304     int value = -1;
00305     HTMLElements::iterator iter;
00306     for (iter = mHTMLElements.begin(); iter != mHTMLElements.end(); iter++)
00307     {
00308         HTMLElement *element = *iter;
00309         bodyElement = element->getChildType(HTML_BODY, "", "");
00310         if (bodyElement)
00311         {
00312             std::string bgColor = bodyElement->getAttributValue("BGCOLOR");
00313             value = bodyElement->getColorFromString(bgColor);
00314             break;
00315         }
00316     }
00317     if (value == -1)
00318     {
00319         CSLAF *laf = CSLAF::getCurrentLAF();
00320         value = laf->getBackgroundColorEnabled(CSWindow::CLASS);
00321     }
00322     return value;
00323 }
00324 
00325 // sat the scrollbar position so that we start at the anker!
00326 void CSHTMLPanel::startAtAnker(const std::string &anker)
00327 {
00328     HTMLElement *ankerElement = 0;
00329 
00330     HTMLElements::iterator iter;
00331     for (iter = mHTMLElements.begin(); iter != mHTMLElements.end(); iter++)
00332     {
00333         HTMLElement *element = *iter;
00334         ankerElement = element->getChildType(HTML_A, "NAME", anker);
00335         if (ankerElement)
00336         {
00337             break;
00338         }
00339     }
00340 
00341     CSWindow *window = getParentWindow();
00342     if ((ankerElement) && (window))
00343     {
00344         int y = ankerElement->getFirstYPostion();
00345         if (y != -1)
00346         {
00347             window->setVerticalDisplayStart(y);
00348             window->setHorizontalDisplayStart(0);
00349         }
00350     }
00351 }
00352 
00353 // in pixel, since there might be pictures as well!
00354 // we do a "dummy" paint of the complete site and
00355 // look how much virtual space we might have used!
00356 // this is quite time expansive
00357 // therefor the information is kept in two 
00358 // variables:
00359 //      mHTMLWidthInPixel;
00360 //      mHTMLHeightInPixel;
00361 // only when these are set to 0 (either or both)
00362 //
00363 // the width an the height will be recalculated
00364 void CSHTMLPanel::getHTMLSize(int &w, int &h)
00365 {
00366     static char *functionName="getVerticalHTMLSize";
00367 //  if ((mHTMLHeightInPixel != 0) && (mHTMLWidthInPixel != 0))
00368 //  {
00369 //      w = mHTMLWidthInPixel;
00370 //      h = mHTMLHeightInPixel;
00371 //      return;
00372 //  }
00373     clearElements();
00374     CSLAF *laf = CSLAF::getCurrentLAF();
00375 
00376     int x = 0;
00377     int y = 0;
00378 
00379     // area without parent offsets is ok, since we don't actually put anything on the screen
00380     // just the area is interesting!
00381     SDL_Rect thisViewportArea = getViewportArea();
00382     CSGrafikElement *parent = getParent();
00383     if (parent)
00384     {
00385         thisViewportArea = parent->getViewportArea();
00386         thisViewportArea.w-=30; // 30 is dirty, should be size of scrollbar!
00387         thisViewportArea.h-=30;
00388 
00389         // if < 0 than reset to 0
00390         if (thisViewportArea.w > 60000)
00391         {
00392             thisViewportArea.w = 0;
00393         }
00394         if (thisViewportArea.h < 60000)
00395         {
00396             thisViewportArea.h = 0;
00397         }
00398     }
00399 
00400     HTMLCursor htmlCursor;
00401     htmlCursor.mXPos = 0;
00402     htmlCursor.mYPos = 0;
00403     htmlCursor.mStyle = 0;
00404     htmlCursor.mFont = getFont();
00405     htmlCursor.mXPosMax = 0;
00406     htmlCursor.nextAdd = htmlCursor.mFont->getHeight(); 
00407     HTMLElements::iterator iter;
00408     for (iter = mHTMLElements.begin(); iter != mHTMLElements.end(); iter++)
00409     {
00410         std::string title = "";
00411         HTMLElement *element = *iter;
00412         // paint with 0 surface means no painting, just counting!
00413         htmlCursor = element->buildDisplay(htmlCursor, 0, thisViewportArea.w, title);
00414     }
00415 
00416     // if the parent viewport is smaller than the largest html element
00417     // the parent viewport is not the correct value for width of layout
00418     // relayout the page with the correct value
00419     // parent window will add a scrollbar!
00420     if (thisViewportArea.w < htmlCursor.mXPosMax)
00421     {
00422         thisViewportArea.w = htmlCursor.mXPosMax-30;
00423         clearElements();
00424         htmlCursor.mXPos = 0;
00425         htmlCursor.mYPos = 0;
00426         htmlCursor.mStyle = 0;
00427         htmlCursor.mFont = getFont();
00428         htmlCursor.mXPosMax = 0;
00429         htmlCursor.nextAdd = htmlCursor.mFont->getHeight(); 
00430         for (iter = mHTMLElements.begin(); iter != mHTMLElements.end(); iter++)
00431         {
00432             std::string title = "";
00433             HTMLElement *element = *iter;
00434             // paint with 0 surface means no painting, just counting!
00435             htmlCursor = element->buildDisplay(htmlCursor, 0, thisViewportArea.w, title);
00436         }
00437     }
00438     
00439     h = mHTMLHeightInPixel = htmlCursor.mYPos + htmlCursor.mFont->getHeight();
00440     w = mHTMLWidthInPixel = htmlCursor.mXPosMax;
00441 }
00442 
00443 void CSHTMLPanel::rebuildElement()
00444 {
00445     // befor we calculate the new viewport size
00446     // we have to remove the scrollbars
00447     // otherwise the viewport width might calculated wrongly
00448     // (when setHeight/setWidth of parent ist called, the scrollbar sizes are
00449     //  added (when removed) to the new size - but the new size never knew
00450     //  of the scrollbars in first place)
00451 
00452     // the size of the viewport changes if a scrollbar is added -> every size might change...
00453     // looks like ping pong - but is a must :-(
00454 }
00455 
00456 void CSHTMLPanel::clearElements()
00457 {
00458     HTMLElements::iterator iter;
00459     for (iter = mHTMLElements.begin(); iter != mHTMLElements.end(); iter++)
00460     {
00461         HTMLElement *element = *iter;
00462         element->clearPosition();
00463     }
00464     deleteElements();
00465     mCleared = true;
00466 }
00467 
00468 // if an element is autosizing -> it is notified by calling changeDisplayLayout!
00469 // that means we have something to do if we are autosizing!
00470 void CSHTMLPanel::layoutSetupHTMLPanel()
00471 {
00472     static char *functionName="layoutSetupHTMLPanel";
00473     LOG_ENTER 
00474     CSLAF *laf = CSLAF::getCurrentLAF();
00475 
00476     // clear all compiled or collected information - 
00477     // we have to start anew
00478     getHTMLSize(mMinWidth, mMinHeight);
00479     clearElements();
00480     
00481     if (mCleared)
00482     {
00483         // set up the starting cursor!
00484         HTMLCursor htmlCursor;
00485         htmlCursor.mBackgroundColor = getBackgroundColor();
00486         htmlCursor.mXPos = 0;
00487         htmlCursor.mYPos = 0;
00488         htmlCursor.mXPosMax = 0;
00489 
00490         htmlCursor.mFont = getFont();
00491         htmlCursor.nextAdd = htmlCursor.mFont->getHeight(); 
00492 
00493         // and paint all elements recursivly
00494         // Insets not respected -> doesn't matter if Insets stay at 0
00495         HTMLElements::iterator iter;
00496         for (iter = mHTMLElements.begin(); iter != mHTMLElements.end(); iter++)
00497         {
00498             std::string title = "";
00499             HTMLElement *element = *iter;
00500             htmlCursor = element->buildDisplay(htmlCursor, this, getViewportWidth(), title);
00501             if (title.size() >0)
00502             {
00503                 CSWindow *window = getParentWindow();
00504                 if (window)
00505                 {
00506                     window->setTitle(title);
00507                 }
00508             }
00509         }
00510         mCleared = false;
00511     }
00512         
00513     setBackgroundColor(getBackgroundColorHTML());
00514 }

Generated on Wed Jul 14 00:43:30 2004 for CSLib by doxygen 1.3.6