TGText.cxx

Go to the documentation of this file.
00001 // @(#)root/gui:$Id: TGText.cxx 35622 2010-09-23 08:29:15Z bellenot $
00002 // Author: Fons Rademakers   26/04/98
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
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     This source is based on Xclass95, a Win95-looking GUI toolkit.
00014     Copyright (C) 1996, 1997 David Barth, Ricky Ralston, Hector Peraza.
00015 
00016     Xclass95 is free software; you can redistribute it and/or
00017     modify it under the terms of the GNU Library General Public
00018     License as published by the Free Software Foundation; either
00019     version 2 of the License, or (at your option) any later version.
00020 
00021 **************************************************************************/
00022 
00023 //////////////////////////////////////////////////////////////////////////
00024 //                                                                      //
00025 // TGText                                                               //
00026 //                                                                      //
00027 // A TGText is a multi line text buffer. It allows the text to be       //
00028 // loaded from file, saved to file and edited. It is used in the        //
00029 // TGTextEdit widget. Single line text is handled by TGTextBuffer       //
00030 // and the TGTextEntry widget.                                          //
00031 //                                                                      //
00032 //////////////////////////////////////////////////////////////////////////
00033 
00034 #include "TGText.h"
00035 #include <ctype.h>
00036 
00037 const Int_t kMaxLen = 8000;
00038 
00039 
00040 ClassImp(TGTextLine)
00041 
00042 //______________________________________________________________________________
00043 TGTextLine::TGTextLine()
00044 {
00045    // Create empty line of text (default ctor).
00046 
00047    fLength = 0;
00048    fString = 0;
00049    fPrev = fNext = 0;
00050 }
00051 
00052 //______________________________________________________________________________
00053 TGTextLine::TGTextLine(TGTextLine *line)
00054 {
00055    // Initialize line of text with other line of text (not copy ctor).
00056 
00057    fLength = line->GetLineLength();
00058    fString = 0;
00059    if (fLength > 0)
00060       fString = line->GetText(0, line->GetLineLength());
00061    fPrev = fNext = 0;
00062 }
00063 
00064 //______________________________________________________________________________
00065 TGTextLine::TGTextLine(const char *string)
00066 {
00067    // Initialize line of text with a const char*.
00068 
00069    if (string) {
00070       fLength = strlen(string);
00071       fString = new char[fLength+1];
00072       strncpy(fString, string, fLength);
00073       fString[fLength] = 0;
00074    } else {
00075       fLength = 0;
00076       fString = 0;
00077    }
00078    fPrev = fNext = 0;
00079 }
00080 
00081 //______________________________________________________________________________
00082 TGTextLine::TGTextLine(const TGTextLine& tl) :
00083   fString(tl.fString),
00084   fLength(tl.fLength),
00085   fPrev(tl.fPrev),
00086   fNext(tl.fNext)
00087 { 
00088    //copy constructor
00089 }
00090 
00091 //______________________________________________________________________________
00092 TGTextLine& TGTextLine::operator=(const TGTextLine& tl)
00093 {
00094    //assignment operator
00095    if(this!=&tl) {
00096       fString=tl.fString;
00097       fLength=tl.fLength;
00098       fPrev=tl.fPrev;
00099       fNext=tl.fNext;
00100    } 
00101    return *this;
00102 }
00103 
00104 //______________________________________________________________________________
00105 TGTextLine::~TGTextLine()
00106 {
00107    // Delete a line of text.
00108 
00109    if (fString)
00110       delete [] fString;
00111 }
00112 
00113 //______________________________________________________________________________
00114 void TGTextLine::Clear()
00115 {
00116    // Clear a line of text.
00117 
00118    if (fString)
00119       delete [] fString;
00120    fString = 0;
00121    fLength = 0;
00122 }
00123 
00124 //______________________________________________________________________________
00125 void TGTextLine::DelText(ULong_t pos, ULong_t length)
00126 {
00127    // Delete length chars from line starting at position pos.
00128 
00129    if (fLength == 0 || pos >= fLength)
00130       return;
00131    if (pos+length > fLength)
00132       length = fLength - pos;
00133 
00134    if (fLength - length <= 0) {
00135       delete [] fString;
00136       fLength = 0;
00137       fString = 0;
00138       return;
00139    }
00140    char *newstring = new char[fLength - length+1];
00141    strncpy(newstring, fString, (UInt_t)pos);
00142    strncpy(newstring+pos, fString+pos+length, UInt_t(fLength-pos-length));
00143    delete [] fString;
00144    fString = newstring;
00145    fLength = fLength - length;
00146    fString[fLength] = '\0';
00147 }
00148 
00149 //______________________________________________________________________________
00150 void TGTextLine::InsText(ULong_t pos, const char *text)
00151 {
00152    // Insert text in line starting at position pos.
00153 
00154    if (pos > fLength || !text)
00155       return;
00156 
00157    char *newstring = new char[strlen(text)+fLength+1];
00158    if (fString != 0)
00159       strncpy(newstring, fString, (UInt_t)pos);
00160    strcpy(newstring+pos, text);
00161    if (fString != 0 && fLength - pos  > 0)
00162       strncpy(newstring+pos+strlen(text), fString+pos, UInt_t(fLength-pos));
00163    fLength = fLength + strlen(text);
00164    delete [] fString;
00165    fString = newstring;
00166    fString[fLength] ='\0';
00167 }
00168 
00169 //______________________________________________________________________________
00170 char *TGTextLine::GetText(ULong_t pos, ULong_t length)
00171 {
00172    // Get length characters from line starting at pos. Returns 0
00173    // in case pos and length are out of range. The returned string
00174    // must be freed by the user.
00175 
00176    if (pos >= fLength) {
00177       return 0;
00178    }
00179 
00180    if (pos + length > (ULong_t)fString) {
00181       length = fLength - pos;
00182    }
00183 
00184    char *retstring = new char[length+1];
00185    retstring[length] = '\0';
00186    strncpy(retstring, fString+pos, (UInt_t)length);
00187 
00188    return retstring;
00189 }
00190 
00191 //______________________________________________________________________________
00192 char *TGTextLine::GetWord(ULong_t pos)
00193 {
00194    // Get word at position. Returned string must be deleted.
00195 
00196    if (pos >= fLength) {
00197       return 0;
00198    }
00199 
00200    Int_t start = (Int_t)pos;
00201    UInt_t end = (UInt_t)pos;
00202    UInt_t i = (UInt_t)pos;
00203 
00204    if (fString[i] == ' ' || fString[i] == '\t') {
00205       while (start >= 0) {
00206          if (fString[start] == ' ' || fString[start] == '\t') --start;
00207          else break;
00208       }
00209       ++start;
00210       while (end < fLength) {
00211          if (fString[end] == ' ' || fString[end] == '\t') ++end;
00212          else break;
00213       }
00214    } else if (isalnum(fString[i])) {
00215       while (start >= 0) {
00216          if (isalnum(fString[start])) --start;
00217          else break;
00218       }
00219       ++start;
00220       while (end < fLength) {
00221          if (isalnum(fString[end])) ++end;
00222          else break;
00223       }
00224    } else {
00225       while (start >= 0) {
00226          if (isalnum(fString[start]) || fString[start] == ' ' || fString[start] == '\t') {
00227             break;
00228          } else {
00229             --start;
00230          }
00231       }
00232       ++start;
00233       while (end < fLength) {
00234          if (isalnum(fString[end]) || fString[end] == ' ' || fString[end] == '\t') {
00235             break;
00236          } else {
00237             ++end;
00238          }
00239       }
00240    }
00241 
00242    UInt_t length = UInt_t(end - start);
00243    char *retstring = new char[length+1];
00244    retstring[length] = '\0';
00245    strncpy(retstring, fString+start, length);
00246 
00247    return retstring;
00248 }
00249 
00250 //______________________________________________________________________________
00251 void TGTextLine::DelChar(ULong_t pos)
00252 {
00253    // Delete a character from the line.
00254 
00255    char *newstring;
00256    if ((fLength <= 0) || (pos > fLength))
00257       return;
00258    newstring = new char[fLength];
00259    strncpy(newstring, fString, (UInt_t)pos-1);
00260    if (pos < fLength)
00261       strncpy(newstring+pos-1, fString+pos, UInt_t(fLength-pos+1));
00262    else
00263       newstring[pos-1] = 0;
00264    delete [] fString;
00265    fString = newstring;
00266    fLength--;
00267 }
00268 
00269 //______________________________________________________________________________
00270 void TGTextLine::InsChar(ULong_t pos, char character)
00271 {
00272    // Insert a character at the specified position.
00273 
00274    char *newstring;
00275    if (pos > fLength)
00276       return;
00277    newstring = new char[fLength+2];
00278    newstring[fLength+1] = '\0';
00279    if (fLength > 0)
00280       strncpy (newstring, fString, (UInt_t)pos);
00281    newstring[pos] = character;
00282    if (fLength - pos > 0)
00283       strncpy(newstring+pos+1, fString+pos, UInt_t(fLength-pos));
00284    delete [] fString;
00285    fString = newstring;
00286    fLength++;
00287 }
00288 
00289 //______________________________________________________________________________
00290 char TGTextLine::GetChar(ULong_t pos)
00291 {
00292    // Get a character at the specified position from the line.
00293    // Returns -1 if pos is out of range.
00294 
00295    if ((fLength <= 0) || (pos >= fLength))
00296       return -1;
00297    return fString[pos];
00298 }
00299 
00300 
00301 ClassImp(TGText)
00302 
00303 //______________________________________________________________________________
00304 TGText::TGText(const TGText& gt) :
00305   fFilename(gt.fFilename),
00306   fIsSaved(gt.fIsSaved),
00307   fFirst(gt.fFirst),
00308   fCurrent(gt.fCurrent),
00309   fCurrentRow(gt.fCurrentRow),
00310   fRowCount(gt.fRowCount),
00311   fColCount(gt.fColCount),
00312   fLongestLine(gt.fLongestLine)
00313 { 
00314    //copy constructor
00315 }
00316 
00317 //______________________________________________________________________________
00318 TGText& TGText::operator=(const TGText& gt)
00319 {
00320    //assignment operator
00321    if(this!=&gt) {
00322       fFilename=gt.fFilename;
00323       fIsSaved=gt.fIsSaved;
00324       fFirst=gt.fFirst;
00325       fCurrent=gt.fCurrent;
00326       fCurrentRow=gt.fCurrentRow;
00327       fRowCount=gt.fRowCount;
00328       fColCount=gt.fColCount;
00329       fLongestLine=gt.fLongestLine;
00330    } 
00331    return *this;
00332 }
00333 
00334 //______________________________________________________________________________
00335 void TGText::Init()
00336 {
00337    // Common initialization method.
00338 
00339    fFirst       = new TGTextLine;
00340    fCurrent     = fFirst;
00341    fCurrentRow  = 0;
00342    fColCount    = 0;
00343    fRowCount    = 1;
00344    fLongestLine = 0;
00345    fIsSaved     = kTRUE;
00346 }
00347 
00348 //______________________________________________________________________________
00349 TGText::TGText()
00350 {
00351    // Create default (empty) text buffer.
00352 
00353    Init();
00354 }
00355 
00356 //______________________________________________________________________________
00357 TGText::TGText(TGText *text)
00358 {
00359    // Create text buffer and initialize with other text buffer.
00360 
00361    TGLongPosition pos, end;
00362 
00363    pos.fX = pos.fY = 0;
00364    end.fY = text->RowCount() - 1;
00365    end.fX = text->GetLineLength(end.fY) - 1;
00366    Init();
00367    InsText(pos, text, pos, end);
00368 }
00369 
00370 //______________________________________________________________________________
00371 TGText::TGText(const char *string)
00372 {
00373    // Create text buffer and initialize with single line string.
00374 
00375    TGLongPosition pos;
00376 
00377    pos.fX = pos.fY = 0;
00378    Init();
00379    InsText(pos, string);
00380 }
00381 
00382 //______________________________________________________________________________
00383 TGText::~TGText()
00384 {
00385    // Destroy text buffer.
00386 
00387    Clear();
00388    delete fFirst;
00389 }
00390 
00391 //______________________________________________________________________________
00392 void TGText::Clear()
00393 {
00394    // Clear text buffer.
00395 
00396    TGTextLine *travel = fFirst->fNext;
00397    TGTextLine *toDelete;
00398    while (travel != 0) {
00399       toDelete = travel;
00400       travel = travel->fNext;
00401       delete toDelete;
00402    }
00403    fFirst->Clear();
00404    fFirst->fNext = 0;
00405    fCurrent      = fFirst;
00406    fCurrentRow   = 0;
00407    fColCount     = 0;
00408    fRowCount     = 1;
00409    fLongestLine  = 0;
00410    fIsSaved      = kTRUE;
00411    fFilename     = "";
00412 }
00413 
00414 //______________________________________________________________________________
00415 Bool_t TGText::Load(const char *fn, Long_t startpos, Long_t length)
00416 {
00417    // Load text from file fn. Startpos is the begin from where to
00418    // load the file and length is the number of characters to read
00419    // from the file.
00420 
00421    Bool_t      isFirst = kTRUE;
00422    Bool_t      finished = kFALSE;
00423    Long_t      count, charcount, i, cnt;
00424    FILE       *fp;
00425    char       *buf, c, *src, *dst, *buffer, *buf2;
00426    TGTextLine *travel, *temp;
00427 
00428    travel = fFirst;
00429 
00430    if (!(fp = fopen(fn, "r"))) return kFALSE;
00431    buf = new char[kMaxLen];
00432    i = 0;
00433    fseek(fp, startpos, SEEK_SET);
00434    charcount = 0;
00435    while (fgets(buf, kMaxLen, fp)) {
00436       if ((length != -1) && (charcount+(Int_t)strlen(buf) > length)) {
00437          count = length - charcount;
00438          finished = kTRUE;
00439       } else
00440          count = kMaxLen;
00441       charcount += strlen(buf);
00442       buf2 = new char[count+1];
00443       buf2[count] = '\0';
00444       src = buf;
00445       dst = buf2;
00446       cnt = 0;
00447       while ((c = *src++)) {
00448          // Don't put CR or NL in buffer
00449          if (c == 0x0D || c == 0x0A)
00450             break;
00451          // Expand tabs
00452          else if (c == 0x09) {
00453             *dst++ = '\t';
00454             while (((dst-buf2) & 0x7) && (cnt++ < count-1))
00455                *dst++ = 16;  //*dst++ = ' ';
00456          } else
00457             *dst++ = c;
00458          if (cnt++ >= count-1) break;
00459       }
00460       *dst = '\0';
00461       temp = new TGTextLine;
00462       buffer = new char[strlen(buf2)+1];
00463       strlcpy(buffer, buf2, strlen(buf2)+1);
00464       temp->fLength = strlen(buf2);
00465       temp->fString = buffer;
00466       temp->fNext = temp->fPrev = 0;
00467       if (isFirst) {
00468          delete fFirst;
00469          fFirst   = temp;
00470          fCurrent = temp;
00471          travel   = fFirst;
00472          isFirst  = kFALSE;
00473       } else {
00474          travel->fNext = temp;
00475          temp->fPrev   = travel;
00476          travel        = travel->fNext;
00477       }
00478       ++i;
00479       delete [] buf2;
00480       if (finished)
00481          break;
00482    }
00483    fclose(fp);
00484    delete [] buf;
00485 
00486    // Remember the number of lines
00487    fRowCount = i;
00488    if (fRowCount == 0)
00489       fRowCount++;
00490    fIsSaved  = kTRUE;
00491    fFilename = fn;
00492    LongestLine();
00493 
00494    return kTRUE;
00495 }
00496 
00497 //______________________________________________________________________________
00498 Bool_t TGText::LoadBuffer(const char *txtbuf)
00499 {
00500    // Load a 0 terminated buffer. Lines will be split at '\n'.
00501 
00502    Bool_t      isFirst = kTRUE;
00503    Bool_t      finished = kFALSE, lastnl = kFALSE;
00504    Long_t      i, cnt;
00505    TGTextLine *travel, *temp;
00506    char       *buf, c, *src, *dst, *buffer, *buf2, *s;
00507    const char *tbuf = txtbuf;
00508 
00509    travel = fFirst;
00510 
00511    if (!tbuf || !strlen(tbuf))
00512       return kFALSE;
00513 
00514    buf = new char[kMaxLen];
00515    i = 0;
00516 next:
00517    if ((s = (char*)strchr(tbuf, '\n'))) {
00518       if (s-tbuf+1 >= kMaxLen-1) {
00519          strncpy(buf, tbuf, kMaxLen-2);
00520          buf[kMaxLen-2] = '\n';
00521          buf[kMaxLen-1] = 0;
00522       } else {
00523          strncpy(buf, tbuf, s-tbuf+1);
00524          buf[s-tbuf+1] = 0;
00525       }
00526       tbuf = s+1;
00527    } else {
00528       strncpy(buf, tbuf, kMaxLen-1);
00529       buf[kMaxLen-1] = 0;
00530       finished = kTRUE;
00531    }
00532 
00533    buf2 = new char[kMaxLen+1];
00534    buf2[kMaxLen] = '\0';
00535    src = buf;
00536    dst = buf2;
00537    cnt = 0;
00538    while ((c = *src++)) {
00539       // Don't put CR or NL in buffer
00540       if (c == 0x0D || c == 0x0A)
00541          break;
00542       // Expand tabs
00543       else if (c == 0x09) {
00544          *dst++ = '\t';
00545          while (((dst-buf2) & 0x7) && (cnt++ < kMaxLen-1))
00546             *dst++ = 16;  //*dst++ = ' ';
00547       } else
00548          *dst++ = c;
00549       if (cnt++ >= kMaxLen-1) break;
00550    }
00551    *dst = '\0';
00552    temp = new TGTextLine;
00553    buffer = new char[strlen(buf2)+1];
00554    strlcpy(buffer, buf2, strlen(buf2)+1);
00555    temp->fLength = strlen(buf2);
00556    temp->fString = buffer;
00557    temp->fNext = temp->fPrev = 0;
00558    if (isFirst) {
00559       delete fFirst;
00560       fFirst   = temp;
00561       fCurrent = temp;
00562       travel   = fFirst;
00563       isFirst  = kFALSE;
00564    } else {
00565       travel->fNext = temp;
00566       temp->fPrev   = travel;
00567       travel        = travel->fNext;
00568    }
00569    ++i;
00570    delete [] buf2;
00571 
00572    // make sure that \n generates a single empty line in the TGText
00573    if (!lastnl && !*tbuf && *(tbuf-1) == '\n') {
00574       tbuf--;
00575       lastnl = kTRUE;
00576    }
00577 
00578    if (!finished && tbuf && strlen(tbuf))
00579       goto next;
00580 
00581    delete [] buf;
00582    // Remember the number of lines
00583    fRowCount = i;
00584    if (fRowCount == 0)
00585       fRowCount++;
00586    fIsSaved  = kTRUE;
00587    fFilename = "";
00588    LongestLine();
00589 
00590    return kTRUE;
00591 }
00592 
00593 //______________________________________________________________________________
00594 Bool_t TGText::Save(const char *fn)
00595 {
00596    // Save text buffer to file fn.
00597 
00598    char *buffer;
00599    TGTextLine *travel = fFirst;
00600    FILE *fp;
00601    if (!(fp = fopen(fn, "w"))) return kFALSE;
00602 
00603    while (travel) {
00604       ULong_t i = 0;
00605       buffer = new char[travel->fLength+2];
00606       strncpy(buffer, travel->fString, (UInt_t)travel->fLength);
00607       buffer[travel->fLength]   = '\n';
00608       buffer[travel->fLength+1] = '\0';
00609       while (buffer[i] != '\0') {
00610          if (buffer[i] == '\t') {
00611             ULong_t j = i+1;
00612             while (buffer[j] == 16)
00613                j++;
00614             strcpy(buffer+i+1, buffer+j);
00615          }
00616          i++;
00617       }
00618       if (fputs(buffer, fp) == EOF) {
00619          delete [] buffer;
00620          fclose(fp);
00621          return kFALSE;
00622       }
00623       delete [] buffer;
00624       travel = travel->fNext;
00625    }
00626    fIsSaved = kTRUE;
00627    fFilename = fn;
00628    fclose(fp);
00629 
00630    return kTRUE;
00631 }
00632 
00633 //______________________________________________________________________________
00634 Bool_t TGText::Append(const char *fn)
00635 {
00636    // Append buffer to file fn.
00637 
00638    char *buffer;
00639    TGTextLine *travel = fFirst;
00640    FILE *fp;
00641    if (!(fp = fopen(fn, "a"))) return kFALSE;
00642 
00643    while (travel) {
00644       ULong_t i = 0;
00645       buffer = new char[travel->fLength+2];
00646       strncpy(buffer, travel->fString, (UInt_t)travel->fLength);
00647       buffer[travel->fLength]   = '\n';
00648       buffer[travel->fLength+1] = '\0';
00649       while (buffer[i] != '\0') {
00650          if (buffer[i] == '\t') {
00651             ULong_t j = i+1;
00652             while (buffer[j] == 16 && buffer[j] != '\0')
00653                j++;
00654             strcpy(buffer+i+1, buffer+j);
00655          }
00656          i++;
00657       }
00658       if (fputs(buffer, fp) == EOF) {
00659          delete [] buffer;
00660          fclose(fp);
00661          return kFALSE;
00662       }
00663       delete [] buffer;
00664       travel = travel->fNext;
00665    }
00666    fIsSaved = kTRUE;
00667    fclose(fp);
00668 
00669    return kTRUE;
00670 }
00671 
00672 //______________________________________________________________________________
00673 Bool_t TGText::DelChar(TGLongPosition pos)
00674 {
00675    // Delete character at specified position pos.
00676 
00677    if ((pos.fY >= fRowCount) || (pos.fY < 0))
00678       return kFALSE;
00679 
00680    if (!SetCurrentRow(pos.fY)) return kFALSE;
00681    fCurrent->DelChar(pos.fX);
00682 
00683    fIsSaved = kFALSE;
00684    LongestLine();
00685    return kTRUE;
00686 }
00687 
00688 //______________________________________________________________________________
00689 Bool_t TGText::InsChar(TGLongPosition pos, char c)
00690 {
00691    // Insert character c at the specified position pos.
00692 
00693    if ((pos.fY >= fRowCount) || (pos.fY < 0) || (pos.fX < 0))
00694       return kFALSE;
00695 
00696    if (!SetCurrentRow(pos.fY)) return kFALSE;
00697    fCurrent->InsChar(pos.fX, c);
00698 
00699    fIsSaved = kFALSE;
00700    LongestLine();
00701    return kTRUE;
00702 }
00703 
00704 //______________________________________________________________________________
00705 char TGText::GetChar(TGLongPosition pos)
00706 {
00707    // Get character a position pos. If charcater not valid return -1.
00708 
00709    if (pos.fY >= fRowCount)
00710       return -1;
00711 
00712    if (!SetCurrentRow(pos.fY)) return -1;
00713    return fCurrent->GetChar(pos.fX);
00714 }
00715 
00716 //______________________________________________________________________________
00717 Bool_t TGText::DelText(TGLongPosition start, TGLongPosition end)
00718 {
00719    // Delete text between start and end positions. Returns false in
00720    // case of failure (start and end not being within bounds).
00721 
00722    if ((start.fY < 0) || (start.fY >= fRowCount) ||
00723        (end.fY < 0)   || (end.fY >= fRowCount)) {
00724       return kFALSE;
00725    }
00726 
00727    if ((end.fX < 0) || (end.fX > GetLineLength(end.fY))) {
00728       return kFALSE;
00729    }
00730 
00731    char *tempbuffer;
00732 
00733    if (!SetCurrentRow(start.fY)) return kFALSE;
00734 
00735    if (start.fY == end.fY) {
00736       fCurrent->DelText(start.fX, end.fX-start.fX+1);
00737       return kTRUE;
00738    }
00739    fCurrent->DelText(start.fX, fCurrent->fLength-start.fX);
00740    SetCurrentRow(fCurrentRow+1);
00741    for (Long_t i = start.fY+1; i < end.fY; i++) {
00742       DelLine(fCurrentRow);
00743    }
00744 
00745    tempbuffer = fCurrent->GetText(end.fX+1, fCurrent->fLength-end.fX-1);
00746    DelLine(fCurrentRow);
00747    SetCurrentRow(start.fY);
00748    if (tempbuffer) {
00749       fCurrent->InsText(fCurrent->GetLineLength(), tempbuffer);
00750       delete [] tempbuffer;
00751    } else {
00752       if (fCurrent->fNext) {
00753          fCurrent->InsText(fCurrent->fLength, fCurrent->fNext->fString);
00754          DelLine(fCurrentRow+1);
00755          SetCurrentRow(start.fY);
00756       }
00757    }
00758 
00759    fIsSaved = kFALSE;
00760    LongestLine();
00761    return kTRUE;
00762 }
00763 
00764 //______________________________________________________________________________
00765 Bool_t TGText::InsText(TGLongPosition ins_pos, TGText *src,
00766                        TGLongPosition start_src, TGLongPosition end_src)
00767 {
00768    // Insert src text from start_src to end_src into text at position ins_pos.
00769    // Returns false in case of failure (start_src, end_src out of range for
00770    // src, and ins_pos out of range for this).
00771 
00772    /*
00773    if ((start_src.fY < 0) || (start_src.fY >= src->RowCount()) ||
00774        (end_src.fY < 0)   || (end_src.fY >= src->RowCount()))
00775       return kFALSE;
00776    if ((start_src.fX < 0) || (start_src.fX > src->GetLineLength(start_src.fY)) ||
00777        (end_src.fX < 0)   || (end_src.fX > src->GetLineLength(end_src.fY)))
00778       return kFALSE;
00779    if ((ins_pos.fY < 0) || (ins_pos.fY > fRowCount))
00780       return kFALSE;
00781    if ((ins_pos.fX < 0) || (ins_pos.fX > GetLineLength(ins_pos.fY)))
00782       return kFALSE;
00783    */
00784    if (ins_pos.fY > fRowCount)
00785       return kFALSE;
00786 
00787    TGLongPosition pos;
00788    ULong_t len;
00789    char *lineString;
00790    char *restString;
00791    TGTextLine *following;
00792 
00793    if (ins_pos.fY == fRowCount) {  // for appending text
00794       pos.fY = fRowCount - 1;
00795       pos.fX = GetLineLength(pos.fY);
00796       BreakLine(pos);  // current row is set by this
00797    } else {
00798       // otherwise going to the desired row
00799       if (!SetCurrentRow(ins_pos.fY)) return kFALSE;
00800    }
00801 
00802    // preparing first line to be inserted
00803    restString = fCurrent->GetText(ins_pos.fX, fCurrent->fLength - ins_pos.fX);
00804    fCurrent->DelText(ins_pos.fX, fCurrent->fLength - ins_pos.fX);
00805    following = fCurrent->fNext;
00806    // inserting first line
00807    if (start_src.fY == end_src.fY) {
00808       len = end_src.fX - start_src.fX+1;
00809    } else {
00810       len = src->GetLineLength(start_src.fY) - start_src.fX;
00811    }
00812 
00813    if (len > 0) {
00814       lineString = src->GetLine(start_src, len);
00815       fCurrent->InsText(ins_pos.fX, lineString);
00816       delete [] lineString;
00817    }
00818    // [...] inserting possible lines
00819    pos.fY = start_src.fY+1;
00820    pos.fX = 0;
00821    for ( ; pos.fY < end_src.fY; pos.fY++) {
00822       Int_t llen = src->GetLineLength(pos.fY);
00823       lineString = src->GetLine(pos, llen > 0 ? llen : 0);
00824       fCurrent->fNext = new TGTextLine(lineString);
00825       fCurrent->fNext->fPrev = fCurrent;
00826       fCurrent = fCurrent->fNext;
00827       fRowCount++;
00828       fCurrentRow++;
00829       delete [] lineString;
00830    }
00831    // last line of inserted text is as special as first line
00832    if (start_src.fY != end_src.fY) {
00833       pos.fY = end_src.fY;
00834       pos.fX = 0;
00835       lineString = src->GetLine(pos, end_src.fX+1);
00836       fCurrent->fNext = new TGTextLine(lineString);
00837       fCurrent->fNext->fPrev = fCurrent;
00838       fCurrent = fCurrent->fNext;
00839       fRowCount++;
00840       fCurrentRow++;
00841       delete [] lineString;
00842    }
00843    // ok, now we have to add the rest of the first destination line
00844    if (restString) {
00845 #if 0
00846       if (ins_pos.fX == 0) {
00847          fCurrent->fNext = new TGTextLine(restString);
00848          fCurrent->fNext->fPrev = fCurrent;
00849          fCurrent = fCurrent->fNext;
00850          fRowCount++;
00851          fCurrentRow++;
00852       } else
00853 #endif
00854          fCurrent->InsText(fCurrent->fLength, restString);
00855       delete [] restString;
00856    }
00857    // now re-linking the rest of the origin text
00858    fCurrent->fNext = following;
00859    if (fCurrent->fNext) {
00860       fCurrent->fNext->fPrev = fCurrent;
00861    }
00862 
00863    LongestLine();
00864    fIsSaved = kFALSE;
00865    return kTRUE;
00866 }
00867 
00868 //______________________________________________________________________________
00869 Bool_t TGText::InsText(TGLongPosition pos, const char *buffer)
00870 {
00871    // Insert single line at specified position. Return false in case position
00872    // is out of bounds.
00873 
00874    if (pos.fY < 0 || pos.fY > fRowCount) {
00875       return kFALSE;
00876    }
00877 
00878    if (pos.fY == fRowCount) {
00879       SetCurrentRow(fRowCount-1);
00880       fCurrent->fNext = new TGTextLine(buffer);
00881       fCurrent->fNext->fPrev = fCurrent;
00882       fRowCount++;
00883    } else {
00884       SetCurrentRow(pos.fY);
00885       fCurrent->InsText(pos.fX, buffer);
00886    }
00887    LongestLine();
00888    fIsSaved = kFALSE;
00889    return kTRUE;
00890 }
00891 
00892 //______________________________________________________________________________
00893 Bool_t TGText::AddText(TGText *text)
00894 {
00895    // Add another text buffer to this buffer.
00896 
00897    TGLongPosition end, start_src, end_src;
00898 
00899    end.fY = fRowCount;
00900    end.fX = 0;
00901    start_src.fX = start_src.fY = 0;
00902    end_src.fY   = text->RowCount()-1;
00903    end_src.fX   = text->GetLineLength(end_src.fY)-1;
00904    fIsSaved     = kFALSE;
00905    return InsText(end, text, start_src, end_src);
00906 }
00907 
00908 //______________________________________________________________________________
00909 Bool_t TGText::InsLine(ULong_t pos, const char *string)
00910 {
00911    // Insert string before specified position.
00912    // Returns false if insertion failed.
00913 
00914    TGTextLine *previous, *newline;
00915    if ((Long_t)pos > fRowCount) {
00916       return kFALSE;
00917    }
00918    if ((Long_t)pos < fRowCount) {
00919       SetCurrentRow(pos);
00920    } else {
00921       SetCurrentRow(fRowCount-1);
00922    }
00923 
00924    if (!fCurrent) return kFALSE;
00925 
00926    previous = fCurrent->fPrev;
00927    newline = new TGTextLine(string);
00928    newline->fPrev = previous;
00929    if (previous) {
00930       previous->fNext = newline;
00931    } else {
00932       fFirst = newline;
00933    }
00934 
00935    newline->fNext = fCurrent;
00936    fCurrent->fPrev = newline;
00937    fRowCount++;
00938    fCurrentRow++;
00939 
00940    LongestLine();
00941    fIsSaved = kFALSE;
00942    return kTRUE;
00943 }
00944 
00945 //______________________________________________________________________________
00946 Bool_t TGText::DelLine(ULong_t pos)
00947 {
00948    // Delete specified row. Returns false if row does not exist.
00949 
00950    if (!SetCurrentRow(pos) || (fRowCount == 1)) {
00951       return kFALSE;
00952    }
00953 
00954    TGTextLine *travel = fCurrent;
00955    if (travel == fFirst) {
00956       fFirst = fFirst->fNext;
00957       fFirst->fPrev = 0;
00958    } else {
00959       travel->fPrev->fNext = travel->fNext;
00960       if (travel->fNext) {
00961          travel->fNext->fPrev = travel->fPrev;
00962          fCurrent = fCurrent->fNext;
00963       } else {
00964          fCurrent = fCurrent->fPrev;
00965          fCurrentRow--;
00966       }
00967    }
00968    delete travel;
00969 
00970    fRowCount--;
00971    fIsSaved = kFALSE;
00972    LongestLine();
00973 
00974    return kTRUE;
00975 }
00976 
00977 //______________________________________________________________________________
00978 char *TGText::GetLine(TGLongPosition pos, ULong_t length)
00979 {
00980    // Return string at position pos. Returns 0 in case pos is not valid.
00981    // The returned string must be deleted by the user.
00982 
00983    if (SetCurrentRow(pos.fY)) {
00984       return fCurrent->GetText(pos.fX, length);
00985    }
00986    return 0;
00987 }
00988 
00989 //______________________________________________________________________________
00990 Bool_t TGText::BreakLine(TGLongPosition pos)
00991 {
00992    // Break line at position pos. Returns false if pos is not valid.
00993 
00994    if (!SetCurrentRow(pos.fY))
00995       return kFALSE;
00996    if ((pos.fX < 0) || (pos.fX > (Long_t)fCurrent->fLength))
00997       return kFALSE;
00998 
00999    TGTextLine *temp;
01000    char *tempbuffer;
01001    if (pos.fX < (Long_t)fCurrent->fLength) {
01002       tempbuffer = fCurrent->GetText(pos.fX, fCurrent->fLength-pos.fX);
01003       temp = new TGTextLine(tempbuffer);
01004       fCurrent->DelText(pos.fX, fCurrent->fLength - pos.fX);
01005       delete [] tempbuffer;
01006    } else {
01007       temp = new TGTextLine;
01008    }
01009    temp->fPrev = fCurrent;
01010    temp->fNext = fCurrent->fNext;
01011    fCurrent->fNext = temp;
01012    if (temp->fNext) {
01013       temp->fNext->fPrev = temp;
01014    }
01015 
01016    fIsSaved = kFALSE;
01017    fRowCount++;
01018    fCurrentRow++;
01019    fCurrent = fCurrent->fNext;
01020    LongestLine();
01021    return kTRUE;
01022 }
01023 
01024 //______________________________________________________________________________
01025 Long_t TGText::GetLineLength(Long_t row)
01026 {
01027    // Get length of specified line. Returns -1 if row does not exist.
01028 
01029    if (!SetCurrentRow(row)) {
01030       return -1;
01031    }
01032    return (Long_t)fCurrent->GetLineLength();
01033 }
01034 
01035 //______________________________________________________________________________
01036 Bool_t TGText::SetCurrentRow(Long_t row)
01037 {
01038    // Make specified row the current row. Returns false if row does not exist.
01039    // In which case fCurrent is not changed or set to the last valid line.
01040 
01041    Long_t count;
01042    if ((row < 0) || (row >= fRowCount)) {
01043       return kFALSE;
01044    }
01045    if (row > fCurrentRow) {
01046       for (count = fCurrentRow; count < row; count++) {
01047          if (!fCurrent->fNext) {
01048             fCurrentRow = count;
01049             return kFALSE;
01050          }
01051          fCurrent = fCurrent->fNext;
01052       }
01053    } else {
01054       if (fCurrentRow == row)
01055          return kTRUE;
01056       for (count = fCurrentRow; count > row; count--) {
01057          if (!fCurrent->fPrev) {
01058             fCurrentRow = count;
01059             return kFALSE;
01060          }
01061          fCurrent = fCurrent->fPrev;
01062       }
01063    }
01064    fCurrentRow = row;
01065    return kTRUE;
01066 }
01067 
01068 //______________________________________________________________________________
01069 void TGText::ReTab(Long_t row)
01070 {
01071    // Redo all tabs in a line. Needed after a new tab is inserted.
01072 
01073    if (!SetCurrentRow(row)) {
01074       return;
01075    }
01076 
01077    // first remove all special tab characters (16)
01078    char *buffer;
01079    ULong_t i = 0;
01080 
01081    buffer = fCurrent->fString;
01082    while (buffer[i] != '\0') {
01083       if (buffer[i] == '\t') {
01084          ULong_t j = i+1;
01085          while (buffer[j] == 16 && buffer[j] != '\0') {
01086             j++;
01087          }
01088          strcpy(buffer+i+1, buffer+j);
01089       }
01090       i++;
01091    }
01092 
01093    char   c, *src, *dst, *buf2;
01094    Long_t cnt;
01095 
01096    buf2 = new char[kMaxLen+1];
01097    buf2[kMaxLen] = '\0';
01098    src = buffer;
01099    dst = buf2;
01100    cnt = 0;
01101    while ((c = *src++)) {
01102       // Expand tabs
01103       if (c == 0x09) {
01104          *dst++ = '\t';
01105          while (((dst-buf2) & 0x7) && (cnt++ < kMaxLen-1)) {
01106             *dst++ = 16;
01107          }
01108       } else {
01109          *dst++ = c;
01110       }
01111       if (cnt++ >= kMaxLen-1) break;
01112    }
01113    *dst = '\0';
01114 
01115    fCurrent->fString = buf2;
01116    fCurrent->fLength = strlen(buf2);
01117 
01118    delete [] buffer;
01119 }
01120 
01121 //______________________________________________________________________________
01122 Bool_t TGText::Search(TGLongPosition *foundPos, TGLongPosition start,
01123                       const char *searchString,
01124                       Bool_t direction, Bool_t caseSensitive)
01125 {
01126    // Search for string searchString starting at the specified position going
01127    // in forward (direction = true) or backward direction. Returns true if
01128    // found and foundPos is set accordingly.
01129 
01130    if (!SetCurrentRow(start.fY))
01131       return kFALSE;
01132 
01133    Ssiz_t x = kNPOS;
01134 
01135    if (direction) {
01136       while(1) {
01137          TString s = fCurrent->fString;
01138          x = s.Index(searchString, (Ssiz_t)start.fX,
01139                      caseSensitive ? TString::kExact : TString::kIgnoreCase);
01140          if (x != kNPOS) {
01141             foundPos->fX = x;
01142             foundPos->fY = fCurrentRow;
01143             return kTRUE;
01144          }
01145          if (!SetCurrentRow(fCurrentRow+1))
01146             break;
01147          start.fX = 0;
01148       }
01149    } else {
01150       while(1) {
01151          TString s = fCurrent->fString;
01152          for (int i = (int)start.fX; i >= 0; i--) {
01153             x = s.Index(searchString, (Ssiz_t)i,
01154                         caseSensitive ? TString::kExact : TString::kIgnoreCase);
01155             if (x >= start.fX) {
01156                x = kNPOS;
01157                continue;
01158             }
01159             if (x != kNPOS) {
01160                break;
01161             }
01162          }
01163          if (x != kNPOS) {
01164             foundPos->fX = x;
01165             foundPos->fY = fCurrentRow;
01166             return kTRUE;
01167          }
01168          if (!SetCurrentRow(fCurrentRow-1)) {
01169             break;
01170          }
01171          start.fX = fCurrent->fLength;
01172       }
01173    }
01174    return kFALSE;
01175 }
01176 
01177 //______________________________________________________________________________
01178 Bool_t TGText::Replace(TGLongPosition start, const char *oldText, const char *newText,
01179                        Bool_t direction, Bool_t caseSensitive)
01180 {
01181    // Replace oldText by newText. Returns false if nothing replaced.
01182 
01183    if (!SetCurrentRow(start.fY)) {
01184       return kFALSE;
01185    }
01186 
01187    TGLongPosition foundPos;
01188    if (!Search(&foundPos, start, oldText, direction, caseSensitive)) {
01189       return kFALSE;
01190    }
01191 
01192    TGLongPosition delEnd;
01193    delEnd.fY = foundPos.fY;
01194    delEnd.fX = foundPos.fX + strlen(oldText) - 1;
01195    DelText(foundPos, delEnd);
01196    InsText(foundPos, newText);
01197    return kTRUE;
01198 }
01199 
01200 //______________________________________________________________________________
01201 void TGText::LongestLine()
01202 {
01203    // Set fLongestLine.
01204 
01205    Long_t line_count = 0;
01206    TGTextLine *travel = fFirst;
01207    fColCount = 0;
01208    while (travel) {
01209       if ((Long_t)travel->fLength > fColCount) {
01210          fColCount = travel->fLength;
01211          fLongestLine = line_count;
01212       }
01213       travel = travel->fNext;
01214       line_count++;
01215    }
01216 }
01217 
01218 //______________________________________________________________________________
01219 TString TGText::AsString()
01220 {
01221    // Returns content as ROOT string
01222 
01223    TString ret;
01224 
01225    Long_t line_count = 0;
01226    TGTextLine *travel = fFirst;
01227    fColCount = 0;
01228 
01229    while (travel) {
01230       if ((Long_t)travel->fLength > fColCount) {
01231          fColCount = travel->fLength;
01232          fLongestLine = line_count;
01233       }
01234       ret += travel->GetText();
01235       travel = travel->fNext;
01236       if (travel) ret += '\n';
01237       line_count++;
01238    }
01239 
01240    return ret;
01241 }

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