TGHtmlIndex.cxx

Go to the documentation of this file.
00001 // $Id: TGHtmlIndex.cxx,v 1.2 2007/05/20 23:22:13 rdm Exp $
00002 // Author:  Valeriy Onuchin   03/05/2007
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2001, Rene Brun, Fons Rademakers and Reiner Rohlfs *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 /**************************************************************************
00013 
00014     HTML widget for xclass. Based on tkhtml 1.28
00015     Copyright (C) 1997-2000 D. Richard Hipp <drh@acm.org>
00016     Copyright (C) 2002-2003 Hector Peraza.
00017 
00018     This library is free software; you can redistribute it and/or
00019     modify it under the terms of the GNU Library General Public
00020     License as published by the Free Software Foundation; either
00021     version 2 of the License, or (at your option) any later version.
00022 
00023     This library is distributed in the hope that it will be useful,
00024     but WITHOUT ANY WARRANTY; without even the implied warranty of
00025     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00026     Library General Public License for more details.
00027 
00028     You should have received a copy of the GNU Library General Public
00029     License along with this library; if not, write to the Free
00030     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00031 
00032 **************************************************************************/
00033 
00034 // Routines that deal with indexes
00035 
00036 #include <ctype.h>
00037 #include <string.h>
00038 #include <stdlib.h>
00039 
00040 #include "TGHtml.h"
00041 
00042 
00043 //______________________________________________________________________________
00044 TGHtmlElement *TGHtml::TokenByIndex(int N, int /*flag*/)
00045 {
00046    // Return a pointer to the Nth TGHtmlElement in the list. If there
00047    // is no Nth element, return 0 if flag==0 and return either the first
00048    // or last element (whichever is closest) if flag!=0
00049 
00050    TGHtmlElement *p;
00051    int n;
00052 
00053    if (N == 0) return fPFirst;
00054 
00055    if (N > fNToken / 2) {
00056       // Start at the end and work back toward the beginning
00057       for (p = fPLast, n = fNToken; p; p = p->fPPrev) {
00058          if (p->fType != Html_Block) {
00059             if (p->fElId == N) break;
00060             --n;
00061          }
00062       }
00063    } else {
00064       // Start at the beginning and work forward
00065       for (p = fPFirst; p; p = p->fPNext) {
00066          if (p->fType != Html_Block) {
00067             --N;
00068             if (N == p->fElId) break;
00069          }
00070       }
00071    }
00072 
00073    return p;
00074 }
00075 
00076 //______________________________________________________________________________
00077 int TGHtml::TokenNumber(TGHtmlElement *p)
00078 {
00079    // Return the token number for the given TGHtmlElement
00080 
00081    //int n = 0;
00082 
00083    if (!p) return -1;
00084    return p->fElId;
00085 
00086 ///  while (p) {
00087 ///    if (p->fType != Html_Block) ++n;
00088 ///    p = p->fPPrev;
00089 ///  }
00090 ///
00091 ///  return n;
00092 }
00093 
00094 //______________________________________________________________________________
00095 void TGHtml::MaxIndex(TGHtmlElement *p, int *pIndex, int isLast)
00096 {
00097    // Find the maximum index for the given token
00098 
00099    if (p == 0) {
00100       *pIndex = 0;
00101    } else {
00102       switch (p->fType) {
00103          case Html_Text:
00104             *pIndex = p->fCount - isLast;
00105             break;
00106 
00107          case Html_Space:
00108             if (p->fStyle.fFlags & STY_Preformatted) {
00109                *pIndex = p->fCount - isLast;
00110             } else {
00111                *pIndex = 0;
00112             }
00113             break;
00114 
00115          default:
00116             *pIndex = 0;
00117             break;
00118       }
00119    }
00120 }
00121 
00122 //______________________________________________________________________________
00123 void TGHtml::FindIndexInBlock(TGHtmlBlock *pBlock, int x,
00124                               TGHtmlElement **ppToken, int *pIndex)
00125 {
00126    // Given a Block and an x coordinate, find the Index of the character
00127    // that is closest to the given x coordinate.
00128    //
00129    // The x-coordinate might specify a point to the left of the block,
00130    // in which case the procedure returns the first token and a character
00131    // index of 0.  Or the x-coordinate might specify a point to the right
00132    // of the block, in which case the last token is returned with an index
00133    // equal to its last character.
00134 
00135    TGHtmlElement *p;
00136    TGFont *font;
00137    int len;
00138    int n;
00139 
00140    p = pBlock->fPNext;
00141    font = GetFont(p->fStyle.fFont);
00142    if (x <= pBlock->fLeft) {
00143       *ppToken = p;
00144       *pIndex = 0;
00145       return;
00146    } else if (x >= pBlock->fRight) {
00147       *ppToken = p;
00148       *pIndex = 0;
00149       while (p && p->fType != Html_Block) {
00150          *ppToken = p;
00151          p = p->fPNext;
00152       }
00153       p = *ppToken;
00154       if (p && p->fType == Html_Text) {
00155          *pIndex = p->fCount - 1;
00156       }
00157       return;
00158    }
00159    if (pBlock->fN == 0) {
00160       *ppToken = p;
00161       *pIndex = 0;
00162    }
00163    n = font->MeasureChars(pBlock->fZ, pBlock->fN, x - pBlock->fLeft, 0, &len);
00164    *pIndex = 0;
00165    *ppToken = 0;
00166    while (p && n >= 0) {
00167       switch (p->fType) {
00168          case Html_Text:
00169             if (n < p->fCount) {
00170                *pIndex = n;
00171             } else {
00172                *pIndex = p->fCount - 1;
00173             }
00174             *ppToken = p;
00175             n -= p->fCount;
00176             break;
00177 
00178          case Html_Space:
00179             if (p->fStyle.fFlags & STY_Preformatted) {
00180                if (n < p->fCount) {
00181                   *pIndex = n;
00182                } else {
00183                   *pIndex = p->fCount - 1;
00184                }
00185                *ppToken = p;
00186                n -= p->fCount;
00187             } else {
00188                *pIndex = 0;
00189                *ppToken = p;
00190                --n;
00191             }
00192             break;
00193 
00194          default:
00195             break;
00196       }
00197       if (p) p = p->fPNext;
00198    }
00199 }
00200 
00201 //______________________________________________________________________________
00202 void TGHtml::IndexToBlockIndex(SHtmlIndex_t sIndex,
00203                                TGHtmlBlock **ppBlock, int *piIndex)
00204 {
00205    // Convert an Element-based index into a Block-based index.
00206    //
00207    // In other words, given a pointer to an element and an index
00208    // of a particular character within that element, compute a
00209    // pointer to the TGHtmlBlock used to display that character and
00210    // the index in the TGHtmlBlock of the character.
00211 
00212    int n = sIndex.fI;
00213    TGHtmlElement *p;
00214 
00215    if (sIndex.fP == 0) {
00216       *ppBlock = 0;
00217       *piIndex = 0;
00218       return;
00219    }
00220    p = sIndex.fP->fPPrev;
00221    while (p && p->fType != Html_Block) {
00222       switch (p->fType) {
00223          case Html_Text:
00224             n += p->fCount;
00225             break;
00226          case Html_Space:
00227             if (p->fStyle.fFlags & STY_Preformatted) {
00228                n += p->fCount;
00229             } else {
00230                n++;
00231             }
00232             break;
00233          default:
00234             break;
00235       }
00236       p = p->fPPrev;
00237    }
00238    if (p) {
00239       *ppBlock = (TGHtmlBlock *) p;
00240       *piIndex = n;
00241       return;
00242    }
00243    for (p = sIndex.fP; p && p->fType != Html_Block; p = p->fPNext) {}
00244    *ppBlock = (TGHtmlBlock *) p;
00245    *piIndex = 0;
00246 }
00247 
00248 //______________________________________________________________________________
00249 int TGHtml::IndexMod(TGHtmlElement **pp, int *ip, char *cp)
00250 {
00251    // Modify an index for both pointer and char +/-/=N
00252 
00253    char nbuf[50];
00254    int i, x, cnt, ccnt[2], cflag[2];
00255 
00256    if (pp == 0 || !*pp) return -1;
00257    ccnt[0] = ccnt[1] = cflag[0] = cflag[1] = 0;
00258    x = 0;
00259    while (*cp && x < 2) {
00260       cnt = 0;
00261       i = 1;
00262       while (i < 45 && isdigit(cp[i])) {
00263          nbuf[i-1] = cp[i];
00264          i++;
00265       }
00266       if (i > 1) {
00267          nbuf[i-1] = 0;
00268          cnt = atoi(nbuf);
00269          if (cnt < 0) return -1;
00270       }
00271       switch (*cp) {
00272          case '+': if (i == 1) ccnt[x] = 1; else ccnt[x] = cnt; break;
00273          case '-': if (i == 1) ccnt[x] = -1; else ccnt[x] = -cnt; break;
00274          case '=': ccnt[x] = 0; cflag[x] = 1; break;
00275          default: return -1;
00276       }
00277       cp += i;
00278       ++x;
00279    }
00280    if (ccnt[0] > 0) {
00281       for (i = 0; i < ccnt[0] && (*pp)->fPNext; ++i) {
00282          *pp = (*pp)->fPNext;
00283          while ((*pp)->fType == Html_Block && (*pp)->fPNext) {
00284             *pp = (*pp)->fPNext;
00285          }
00286       }
00287    } else if (ccnt[0] < 0) {
00288       for (i = 0; ccnt[0] < i && (*pp)->fPPrev; --i) {
00289          //printf("i=%d, cnt=%d\n", i, ccnt[0]);
00290          *pp = (*pp)->fPPrev;
00291          while ((*pp)->fType == Html_Block && (*pp)->fPPrev) {
00292             *pp = (*pp)->fPPrev;
00293          }
00294       }
00295    }
00296    if (ccnt[1] > 0) {
00297       for (i = 0; i < ccnt[1]; ++i) (*ip)++;
00298    } else if (ccnt[1] < 0) {
00299       for (i = 0; i > ccnt[1]; --i) (*ip)--;
00300    }
00301    return 0;
00302 }
00303 
00304 //______________________________________________________________________________
00305 int TGHtml::DecodeBaseIndex(const char *baseIx,
00306                             TGHtmlElement **ppToken, int *pIndex)
00307 {
00308    // Given a base index name (without any modifiers) return a pointer
00309    // to the token described, and the character within that token.
00310    //
00311    // Valid input forms include:
00312    //
00313    //       N.M          Token number N (with numbering starting at 1) and
00314    //                    character number M (with numbering starting at 0).
00315    //
00316    //       M.X          Like above, but token is markup and X is an attribute.
00317    //
00318    //       begin        The start of all text
00319    //
00320    //       end          The end of all text
00321    //
00322    //       N.last       Last character of token number N.
00323    //
00324    //       N.end        One past last character of token number N.
00325    //
00326    //       sel.first    First character of the selection.
00327    //
00328    //       sel.last     Last character of the selection.
00329    //
00330    //       sel.end      On past last character of the selection.
00331    //
00332    //       insert       The character holding the insertion cursor.
00333    //
00334    //       @X,Y         The character a location X,Y of the clipping window.
00335    //
00336    //       &DOM         The DOM Address of a token.
00337    //
00338    // Zero is returned if we are successful and non-zero if there is
00339    // any kind of error.
00340    //
00341    // If the given token doesn't exist (for example if there are only 10
00342    // tokens and 11.5 is requested) then *ppToken is left pointing to NULL.
00343    // But the function still returns 0 for success.
00344 
00345    int i, n, x, y;
00346    TGHtmlElement *p = 0;
00347    TGHtmlBlock *pBlock;
00348    TGHtmlBlock *pNearby;
00349    int dist = 1000000;
00350    int rc = 0;
00351    char buf[200], *base = buf, *suffix, *ep;
00352 
00353    strlcpy(buf, baseIx, sizeof(buf));
00354 
00355    while (isspace((unsigned char)*base)) base++;
00356    ep = base;
00357    while (*ep && !isspace((unsigned char)*ep)) ep++;
00358    *ep = 0;
00359 
00360    if ((suffix = strchr(base, ':'))) *suffix = 0;
00361 
00362    switch (*base) {
00363       case '1': case '2': case '3': case '4': case '5':
00364       case '6': case '7': case '8': case '9': case '0':
00365          n = sscanf(base, "%d.%d", &x, &y);
00366          if (n > 0) {
00367             p = *ppToken = TokenByIndex(x, 0);
00368          }
00369          if (n == 2) {
00370             *pIndex = y;
00371          } else {
00372             for (i = 1; isdigit(base[i]); ++i) {}
00373             if (base[i] == 0) {
00374                *pIndex = 0;
00375             } else if (strcmp(&base[i], ".last") == 0) {
00376                MaxIndex(p, pIndex, 1);
00377             } else if (strcmp(&base[i], ".end") == 0) {
00378                MaxIndex(p, pIndex, 0);
00379                (*pIndex)++;
00380             } else {
00381                if (n == 1 && p && p->IsMarkup() && base[i] == '.' &&
00382                    p->MarkupArg(fZBase + i + 1, 0)) {
00383                   *pIndex = 0;
00384                } else {
00385                   rc = 1;
00386                }
00387             }
00388          }
00389          break;
00390 
00391       case 'b':
00392          if (strcmp(base, "begin") == 0) {
00393             p = *ppToken = fPFirst;
00394             *pIndex = 0;
00395          } else {
00396             rc = 1;
00397          }
00398          break;
00399 
00400       case 'e':
00401          if (strcmp(base, "end") == 0) {
00402             p = *ppToken = fPLast;
00403             MaxIndex(p, pIndex, 0);
00404          } else {
00405             rc = 1;
00406          }
00407          break;
00408 
00409       case 'l':
00410          if (strcmp(base, "last") == 0) {
00411             p = *ppToken = fPLast;
00412             MaxIndex(p, pIndex, 1);
00413          } else {
00414             rc = 1;
00415          }
00416          break;
00417 
00418       case 's':
00419          if (strcmp(base, "sel.first") == 0) {
00420             *ppToken = fSelBegin.fP;
00421             *pIndex = fSelBegin.fI;
00422          } else if (strcmp(base, "sel.last") == 0) {
00423             *ppToken = fSelEnd.fP;
00424             *pIndex = fSelEnd.fI;
00425          } else if (strcmp(base, "sel.end") == 0) {
00426             *ppToken = fSelEnd.fP;
00427             *pIndex = fSelEnd.fI + 1;
00428          } else {
00429             rc = 1;
00430          }
00431          break;
00432 
00433       case 'i':
00434          if (strcmp(baseIx, "insert") == 0) {
00435             *ppToken = fIns.fP;
00436             *pIndex = fIns.fI;
00437          } else {
00438             rc = 1;
00439          }
00440          break;
00441 
00442 #if 0
00443       case '&':
00444          *pIndex = 0;
00445          if (DomIdLookup("id", base + 1, ppToken)) rc = 1;
00446          break;
00447 #endif
00448 
00449       case '@':
00450          n = sscanf(base, "@%d,%d", &x, &y);
00451          if (n != 2) {
00452             rc = 1;
00453             break;
00454          }
00455          x += fVisible.fX;
00456          y += fVisible.fY;
00457          pNearby = 0;
00458          *ppToken = fPLast;
00459          *pIndex = 0;
00460          for (pBlock = fFirstBlock; pBlock; pBlock = pBlock->fBNext) {
00461             int dotest;
00462             if (pBlock->fN == 0) {
00463                switch (pBlock->fPNext->fType) {
00464                   case Html_LI:
00465                   case Html_IMG:
00466                   case Html_INPUT:
00467                   case Html_TEXTAREA:
00468                   case Html_SELECT:
00469                      dotest = 1;
00470                      break;
00471                   default:
00472                      dotest = 0;
00473                      break;
00474                }
00475             } else {
00476                dotest = 1;
00477             }
00478             if (dotest) {
00479                if (pBlock->fTop <= y && pBlock->fBottom >= y) {
00480                   if (pBlock->fLeft > x) {
00481                      if (pBlock->fLeft - x < dist) {
00482                         dist = pBlock->fLeft - x;
00483                         pNearby = pBlock;
00484                      }
00485                   } else if (pBlock->fRight < x) {
00486                      if (x - pBlock->fRight < dist) {
00487                         dist = x - pBlock->fRight;
00488                         pNearby = pBlock;
00489                      }
00490                   } else {
00491                      FindIndexInBlock(pBlock, x, ppToken, pIndex);
00492                      break;
00493                   }
00494                } else {
00495                   int distY;
00496                   int distX;
00497 
00498                   if (pBlock->fBottom < y) {
00499                      distY = y - pBlock->fBottom;
00500                   } else {
00501                      distY = pBlock->fTop - y;
00502                   }
00503                   if (pBlock->fLeft > x) {
00504                      distX = pBlock->fLeft - x;
00505                   } else if (pBlock->fRight < x) {
00506                      distX = x - pBlock->fRight;
00507                   } else {
00508                      distX = 0;
00509                   }
00510                   if (distX + 4*distY < dist) {
00511                      dist = distX + 4*distY;
00512                      pNearby = pBlock;
00513                   }
00514                }
00515             }
00516          }
00517          if (pBlock == 0) {
00518             if (pNearby) {
00519                FindIndexInBlock(pNearby, x, ppToken, pIndex);
00520             }
00521          }
00522          break;
00523 
00524       default:
00525          rc = 1;
00526          break;
00527    }
00528    if (suffix) IndexMod(ppToken, pIndex, suffix + 1);
00529 
00530    return rc;
00531 }
00532 
00533 //______________________________________________________________________________
00534 int TGHtml::GetIndex(const char *zIndex,
00535                      TGHtmlElement **ppToken, int *pIndex)
00536 {
00537    // This routine decodes a complete index specification. A complete
00538    // index consists of the base specification followed by modifiers.
00539 
00540    return DecodeBaseIndex(zIndex, ppToken, pIndex);
00541 }

Generated on Tue Jul 5 14:22:19 2011 for ROOT_528-00b_version by  doxygen 1.5.1