-rw-r--r-- | core/apps/embeddedkonsole/TEScreen.cpp | 32 | ||||
-rw-r--r-- | inputmethods/dasher/PPMLanguageModel.cpp | 3 | ||||
-rw-r--r-- | noncore/apps/opie-reader/Bkmks.cpp | 18 | ||||
-rw-r--r-- | noncore/apps/opie-reader/Bkmks.h | 7 | ||||
-rw-r--r-- | noncore/apps/opie-reader/StyleConsts.cpp | 7 | ||||
-rw-r--r-- | noncore/apps/opie-reader/StyleConsts.h | 8 | ||||
-rw-r--r-- | noncore/apps/opie-write/qrichtext.cpp | 5 | ||||
-rw-r--r-- | noncore/apps/tinykate/libkate/document/katehighlight.cpp | 7 | ||||
-rw-r--r-- | noncore/apps/tinykate/libkate/document/katehighlight.h | 2 |
9 files changed, 57 insertions, 32 deletions
diff --git a/core/apps/embeddedkonsole/TEScreen.cpp b/core/apps/embeddedkonsole/TEScreen.cpp index 1db34d2..30ff49d 100644 --- a/core/apps/embeddedkonsole/TEScreen.cpp +++ b/core/apps/embeddedkonsole/TEScreen.cpp @@ -1,1236 +1,1238 @@ /* -------------------------------------------------------------------------- */ /* */ /* [TEScreen.C] Screen Data Type */ /* */ /* -------------------------------------------------------------------------- */ /* */ /* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */ /* */ /* This file is part of Konsole - an X terminal for KDE */ /* */ /* -------------------------------------------------------------------------- */ /* */ /* Ported Konsole to Qt/Embedded */ /* */ /* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */ /* */ /* -------------------------------------------------------------------------- */ // enhancements added by L.J. Potter <ljp@llornkcor.com> /*! \file */ /*! \class TEScreen \brief The image manipulated by the emulation. This class implements the operations of the terminal emulation framework. It is a complete passive device, driven by the emulation decoder (TEmuVT102). By this it forms in fact an ADT, that defines operations on a rectangular image. It does neither know how to display its image nor about escape sequences. It is further independent of the underlying toolkit. By this, one can even use this module for an ordinary text surface. Since the operations are called by a specific emulation decoder, one may collect their different operations here. The state manipulated by the operations is mainly kept in `image', though it is a little more complex bejond this. See the header file of the class. \sa TEWidget \sa VT102Emulation */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> // #include <kdebug.h> #include <assert.h> #include <string.h> #include <ctype.h> #include <qpe/config.h> #include "TEScreen.h" #define HERE printf("%s(%d): here\n",__FILE__,__LINE__) //FIXME: this is emulation specific. Use FALSE for xterm, TRUE for ANSI. //FIXME: see if we can get this from terminfo. #define BS_CLEARS FALSE #define loc(X,Y) ((Y) * columns + (X)) /*! creates a `TEScreen' of `lines' lines and `columns' columns. */ -TEScreen::TEScreen(int lines, int columns) +TEScreen::TEScreen(int _lines, int _columns) : + lines(_lines), + columns(_columns), + tabstops(0), + histCursor(0), + horzCursor(0) { - this->lines = lines; - this->columns = columns; // odebug << "Columns " << columns << "" << oendl; - image = (ca*) malloc(lines*columns*sizeof(ca)); - tabstops = NULL; initTabStops(); - - histCursor = 0; - horzCursor = 0; + image = new ca[lines*columns]; + initTabStops(); clearSelection(); reset(); } /*! Destructor */ TEScreen::~TEScreen() { - free(image); - if (tabstops) free(tabstops); + delete [] image; + delete [] tabstops; } /* ------------------------------------------------------------------------- */ /* */ /* Normalized Screen Operations */ /* */ /* ------------------------------------------------------------------------- */ // Cursor Setting -------------------------------------------------------------- /*! \section Cursor The `cursor' is a location within the screen that is implicitely used in many operations. The operations within this section allow to manipulate the cursor explicitly and to obtain it's value. The position of the cursor is guarantied to be between (including) 0 and `columns-1' and `lines-1'. */ /*! Move the cursor up. The cursor will not be moved beyond the top margin. */ void TEScreen::cursorUp(int n) //=CUU { if (n == 0) n = 1; // Default int stop = cuY < tmargin ? 0 : tmargin; cuX = QMIN(columns-1,cuX); // nowrap! cuY = QMAX(stop,cuY-n); } /*! Move the cursor down. The cursor will not be moved beyond the bottom margin. */ void TEScreen::cursorDown(int n) //=CUD { if (n == 0) n = 1; // Default int stop = cuY > bmargin ? lines-1 : bmargin; cuX = QMIN(columns-1,cuX); // nowrap! cuY = QMIN(stop,cuY+n); } /*! Move the cursor left. The cursor will not move beyond the first column. */ void TEScreen::cursorLeft(int n) //=CUB { if (n == 0) n = 1; // Default cuX = QMIN(columns-1,cuX); // nowrap! cuX = QMAX(0,cuX-n); } /*! Move the cursor left. The cursor will not move beyond the rightmost column. */ void TEScreen::cursorRight(int n) //=CUF { if (n == 0) n = 1; // Default cuX = QMIN(columns-1,cuX+n); } /*! Set top and bottom margin. */ void TEScreen::setMargins(int top, int bot) //=STBM { if (top == 0) top = 1; // Default if (bot == 0) bot = lines; // Default top = top - 1; // Adjust to internal lineno bot = bot - 1; // Adjust to internal lineno if ( !( 0 <= top && top < bot && bot < lines ) ) { fprintf(stderr,"%s(%d) : setRegion(%d,%d) : bad range.\n", __FILE__,__LINE__,top,bot); return; // Default error action: ignore } tmargin = top; bmargin = bot; cuX = 0; cuY = getMode(MODE_Origin) ? top : 0; } /*! Move the cursor down one line. If cursor is on bottom margin, the region between the actual top and bottom margin is scrolled up instead. */ void TEScreen::index() //=IND { if (cuY == bmargin) { if (tmargin == 0 && bmargin == lines-1) addHistLine(); // hist.history scrollUp(tmargin,1); } else if (cuY < lines-1) cuY += 1; } /*! Move the cursor up one line. If cursor is on the top margin, the region between the actual top and bottom margin is scrolled down instead. */ void TEScreen::reverseIndex() //=RI { if (cuY == tmargin) scrollDown(tmargin,1); else if (cuY > 0) cuY -= 1; } /*! Move the cursor to the begin of the next line. If cursor is on bottom margin, the region between the actual top and bottom margin is scrolled up. */ void TEScreen::NextLine() //=NEL { Return(); index(); } // Line Editing ---------------------------------------------------------------- /*! \section inserting / deleting characters */ /*! erase `n' characters starting from (including) the cursor position. The line is filled in from the right with spaces. */ void TEScreen::eraseChars(int n) { if (n == 0) n = 1; // Default int p = QMAX(0,QMIN(cuX+n-1,columns-1)); clearImage(loc(cuX,cuY),loc(p,cuY),' '); } /*! delete `n' characters starting from (including) the cursor position. The line is filled in from the right with spaces. */ void TEScreen::deleteChars(int n) { if (n == 0) n = 1; // Default int p = QMAX(0,QMIN(cuX+n,columns-1)); moveImage(loc(cuX,cuY),loc(p,cuY),loc(columns-1,cuY)); clearImage(loc(columns-n,cuY),loc(columns-1,cuY),' '); } /*! insert `n' spaces at the cursor position. The cursor is not moved by the operation. */ void TEScreen::insertChars(int n) { if (n == 0) n = 1; // Default int p = QMAX(0,QMIN(columns-1-n,columns-1)); int q = QMAX(0,QMIN(cuX+n,columns-1)); moveImage(loc(q,cuY),loc(cuX,cuY),loc(p,cuY)); clearImage(loc(cuX,cuY),loc(q-1,cuY),' '); } /*! delete `n' lines starting from (including) the cursor position. The cursor is not moved by the operation. */ void TEScreen::deleteLines(int n) { if (n == 0) n = 1; // Default scrollUp(cuY,n); } /*! insert `n' lines at the cursor position. The cursor is not moved by the operation. */ void TEScreen::insertLines(int n) { if (n == 0) n = 1; // Default scrollDown(cuY,n); } // Mode Operations ----------------------------------------------------------- /*! Set a specific mode. */ void TEScreen::setMode(int m) { currParm.mode[m] = TRUE; switch(m) { case MODE_Origin : cuX = 0; cuY = tmargin; break; //FIXME: home } } /*! Reset a specific mode. */ void TEScreen::resetMode(int m) { currParm.mode[m] = FALSE; switch(m) { case MODE_Origin : cuX = 0; cuY = 0; break; //FIXME: home } } /*! Save a specific mode. */ void TEScreen::saveMode(int m) { saveParm.mode[m] = currParm.mode[m]; } /*! Restore a specific mode. */ void TEScreen::restoreMode(int m) { currParm.mode[m] = saveParm.mode[m]; } //NOTE: this is a helper function /*! Return the setting a specific mode. */ BOOL TEScreen::getMode(int m) { return currParm.mode[m]; } /*! Save the cursor position and the rendition attribute settings. */ void TEScreen::saveCursor() { sa_cuX = cuX; sa_cuY = cuY; sa_cu_re = cu_re; sa_cu_fg = cu_fg; sa_cu_bg = cu_bg; } /*! Restore the cursor position and the rendition attribute settings. */ void TEScreen::restoreCursor() { cuX = QMIN(sa_cuX,columns-1); cuY = QMIN(sa_cuY,lines-1); cu_re = sa_cu_re; cu_fg = sa_cu_fg; cu_bg = sa_cu_bg; effectiveRendition(); } /* ------------------------------------------------------------------------- */ /* */ /* Screen Operations */ /* */ /* ------------------------------------------------------------------------- */ /*! Assing a new size to the screen. The topmost left position is maintained, while lower lines or right hand side columns might be removed or filled with spaces to fit the new size. The region setting is reset to the whole screen and the tab positions reinitialized. */ void TEScreen::resizeImage(int new_lines, int new_columns) { if (cuY > new_lines-1) { // attempt to preserve focus and lines bmargin = lines-1; //FIXME: margin lost for (int i = 0; i < cuY-(new_lines-1); i++) { addHistLine(); scrollUp(horzCursor,1); } } // make new image - ca* newimg = (ca*)malloc( new_lines * new_columns * sizeof( ca)); + ca* newimg = new ca[new_lines * new_columns]; clearSelection(); // clear new image for (int y = 0; y < new_lines; y++) for (int x = 0; x < new_columns; x++) { newimg[y*new_columns+x].c = ' '; newimg[y*new_columns+x].f = DEFAULT_FORE_COLOR; newimg[y*new_columns+x].b = DEFAULT_BACK_COLOR; newimg[y*new_columns+x].r = DEFAULT_RENDITION; } int cpy_lines = QMIN(new_lines, lines); int cpy_columns = QMIN(new_columns,columns); // copy to new image for (int y = 0; y < cpy_lines; y++) for (int x = 0; x < cpy_columns; x++) { newimg[y*new_columns+x].c = image[loc(x,y)].c; newimg[y*new_columns+x].f = image[loc(x,y)].f; newimg[y*new_columns+x].b = image[loc(x,y)].b; newimg[y*new_columns+x].r = image[loc(x,y)].r; } - free(image); + delete [] image; image = newimg; lines = new_lines; columns = new_columns; cuX = QMIN(cuX,columns-1); cuY = QMIN(cuY,lines-1); // FIXME: try to keep values, evtl. tmargin=0; bmargin=lines-1; initTabStops(); clearSelection(); } /* Clarifying rendition here and in TEWidget. currently, TEWidget's color table is 0 1 2 .. 9 10 .. 17 dft_fg, dft_bg, dim 0..7, intensive 0..7 cu_fg, cu_bg contain values 0..8; - 0 = default color - 1..8 = ansi specified color re_fg, re_bg contain values 0..17 due to the TEWidget's color table rendition attributes are attr widget screen -------------- ------ ------ RE_UNDERLINE XX XX affects foreground only RE_BLINK XX XX affects foreground only RE_BOLD XX XX affects foreground only RE_REVERSE -- XX RE_TRANSPARENT XX -- affects background only RE_INTENSIVE XX -- affects foreground only Note that RE_BOLD is used in both widget and screen rendition. Since xterm/vt102 is to poor to distinguish between bold (which is a font attribute) and intensive (which is a color attribute), we translate this and RE_BOLD in falls eventually appart into RE_BOLD and RE_INTENSIVE. */ void TEScreen::reverseRendition(ca* p) { UINT8 f = p->f; UINT8 b = p->b; p->f = b; p->b = f; //p->r &= ~RE_TRANSPARENT; } void TEScreen::effectiveRendition() // calculate rendition { ef_re = cu_re & (RE_UNDERLINE | RE_BLINK); if (cu_re & RE_REVERSE) { ef_fg = cu_bg; ef_bg = cu_fg; } else { ef_fg = cu_fg; ef_bg = cu_bg; } if (cu_re & RE_BOLD) { if (ef_fg < BASE_COLORS) ef_fg += BASE_COLORS; else ef_fg -= BASE_COLORS; } } /*! returns the image. Get the size of the image by \sa getLines and \sa getColumns. NOTE that the image returned by this function must later be freed. */ ca* TEScreen::getCookedImage() { int x,y; - ca* merged = (ca*)malloc(lines*columns*sizeof(ca)); + ca* merged = new ca[lines*columns]; ca dft(' ',DEFAULT_FORE_COLOR,DEFAULT_BACK_COLOR,DEFAULT_RENDITION); if (histCursor > hist.getLines()) { histCursor = hist.getLines(); } for (y = 0; (y < lines) && (y < (hist.getLines()-histCursor)); y++) { int len = QMIN(columns,hist.getLineLen(y+histCursor)); int yp = y*columns; int yq = (y+histCursor)*columns; hist.getCells(y+histCursor,0,len,merged+yp); for (x = len; x < columns; x++) merged[yp+x] = dft; for (x = 0; x < columns; x++) { int p=x + yp; int q=x + yq; if ( ( q >= sel_TL ) && ( q <= sel_BR ) ) reverseRendition(&merged[p]); // for selection } } if (lines >= hist.getLines()-histCursor) { for (y = (hist.getLines()-histCursor); y < lines ; y++) { int yp = y*columns; int yq = (y+histCursor)*columns; int yr = (y-hist.getLines()+histCursor)*columns; for (x = 0; x < columns; x++) { int p = x + yp; int q = x + yq; int r = x + yr; merged[p] = image[r]; if ( q >= sel_TL && q <= sel_BR ) reverseRendition(&merged[p]); // for selection } } } // evtl. inverse display if (getMode(MODE_Screen)) { int i,n = lines*columns; for (i = 0; i < n; i++) reverseRendition(&merged[i]); // for reverse display } if (getMode(MODE_Cursor) && (cuY+(hist.getLines()-histCursor) < lines)) // cursor visible reverseRendition(&merged[loc(cuX,cuY+(hist.getLines()-histCursor))]); return merged; } /*! */ void TEScreen::reset() { Config cfg( "Konsole" ); cfg.setGroup("ScrollBar"); if( !cfg.readBoolEntry("HorzScroll",0) ) setMode(MODE_Wrap ); saveMode(MODE_Wrap ); // wrap at end of margin resetMode(MODE_Origin); saveMode(MODE_Origin); // position refere to [1,1] resetMode(MODE_Insert); saveMode(MODE_Insert); // overstroke setMode(MODE_Cursor); // cursor visible resetMode(MODE_Screen); // screen not inverse resetMode(MODE_NewLine); tmargin=0; bmargin=lines-1; setDefaultRendition(); saveCursor(); clear(); } /*! Clear the entire screen and home the cursor. */ void TEScreen::clear() { clearEntireScreen(); home(); } /*! Moves the cursor left one column. */ void TEScreen::BackSpace() { cuX = QMAX(0,cuX-1); if (BS_CLEARS) image[loc(cuX,cuY)].c = ' '; } /*! */ void TEScreen::Tabulate() { // note that TAB is a format effector (does not write ' '); cursorRight(1); while(cuX < columns-1 && !tabstops[cuX]) cursorRight(1); } void TEScreen::clearTabStops() { for (int i = 0; i < columns; i++) tabstops[i-1] = FALSE; } void TEScreen::changeTabStop(bool set) { if (cuX >= columns) return; tabstops[cuX] = set; } void TEScreen::initTabStops() { - if (tabstops) free(tabstops); - tabstops = (bool*)malloc(columns*sizeof(bool)); + if (tabstops) + delete [] tabstops; + + tabstops = new bool[columns]; // Arrg! The 1st tabstop has to be one longer than the other. // i.e. the kids start counting from 0 instead of 1. // Other programs might behave correctly. Be aware. for (int i = 0; i < columns; i++) tabstops[i] = (i%8 == 0 && i != 0); } /*! This behaves either as IND (Screen::Index) or as NEL (Screen::NextLine) depending on the NewLine Mode (LNM). This mode also affects the key sequence returned for newline ([CR]LF). */ void TEScreen::NewLine() { if (getMode(MODE_NewLine)) Return(); index(); } /*! put `c' literally onto the screen at the current cursor position. VT100 uses the convention to produce an automatic newline (am) with the *first* character that would fall onto the next line (xenl). */ void TEScreen::checkSelection(int from, int to) { if (sel_begin == -1) return; int scr_TL = loc(0, hist.getLines()); //Clear entire selection if it overlaps region [from, to] if ( (sel_BR > (from+scr_TL) )&&(sel_TL < (to+scr_TL)) ) { clearSelection(); } } void TEScreen::ShowCharacter(unsigned short c) { // Note that VT100 does wrapping BEFORE putting the character. // This has impact on the assumption of valid cursor positions. // We indicate the fact that a newline has to be triggered by // putting the cursor one right to the last column of the screen. if (cuX >= columns) { if (getMode(MODE_Wrap)) NextLine(); else cuX = columns - 1; // comment out for no wrap } if (getMode(MODE_Insert)) insertChars(1); int i = loc( cuX, cuY); checkSelection(i, i); // check if selection is still valid. image[i].c = c; image[i].f = ef_fg; image[i].b = ef_bg; image[i].r = ef_re; cuX += 1; } // Region commands ------------------------------------------------------------- /*! scroll up `n' lines within current region. The `n' new lines are cleared. \sa setRegion \sa scrollDown */ void TEScreen::scrollUp(int from, int n) { if (n <= 0 || from + n > bmargin) return; //FIXME: make sure `tmargin', `bmargin', `from', `n' is in bounds. moveImage( loc( 0, from), loc( 0, from + n), loc( columns - 1, bmargin)); clearImage( loc( 0, bmargin - n + 1), loc( columns - 1, bmargin), ' '); } /*! scroll down `n' lines within current region. The `n' new lines are cleared. \sa setRegion \sa scrollUp */ void TEScreen::scrollDown(int from, int n) { //FIXME: make sure `tmargin', `bmargin', `from', `n' is in bounds. if (n <= 0) return; if (from > bmargin) return; if (from + n > bmargin) n = bmargin - from; moveImage( loc(0,from+n), loc(0,from), loc(columns-1,bmargin-n)); clearImage(loc(0,from),loc(columns-1,from+n-1),' '); } /*! position the cursor to a specific line and column. */ void TEScreen::setCursorYX(int y, int x) { setCursorY(y); setCursorX(x); } /*! Set the cursor to x-th line. */ void TEScreen::setCursorX(int x) { if (x == 0) x = 1; // Default x -= 1; // Adjust cuX = QMAX(0,QMIN(columns-1, x)); } /*! Set the cursor to y-th line. */ void TEScreen::setCursorY(int y) { if (y == 0) y = 1; // Default y -= 1; // Adjust cuY = QMAX(0,QMIN(lines -1, y + (getMode(MODE_Origin) ? tmargin : 0) )); } /*! set cursor to the `left upper' corner of the screen (1,1). */ void TEScreen::home() { cuX = 0; cuY = 0; } /*! set cursor to the begin of the current line. */ void TEScreen::Return() { cuX = 0; } /*! returns the current cursor columns. */ int TEScreen::getCursorX() { return cuX; } /*! returns the current cursor line. */ int TEScreen::getCursorY() { return cuY; } // Erasing --------------------------------------------------------------------- /*! \section Erasing This group of operations erase parts of the screen contents by filling it with spaces colored due to the current rendition settings. Althought the cursor position is involved in most of these operations, it is never modified by them. */ /*! fill screen between (including) `loca' and `loce' with spaces. This is an internal helper functions. The parameter types are internal addresses of within the screen image and make use of the way how the screen matrix is mapped to the image vector. */ void TEScreen::clearImage(int loca, int loce, char c) { int i; int scr_TL=loc(0,hist.getLines()); //FIXME: check positions //Clear entire selection if it overlaps region to be moved... if ( (sel_BR > (loca+scr_TL) )&&(sel_TL < (loce+scr_TL)) ) { clearSelection(); } for (i = loca; i <= loce; i++) { image[i].c = c; image[i].f = ef_fg; //DEFAULT_FORE_COLOR; //FIXME: xterm and linux/ansi image[i].b = ef_bg; //DEFAULT_BACK_COLOR; // many have different image[i].r = ef_re; //DEFAULT_RENDITION; // ideas here. } } /*! move image between (including) `loca' and `loce' to 'dst'. This is an internal helper functions. The parameter types are internal addresses of within the screen image and make use of the way how the screen matrix is mapped to the image vector. */ void TEScreen::moveImage(int dst, int loca, int loce) { //FIXME: check positions if (loce < loca) { // kdDebug() << "WARNING!!! call to TEScreen:moveImage with loce < loca!" << endl; return; } memmove(&image[dst],&image[loca],(loce-loca+1)*sizeof(ca)); } /*! clear from (including) current cursor position to end of screen. */ void TEScreen::clearToEndOfScreen() { clearImage(loc(cuX,cuY),loc(columns-1,lines-1),' '); } /*! clear from begin of screen to (including) current cursor position. */ void TEScreen::clearToBeginOfScreen() { clearImage(loc(0,0),loc(cuX,cuY),' '); } /*! clear the entire screen. */ void TEScreen::clearEntireScreen() { clearImage(loc(0,0),loc(columns-1,lines-1),' '); } /*! fill screen with 'E' This is to aid screen alignment */ void TEScreen::helpAlign() { clearImage(loc(0,0),loc(columns-1,lines-1),'E'); } /*! clear from (including) current cursor position to end of current cursor line. */ void TEScreen::clearToEndOfLine() { clearImage(loc(cuX,cuY),loc(columns-1,cuY),' '); } /*! clear from begin of current cursor line to (including) current cursor position. */ void TEScreen::clearToBeginOfLine() { clearImage(loc(0,cuY),loc(cuX,cuY),' '); } /*! clears entire current cursor line */ void TEScreen::clearEntireLine() { clearImage( loc( 0, cuY),loc( columns - 1, cuY),' '); } // Rendition ------------------------------------------------------------------ /*! set rendition mode */ void TEScreen::setRendition(int re) { cu_re |= re; effectiveRendition(); } /*! reset rendition mode */ void TEScreen::resetRendition(int re) { cu_re &= ~re; effectiveRendition(); } /*! */ void TEScreen::setDefaultRendition() { setForeColorToDefault(); setBackColorToDefault(); cu_re = DEFAULT_RENDITION; effectiveRendition(); } /*! */ void TEScreen::setForeColor(int fgcolor) { cu_fg = (fgcolor&7)+((fgcolor&8) ? 4+8 : 2); effectiveRendition(); } /*! */ void TEScreen::setBackColor(int bgcolor) { cu_bg = (bgcolor&7)+((bgcolor&8) ? 4+8 : 2); effectiveRendition(); } /*! */ void TEScreen::setBackColorToDefault() { cu_bg = DEFAULT_BACK_COLOR; effectiveRendition(); } /*! */ void TEScreen::setForeColorToDefault() { cu_fg = DEFAULT_FORE_COLOR; effectiveRendition(); } /* ------------------------------------------------------------------------- */ /* */ /* Marking & Selection */ /* */ /* ------------------------------------------------------------------------- */ void TEScreen::clearSelection() { sel_BR = -1; sel_TL = -1; sel_begin = -1; } void TEScreen::setSelBeginXY(const int x, const int y) { if (histCursor > hist.getLines()) { histCursor = hist.getLines(); } sel_begin = loc(x,y+histCursor) ; sel_BR = sel_begin; sel_TL = sel_begin; } void TEScreen::setSelExtentXY(const int x, const int y) { if (sel_begin == -1) return; if (histCursor > hist.getLines()) { histCursor = hist.getLines(); } int l = loc(x,y + histCursor); if (l < sel_begin) { sel_TL = l; sel_BR = sel_begin; } else { /* FIXME, HACK to correct for x too far to the right... */ if (( x == columns )|| (x == 0)) l--; sel_TL = sel_begin; sel_BR = l; } } QString TEScreen::getSelText(const BOOL preserve_line_breaks) { if (sel_begin == -1) return QString::null; // Selection got clear while selecting. int *m; // buffer to fill. int s, d; // source index, dest. index. int hist_BR = loc(0, hist.getLines()); int hY = sel_TL / columns; int hX = sel_TL % columns; int eol; // end of line s = sel_TL; // tracks copy in source. // allocate buffer for maximum // possible size... d = (sel_BR - sel_TL) / columns + 1; m = new int[d * (columns + 1) + 2]; d = 0; while (s <= sel_BR) { if (s < hist_BR) { // get lines from hist.history // buffer. eol = hist.getLineLen(hY); if ((hY == (sel_BR / columns)) && (eol >= (sel_BR % columns))) { eol = sel_BR % columns + 1; } while (hX < eol) { m[d++] = hist.getCell(hY, hX++).c; s++; } if (s <= sel_BR) { // The line break handling // It's different from the screen // image case! if (eol % columns == 0) { // That's either a completely filled // line or an empty line if (eol == 0) { m[d++] = '\n'; } else { // We have a full line. // FIXME: How can we handle newlines // at this position?! } } else if ((eol + 1) % columns == 0) { // FIXME: We don't know if this was a // space at the last position or a // short line!! m[d++] = ' '; } else { // We have a short line here. Put a // newline or a space into the // buffer. m[d++] = preserve_line_breaks ? '\n' : ' '; } } hY++; hX = 0; s = hY * columns; } else { // or from screen image. eol = (s / columns + 1) * columns - 1; if (eol < sel_BR) { while ((eol > s) && isspace(image[eol - hist_BR].c)) { eol--; } } else { eol = sel_BR; } while (s <= eol) { m[d++] = image[s++ - hist_BR].c; } if (eol < sel_BR) { // eol processing see below ... if ((eol + 1) % columns == 0) { if (image[eol - hist_BR].c == ' ') { m[d++] = ' '; } } else { m[d++] = ((preserve_line_breaks || ((eol % columns) == 0)) ? '\n' : ' '); } } s = (eol / columns + 1) * columns; } } QChar* qc = new QChar[d]; for (int i = 0; i < d; i++) { qc[i] = m[i]; } QString res(qc, d); delete [] m; delete [] qc; return res; } /* above ... end of line processing for selection -- psilva cases: 1) (eol+1)%columns == 0 --> the whole line is filled. If the last char is a space, insert (preserve) space. otherwise leave the text alone, so that words that are broken by linewrap are preserved. FIXME: * this suppresses \n for command output that is sized to the exact column width of the screen. 2) eol%columns == 0 --> blank line. insert a \n unconditionally. Do it either you would because you are in preserve_line_break mode, or because it's an ASCII paragraph delimiter, so even when not preserving line_breaks, you want to preserve paragraph breaks. 3) else --> partially filled line insert a \n in preserve line break mode, else a space The space prevents concatenation of the last word of one line with the first of the next. */ void TEScreen::addHistLine() { assert(hasScroll() || histCursor == 0); // add to hist buffer // we have to take care about scrolling, too... if (hasScroll()){ ca dft; int end = columns - 1; while (end >= 0 && image[end] == dft) end -= 1; hist.addCells( image, end + 1); hist.addLine(); // adjust history cursor histCursor += ( hist.getLines() - 1 == histCursor); } if (!hasScroll()) histCursor = 0; //FIXME: a poor workaround } void TEScreen::setHistCursor(int cursor) { histCursor = cursor; //FIXME:rangecheck if (histCursor > hist.getLines()) { histCursor = hist.getLines(); } if (histCursor < 0) { histCursor = 0; } } void TEScreen::setHorzCursor(int cursor) { horzCursor = cursor; } int TEScreen::getHistCursor() { return histCursor; } int TEScreen::getHorzCursor() { return horzCursor; } int TEScreen::getHistLines() { return hist.getLines(); } void TEScreen::setScroll(bool on) { histCursor = 0; clearSelection(); hist.setScroll(on); } bool TEScreen::hasScroll() { return hist.hasScroll(); } diff --git a/inputmethods/dasher/PPMLanguageModel.cpp b/inputmethods/dasher/PPMLanguageModel.cpp index 137b07f..d767d16 100644 --- a/inputmethods/dasher/PPMLanguageModel.cpp +++ b/inputmethods/dasher/PPMLanguageModel.cpp @@ -1,309 +1,310 @@ // PPMLanguageModel.h // ///////////////////////////////////////////////////////////////////////////// // // Copyright (c) 1999-2002 David Ward // ///////////////////////////////////////////////////////////////////////////// #include <math.h> #include "PPMLanguageModel.h" using namespace Dasher; using namespace std; // static TCHAR debug[256]; typedef unsigned long ulong; //////////////////////////////////////////////////////////////////////// /// PPMnode definitions //////////////////////////////////////////////////////////////////////// CPPMLanguageModel::CPPMnode *CPPMLanguageModel::CPPMnode::find_symbol(int sym) // see if symbol is a child of node { // printf("finding symbol %d at node %d\n",sym,node->id); CPPMnode *found=child; while (found) { if (found->symbol==sym) return found; found=found->next; } return 0; } CPPMLanguageModel::CPPMnode * CPPMLanguageModel::CPPMnode::add_symbol_to_node(int sym,int *update) { CPPMnode *born,*search; search=find_symbol(sym); if (!search) { born = new CPPMnode(sym); born->next=child; child=born; // node->count=1; return born; } else { if (*update) { // perform update exclusions search->count++; *update=0; } return search; } } ///////////////////////////////////////////////////////////////////// // CPPMLanguageModel defs ///////////////////////////////////////////////////////////////////// CPPMLanguageModel::CPPMLanguageModel(CAlphabet *_alphabet,int _normalization) - : CLanguageModel(_alphabet,_normalization) + : CLanguageModel(_alphabet,_normalization), root(0), m_rootcontext(0) { root=new CPPMnode(-1); m_rootcontext=new CPPMContext(root,0); } CPPMLanguageModel::~CPPMLanguageModel() { + delete m_rootcontext; delete root; } bool CPPMLanguageModel::GetProbs(CContext *context,vector<unsigned int> &probs,double ) // get the probability distribution at the context { // seems like we have to have this hack for VC++ CPPMContext *ppmcontext=static_cast<CPPMContext *> (context); int modelchars=GetNumberModelChars(); int norm=CLanguageModel::normalization(); probs.resize(modelchars); CPPMnode *temp,*s; int loop,total; int sym; // ulong spent=0; ulong size_of_slice; bool *exclusions=new bool [modelchars]; ulong uniform=modelchars; ulong tospend=norm-uniform; temp=ppmcontext->head; for (loop=0; loop <modelchars; loop++) { /* set up the exclusions array */ probs[loop]=0; exclusions[loop]=0; } while (temp!=0) { // Usprintf(debug,TEXT("tospend %u\n"),tospend); // DebugOutput(TEXT("round\n")); total=0; s=temp->child; while (s) { sym=s->symbol; if (!exclusions[s->symbol]) total=total+s->count; s=s->next; } if (total) { // Usprintf(debug,TEXT"escape %u\n"),tospend* size_of_slice=tospend; s=temp->child; while (s) { if (!exclusions[s->symbol]) { exclusions[s->symbol]=1; ulong p=size_of_slice*(2*s->count-1)/2/ulong(total); probs[s->symbol]+=p; tospend-=p; } // Usprintf(debug,TEXT("sym %u counts %d p %u tospend %u \n"),sym,s->count,p,tospend); // DebugOutput(debug); s=s->next; } } temp = temp->vine; } // Usprintf(debug,TEXT("Norm %u tospend %u\n"),Norm,tospend); // DebugOutput(debug); size_of_slice=tospend; int symbolsleft=0; for (sym=1;sym<modelchars;sym++) if (!probs[sym]) symbolsleft++; for (sym=1;sym<modelchars;sym++) if (!probs[sym]) { ulong p=size_of_slice/symbolsleft; probs[sym]+=p; tospend-=p; } // distribute what's left evenly tospend+=uniform; for (sym=1;sym<modelchars;sym++) { ulong p=tospend/(modelchars-sym); probs[sym]+=p; tospend-=p; } // Usprintf(debug,TEXT("finaltospend %u\n"),tospend); // DebugOutput(debug); // free(exclusions); // !!! // !!! NB by IAM: p577 Stroustrup 3rd Edition: "Allocating an object using new and deleting it using free() is asking for trouble" delete[] exclusions; return true; } void CPPMLanguageModel::AddSymbol(CPPMLanguageModel::CPPMContext &context,int symbol) // add symbol to the context // creates new nodes, updates counts // and leaves 'context' at the new context { // sanity check if (symbol==0 || symbol>=GetNumberModelChars()) return; CPPMnode *vineptr,*temp; int updatecnt=1; temp=context.head->vine; context.head=context.head->add_symbol_to_node(symbol,&updatecnt); vineptr=context.head; context.order++; while (temp!=0) { vineptr->vine=temp->add_symbol_to_node(symbol,&updatecnt); vineptr=vineptr->vine; temp=temp->vine; } vineptr->vine=root; if (context.order>MAX_ORDER){ context.head=context.head->vine; context.order--; } } // update context with symbol 'Symbol' void CPPMLanguageModel::EnterSymbol(CContext* Context, modelchar Symbol) { CPPMLanguageModel::CPPMContext& context = * static_cast<CPPMContext *> (Context); CPPMnode *find; // CPPMnode *temp=context.head; while (context.head) { find =context.head->find_symbol(Symbol); if (find) { context.order++; context.head=find; // Usprintf(debug,TEXT("found context %x order %d\n"),head,order); // DebugOutput(debug); return; } context.order--; context.head=context.head->vine; } if (context.head==0) { context.head=root; context.order=0; } } void CPPMLanguageModel::LearnSymbol(CContext* Context, modelchar Symbol) { CPPMLanguageModel::CPPMContext& context = * static_cast<CPPMContext *> (Context); AddSymbol(context, Symbol); } void CPPMLanguageModel::dumpSymbol(int symbol) { if ((symbol <= 32) || (symbol >= 127)) printf( "<%d>", symbol ); else printf( "%c", symbol ); } void CPPMLanguageModel::dumpString( char *str, int pos, int len ) // Dump the string STR starting at position POS { char cc; int p; for (p = pos; p<pos+len; p++) { cc = str [p]; if ((cc <= 31) || (cc >= 127)) printf( "<%d>", cc ); else printf( "%c", cc ); } } void CPPMLanguageModel::dumpTrie( CPPMLanguageModel::CPPMnode *, int ) // diagnostic display of the PPM trie from node t and deeper { //TODO /* dchar debug[256]; int sym; CPPMnode *s; Usprintf( debug,TEXT("%5d %7x "), d, t ); //TODO: Uncomment this when headers sort out //DebugOutput(debug); if (t < 0) // pointer to input printf( " <" ); else { Usprintf(debug,TEXT( " %3d %5d %7x %7x %7x <"), t->symbol,t->count, t->vine, t->child, t->next ); //TODO: Uncomment this when headers sort out //DebugOutput(debug); } dumpString( dumpTrieStr, 0, d ); Usprintf( debug,TEXT(">\n") ); //TODO: Uncomment this when headers sort out //DebugOutput(debug); if (t != 0) { s = t->child; while (s != 0) { sym =s->symbol; dumpTrieStr [d] = sym; dumpTrie( s, d+1 ); s = s->next; } } */ } void CPPMLanguageModel::dump() // diagnostic display of the whole PPM trie { // TODO: /* dchar debug[256]; Usprintf(debug,TEXT( "Dump of Trie : \n" )); //TODO: Uncomment this when headers sort out //DebugOutput(debug); Usprintf(debug,TEXT( "---------------\n" )); //TODO: Uncomment this when headers sort out //DebugOutput(debug); Usprintf( debug,TEXT( "depth node symbol count vine child next context\n") ); //TODO: Uncomment this when headers sort out //DebugOutput(debug); dumpTrie( root, 0 ); Usprintf( debug,TEXT( "---------------\n" )); //TODO: Uncomment this when headers sort out //DebugOutput(debug); Usprintf(debug,TEXT( "\n" )); //TODO: Uncomment this when headers sort out //DebugOutput(debug); */ } diff --git a/noncore/apps/opie-reader/Bkmks.cpp b/noncore/apps/opie-reader/Bkmks.cpp index 440d8be..28f6318 100644 --- a/noncore/apps/opie-reader/Bkmks.cpp +++ b/noncore/apps/opie-reader/Bkmks.cpp @@ -1,399 +1,415 @@ #include <qmessagebox.h> #include "Bkmks.h" #include "StyleConsts.h" #include "Markups.h" #include "my_list.h" #include "version.h" #include "names.h" const unsigned long BkmkFile::magic = ((unsigned long)'q' << 24) | ((unsigned long)'t' << 16) | ((unsigned long)'r' << 8) | ((unsigned long)BKMKTYPE); -Bkmk::Bkmk(const unsigned char* _nm, unsigned short _nmlen, const unsigned char* _anno, unsigned short _annolen, unsigned int _p) +Bkmk::Bkmk(const unsigned char* _nm, unsigned short _nmlen, const unsigned char* _anno, unsigned short _annolen, unsigned int _p) : + m_name(0), + m_namelen(0), + m_anno(0), + m_annolen(0), + m_position(0) { init(_nm, _nmlen, _anno, _annolen, _p); } Bkmk::Bkmk(const tchar* _nm, const unsigned char* _anno, unsigned short annolen, unsigned int _p) : m_position(_p) { init(_nm, sizeof(tchar)*(ustrlen(_nm)+1), _anno, annolen, _p); } +Bkmk::Bkmk(const Bkmk& rhs) : + m_name(0), + m_namelen(0), + m_anno(0), + m_annolen(0), + m_position(0) +{ + init(rhs.name(), sizeof(tchar)*(ustrlen(rhs.name())+1), rhs.anno(), + sizeof(tchar)*(ustrlen(rhs.anno())+1), rhs.value()); +} + Bkmk::Bkmk(const tchar* _nm, const tchar* _anno, unsigned int _p) : m_position(_p) { if (_anno == NULL) { tchar t = 0; init(_nm, sizeof(tchar)*(ustrlen(_nm)+1), &t, sizeof(t), _p); } else { init(_nm, sizeof(tchar)*(ustrlen(_nm)+1), _anno, sizeof(tchar)*(ustrlen(_anno)+1), _p); } } Bkmk::Bkmk(const tchar* _nm, const tchar* _anno, unsigned int _p, unsigned int _p2) : m_position(_p) { if (_anno == NULL) { tchar t = 0; init(_nm, sizeof(tchar)*(ustrlen(_nm)+1), &t, sizeof(t), _p); } else { init(_nm, sizeof(tchar)*(ustrlen(_nm)+1), _anno, sizeof(tchar)*(ustrlen(_anno)+1), _p); } m_position2 = _p2; m_red = m_green = m_blue = 127; } void Bkmk::init(const void* _nm, unsigned short _nmlen, const void* _anno, unsigned short _annolen, unsigned int _p) { m_namelen = _nmlen; if (m_namelen > 0) { m_name = new unsigned char[m_namelen]; memcpy(m_name, _nm, m_namelen); } else { m_name = NULL; } m_annolen = _annolen; if (m_annolen > 0) { m_anno = new unsigned char[m_annolen]; memcpy(m_anno, _anno, m_annolen); } else { m_anno = NULL; } m_position = _p; m_position2 = _p; m_red = m_green = m_blue = 255; m_level = 0; } Bkmk::~Bkmk() { if (m_name != NULL) delete [] m_name; m_name = NULL; if (m_anno != NULL) delete [] m_anno; m_anno = NULL; } Bkmk& Bkmk::operator=(const Bkmk& rhs) { if (m_name != NULL) { delete [] m_name; m_name = NULL; } if (m_anno != NULL) { delete [] m_anno; m_anno = NULL; } if (rhs.m_name != NULL) { m_namelen = rhs.m_namelen; m_name = new unsigned char[m_namelen]; memcpy(m_name, rhs.m_name, m_namelen); } else m_name = NULL; if (rhs.m_anno != NULL) { m_annolen = rhs.m_annolen; m_anno = new unsigned char[m_annolen]; memcpy(m_anno, rhs.m_anno, m_annolen); } else m_anno = NULL; m_position = rhs.m_position; m_position2 = rhs.m_position2; m_red = rhs.m_red; m_green = rhs.m_green; m_blue = rhs.m_blue; m_level = rhs.m_level; return *this; } bool Bkmk::operator==(const Bkmk& rhs) { return ((m_position == rhs.m_position) && (m_position2 == rhs.m_position2) && (rhs.m_namelen == m_namelen) && memcmp(m_name,rhs.m_name,m_namelen) == 0); } void Bkmk::setAnno(unsigned char* t, unsigned short len) { if (m_anno != NULL) { delete [] m_anno; m_anno = NULL; } if (t != NULL) { m_annolen = len; m_anno = new unsigned char[m_annolen]; memcpy(m_anno, t, m_annolen); } else { m_annolen = sizeof(tchar); m_anno = new unsigned char[m_annolen]; *((tchar*)m_anno) = 0; } } void Bkmk::setAnno(tchar* t) { if (m_anno != NULL) { delete [] m_anno; m_anno = NULL; } if (t != NULL) { unsigned short len = ustrlen(t)+1; m_annolen = sizeof(tchar)*len; m_anno = new unsigned char[m_annolen]; memcpy(m_anno, t, m_annolen); } else { m_annolen = sizeof(tchar); m_anno = new unsigned char[m_annolen]; *((tchar*)m_anno) = 0; } } BkmkFile::BkmkFile(const char *fnm, bool w, bool _x) : wt(w), isUpgraded(false), m_extras(_x) { if (w) { f = fopen(fnm, "wb"); } else { f = fopen(fnm, "rb"); } } BkmkFile::~BkmkFile() { if (f != NULL) fclose(f); } void BkmkFile::write(const Bkmk& b) { if (f != NULL) { fwrite(&b.m_namelen, sizeof(b.m_namelen),1,f); fwrite(b.m_name,1,b.m_namelen,f); fwrite(&b.m_annolen, sizeof(b.m_annolen),1,f); fwrite(b.m_anno,1,b.m_annolen,f); fwrite(&b.m_position,sizeof(b.m_position),1,f); if (m_extras) { fwrite(&b.m_position2,sizeof(b.m_position2),1,f); fwrite(&b.m_red,sizeof(b.m_red),1,f); fwrite(&b.m_green,sizeof(b.m_green),1,f); fwrite(&b.m_blue,sizeof(b.m_blue),1,f); fwrite(&b.m_level,sizeof(b.m_level),1,f); } } } void BkmkFile::write(CList<Bkmk>& bl) { if (f != NULL) { fwrite(&magic, sizeof(magic), 1, f); for (CList<Bkmk>::iterator i = bl.begin(); i != bl.end(); i++) { write(*i); } } } CList<Bkmk>* BkmkFile::readall() { CList<Bkmk>* bl = NULL; if (f != NULL) { unsigned long newmagic; fread(&newmagic, sizeof(newmagic), 1, f); if ((newmagic & 0xffffff00) != (magic & 0xffffff00)) { if (QMessageBox::warning(NULL, "Old bookmark file!", "Which version of " PROGNAME "\ndid you upgrade from?", "0_4*", "Any other version") == 0) { fseek(f,0,SEEK_SET); bl = readall00(&read05); } else { fseek(f,0,SEEK_SET); bl = readall00(&read03); } isUpgraded = true; } else { switch(newmagic & 0xff) { case 7: isUpgraded = false; bl = readall00(read07); // qDebug("Correct version!"); break; case 6: isUpgraded = true; bl = readall00(read06); // qDebug("Correct version!"); break; case 5: isUpgraded = true; bl = readall00(read05); // qDebug("Known version!"); break; default: // qDebug("Unknown version!"); isUpgraded = true; bl = readall00(read05); } } } return bl; } CList<Bkmk>* BkmkFile::readall00(Bkmk* (*readfn)(BkmkFile*, FILE*)) { CList<Bkmk>* bl = new CList<Bkmk>; while (1) { Bkmk* b = (*readfn)(this, f); if (b == NULL) break; bl->push_back(*b); delete b; } return bl; } Bkmk* BkmkFile::read03(BkmkFile* /*_this*/, FILE* f) { Bkmk* b = NULL; if (f != NULL) { unsigned short ln; if (fread(&ln,sizeof(ln),1,f) == 1) { tchar* name = new tchar[ln+1]; fread(name,sizeof(tchar),ln,f); name[ln] = 0; ln = 0; tchar* anno = new tchar[ln+1]; anno[ln] = 0; unsigned int pos; fread(&pos,sizeof(pos),1,f); b = new Bkmk(name,anno,pos); } } return b; } Bkmk* BkmkFile::read05(BkmkFile* /*_this*/, FILE* f) { Bkmk* b = NULL; if (f != NULL) { unsigned short ln; if (fread(&ln,sizeof(ln),1,f) == 1) { tchar* nm = new tchar[ln+1]; fread(nm,sizeof(tchar),ln,f); nm[ln] = 0; fread(&ln,sizeof(ln),1,f); tchar* anno = new tchar[ln+1]; if (ln > 0) fread(anno,sizeof(tchar),ln,f); anno[ln] = 0; unsigned int pos; fread(&pos,sizeof(pos),1,f); b = new Bkmk(nm,anno,pos); } } return b; } Bkmk* BkmkFile::read06(BkmkFile* /*_this*/, FILE* f) { Bkmk* b = NULL; if (f != NULL) { unsigned short ln; if (fread(&ln,sizeof(ln),1,f) == 1) { b = new Bkmk; b->m_namelen = ln; b->m_name = new unsigned char[b->m_namelen]; fread(b->m_name,1,b->m_namelen,f); fread(&(b->m_annolen),sizeof(b->m_annolen),1,f); if (b->m_annolen > 0) { b->m_anno = new unsigned char[b->m_annolen]; fread(b->m_anno,1,b->m_annolen,f); } fread(&(b->m_position),sizeof(b->m_position),1,f); b->m_position2 = b->m_position+b->m_namelen-1; b->m_red = b->m_green = b->m_blue = 127; b->m_level = 0; } } return b; } Bkmk* BkmkFile::read07(BkmkFile* _this, FILE* f) { Bkmk* b = NULL; if (f != NULL) { unsigned short ln; if (fread(&ln,sizeof(ln),1,f) == 1) { b = new Bkmk; b->m_namelen = ln; b->m_name = new unsigned char[b->m_namelen]; fread(b->m_name,1,b->m_namelen,f); fread(&(b->m_annolen),sizeof(b->m_annolen),1,f); if (b->m_annolen > 0) { b->m_anno = new unsigned char[b->m_annolen]; fread(b->m_anno,1,b->m_annolen,f); } fread(&(b->m_position),sizeof(b->m_position),1,f); if (_this->m_extras) { fread(&(b->m_position2),sizeof(b->m_position2),1,f); fread(&(b->m_red),sizeof(b->m_red),1,f); fread(&(b->m_green),sizeof(b->m_green),1,f); fread(&(b->m_blue),sizeof(b->m_blue),1,f); fread(&(b->m_level),sizeof(b->m_level),1,f); } else { b->m_position2 = b->m_position; b->m_red = b->m_green = b->m_blue = 255; b->m_level = 0; } } } return b; } diff --git a/noncore/apps/opie-reader/Bkmks.h b/noncore/apps/opie-reader/Bkmks.h index c2275e2..985e158 100644 --- a/noncore/apps/opie-reader/Bkmks.h +++ b/noncore/apps/opie-reader/Bkmks.h @@ -1,84 +1,81 @@ #ifndef __Bkmks_h #define __Bkmks_h #include "config.h" #include "Filedata.h" #include <stdio.h> template<class T> class CList; class Bkmk { friend class BkmkFile; unsigned char* m_name; unsigned short m_namelen; unsigned char* m_anno; unsigned short m_annolen; unsigned int m_position; unsigned int m_position2; unsigned char m_red,m_green,m_blue, m_level; void init(const void*, unsigned short, const void*, unsigned short, unsigned int); public: - Bkmk() : m_name(NULL), m_namelen(0), m_anno(NULL), m_annolen(0), m_position(0) {}; + Bkmk() : m_name(0), m_namelen(0), m_anno(0), m_annolen(0), m_position(0) {}; Bkmk(const unsigned char* _nm, unsigned short _nmlen, const unsigned char* _anno, unsigned short _annolen, unsigned int _p); Bkmk(const tchar* _nm, const unsigned char* _anno, unsigned short _annolen, unsigned int _p); Bkmk(const tchar* _nm, const tchar* _anno, unsigned int _p); Bkmk(const tchar* _nm, const tchar* _anno, unsigned int _p, unsigned int _p2); - Bkmk(const Bkmk& rhs) : m_name(NULL), m_anno(NULL) - { - *this = rhs; - } + Bkmk(const Bkmk& rhs); ~Bkmk(); unsigned int value() const { return m_position; } void value(unsigned int _v) { m_position = _v; } unsigned int value2() const { return m_position2; } void value2(unsigned int _v) { m_position2 = _v; } unsigned char red() { return m_red; } unsigned char green() { return m_green; } unsigned char blue() { return m_blue; } void red(unsigned char _v) { m_red = _v; } void green(unsigned char _v) { m_green = _v; } void blue(unsigned char _v) { m_blue = _v; } unsigned char level() { return m_level; } void level(unsigned char _v) { m_level = _v; } tchar *name() const { return (tchar*)m_name; } tchar *anno() const { return (tchar*)m_anno; } bool operator<(const Bkmk& rhs) { return (m_position < rhs.m_position); } Bkmk& operator=(const Bkmk& rhs); bool operator==(const Bkmk& rhs); void setAnno(tchar* t); void setAnno(unsigned char* t, unsigned short len); unsigned char* filedata() { CFiledata fd(anno()); return m_anno+fd.length(); } unsigned short filedatalen() { CFiledata fd(anno()); return m_annolen - fd.length(); } }; class BkmkFile { FILE* f; bool wt; bool isUpgraded, m_extras; static const unsigned long magic; private: static Bkmk* read07(BkmkFile*, FILE*); static Bkmk* read06(BkmkFile*, FILE*); static Bkmk* read05(BkmkFile*, FILE*); static Bkmk* read03(BkmkFile*, FILE*); CList<Bkmk>* readall00(Bkmk*(*fn)(BkmkFile*, FILE*)); void write(const Bkmk& b); public: bool upgraded() { return isUpgraded; } BkmkFile(const char *fnm, bool w, bool _x); ~BkmkFile(); void write(CList<Bkmk>& bl); CList<Bkmk>* readall(); }; #endif diff --git a/noncore/apps/opie-reader/StyleConsts.cpp b/noncore/apps/opie-reader/StyleConsts.cpp index 77c9d3b..c19fa3d 100644 --- a/noncore/apps/opie-reader/StyleConsts.cpp +++ b/noncore/apps/opie-reader/StyleConsts.cpp @@ -1,108 +1,115 @@ #include <qimage.h> #include "StyleConsts.h" GraphicLink::~GraphicLink() { delete graphic; } +pmstore::pmstore(bool _canScale, QImage* p, bool isLnk, unsigned long tgt) : + count(1), + m_isScaleable(_canScale) +{ + graphic = new GraphicLink(p, isLnk, tgt); +} + pmstore::~pmstore() { //// qDebug("Deleting image"); delete graphic; } CStyle::~CStyle() { if (graphic != NULL) { if (--(graphic->count) == 0) { delete graphic; } } } CStyle::CStyle(const CStyle& rhs) : graphic(NULL) { *this = rhs; } CStyle& CStyle::operator=(const CStyle& rhs) { if (rhs.graphic != NULL) { (rhs.graphic->count)++; if (graphic != NULL) { if (--(graphic->count) == 0) { delete graphic; } } graphic = rhs.graphic; } else { if (graphic != NULL) { if (--(graphic->count) == 0) { delete graphic; } graphic = NULL; } } sty = rhs.sty; return *this; } void CStyle::clearPicture() { if (graphic != NULL) { if (--(graphic->count) == 0) { delete graphic; } graphic = NULL; } } void CStyle::unset() { sty.unset(); if (graphic != NULL) { if (--(graphic->count) == 0) { delete graphic; } graphic = NULL; } } void CStyle::setPicture(bool canScale, QImage* _g, bool il, unsigned long tgt) { if (graphic != NULL) { if (--(graphic->count) == 0) { delete graphic; } graphic = NULL; } if (_g != NULL) graphic = new pmstore(canScale, _g, il, tgt); } void CStyle::invert() { qDebug("Before:<%02x%02x%02x>", sty.bred, sty.bgreen, sty.bblue); qDebug("Before:<%02x%02x%02x>", sty.red, sty.green, sty.blue); sty.bred = 255-sty.bred; sty.bgreen = 255-sty.bgreen; sty.bblue = 255-sty.bblue; sty.red = 255-sty.red; sty.green = 255-sty.green; sty.blue = 255-sty.blue; qDebug("After:<%02x%02x%02x>", sty.bred, sty.bgreen, sty.bblue); qDebug("After:<%02x%02x%02x>", sty.red, sty.green, sty.blue); } diff --git a/noncore/apps/opie-reader/StyleConsts.h b/noncore/apps/opie-reader/StyleConsts.h index 4b7ff4b..5fd9669 100644 --- a/noncore/apps/opie-reader/StyleConsts.h +++ b/noncore/apps/opie-reader/StyleConsts.h @@ -1,232 +1,230 @@ #ifndef __STYLECONSTS_H #define __STYLECONSTS_H typedef unsigned short StyleType; #ifdef _WINDOWS #include <string.h> #endif #include <string.h> #include <stdlib.h> #include <qglobal.h> class QImage; struct GraphicLink { QImage* graphic; bool isLink; unsigned long link; GraphicLink(QImage* p, bool isLnk, unsigned long tgt) : graphic(p), isLink(isLnk), link(tgt) {} ~GraphicLink(); }; -struct pmstore +class pmstore { + public: unsigned int count; bool m_isScaleable; GraphicLink* graphic; - pmstore(bool _canScale, QImage* p, bool isLnk, unsigned long tgt) : count(1), m_isScaleable(_canScale) - { - graphic = new GraphicLink(p, isLnk, tgt); - } + pmstore(bool _canScale, QImage* p, bool isLnk, unsigned long tgt); ~pmstore(); }; enum EalignmentType { m_AlignLeft, m_AlignRight, m_AlignCentre, m_AlignJustify, m_AlignNone }; class CBasicStyle { friend class CStyle; bool m_bold, m_italic; unsigned long m_table; int m_fontsize; EalignmentType m_align; unsigned char red, green, blue; unsigned char bred, bgreen, bblue; unsigned char pred, pgreen, pblue; unsigned long data; unsigned long offset; bool isLink; // bool isVisited; bool m_underline; bool m_strikethru; bool m_monospaced; unsigned char m_leftmargin, m_rightmargin; signed char m_extraspace; signed char m_voffset; CBasicStyle() { unset(); m_table = 0xffffffff; } bool operator!=(const CBasicStyle& rhs) { return (memcmp(this, &rhs, sizeof(CBasicStyle)) != 0); } void unset() { m_bold = false; m_italic = false; m_fontsize = 0; m_align = m_AlignLeft; red = green = blue = 0; bred = bgreen = bblue = 255; pred = pgreen = pblue = 255; data = 0; offset = 0; isLink = false; // isVisited = false; m_underline = false; m_strikethru = false; m_leftmargin = 0; m_rightmargin = 0; m_monospaced = false; m_extraspace = 0; m_voffset = 0; } }; class CStyle { CBasicStyle sty; pmstore* graphic; public: signed char getVOffset() { return sty.m_voffset; } void setVOffset(signed char sp) { sty.m_voffset = sp; } signed char getExtraSpace() { return sty.m_extraspace; } void setExtraSpace(signed char sp) { sty.m_extraspace = sp; } bool getPictureLink() { return (graphic != NULL && graphic->graphic->isLink); } unsigned long getPictureLinkData() { return graphic->graphic->link; } void setLeftMargin(unsigned char m) { sty.m_leftmargin = m; } unsigned char getLeftMargin() { return sty.m_leftmargin; } void setRightMargin(unsigned char m) { sty.m_rightmargin = m; } unsigned char getRightMargin() { return sty.m_rightmargin; } unsigned char Red() { return sty.red; } unsigned char Green() { return sty.green; } unsigned char Blue() { return sty.blue; } void setColour(unsigned char r, unsigned char g, unsigned char b) { sty.red = r; sty.green = g; sty.blue = b; } unsigned char bRed() { return sty.bred; } unsigned char bGreen() { return sty.bgreen; } unsigned char bBlue() { return sty.bblue; } unsigned char pRed() { return sty.pred; } unsigned char pGreen() { return sty.pgreen; } unsigned char pBlue() { return sty.pblue; } void setPaper(unsigned char r, unsigned char g, unsigned char b) { sty.pred = r; sty.pgreen = g; sty.pblue = b; } void setBackground(unsigned char r, unsigned char g, unsigned char b) { sty.bred = r; sty.bgreen = g; sty.bblue = b; } CStyle() : graphic(NULL) {} ~CStyle(); // CStyle(CStyle&); CStyle(const CStyle&); CStyle& operator=(const CStyle&); void unset(); bool isTable() const { return (sty.m_table != 0xffffffff); } void setTable(unsigned long _b) { sty.m_table = _b; } unsigned long getTable() { return sty.m_table; } bool isPicture() const { return (graphic != NULL); } bool canScale() const { return graphic->m_isScaleable; } void clearPicture(); void setPicture(bool canScale, QImage* _g, bool il=false, unsigned long tgt=0); QImage* getPicture() { QImage* pm = ((graphic != NULL) ? graphic->graphic->graphic : NULL); return pm; } void setUnderline() { sty.m_underline = true; } void unsetUnderline() { sty.m_underline = false; } bool isUnderline() { return sty.m_underline; } void setStrikethru() { sty.m_strikethru = true; } void unsetStrikethru() { sty.m_strikethru = false; } bool isStrikethru() { return sty.m_strikethru; } void setBold() { sty.m_bold = true; } void unsetBold() { sty.m_bold = false; } bool isBold() { return sty.m_bold; } void setItalic() { sty.m_italic = true; } void unsetItalic() { sty.m_italic = false; } bool isItalic() { return sty.m_italic; } void setMono() { sty.m_monospaced = true; } void unsetMono() { sty.m_monospaced = false; } bool isMono() { return sty.m_monospaced; } void setLeftJustify() { sty.m_align = m_AlignLeft; } void setRightJustify() { sty.m_align = m_AlignRight; } void setCentreJustify() { sty.m_align = m_AlignCentre; } void setFullJustify() { sty.m_align = m_AlignJustify; } void setNoJustify() { sty.m_align = m_AlignNone; } StyleType getJustify() { return sty.m_align; } void setFontSize(int _fs) { sty.m_fontsize = _fs; } int getFontSize() const { return sty.m_fontsize; } bool operator!=(const CStyle& rhs) { return ( (sty != rhs.sty) || (graphic != rhs.graphic) ); } void setLink(bool _l) { sty.isLink = _l; } bool getLink() { return sty.isLink; } // void setVisited(bool _l) { sty.isVisited = _l; } // bool getVisited() { return sty.isVisited; } void setData(unsigned long _d) { sty.data = _d; } unsigned long getData() { return sty.data; } void setOffset(unsigned long _d) { sty.offset = _d; } unsigned long getOffset() { return sty.offset; } void invert(); }; #endif diff --git a/noncore/apps/opie-write/qrichtext.cpp b/noncore/apps/opie-write/qrichtext.cpp index c27eb1e..f040f1e 100644 --- a/noncore/apps/opie-write/qrichtext.cpp +++ b/noncore/apps/opie-write/qrichtext.cpp @@ -5039,2149 +5039,2148 @@ QTextLineStart *QTextFormatter::bidiReorderLine( QTextParagraph * /*parag*/, QTe delete runs; return ls; } #endif bool QTextFormatter::isBreakable( QTextString *string, int pos ) { const QChar &c = string->at( pos ).c; char ch = c.latin1(); if ( c == QChar_linesep ) return TRUE; if ( c.isSpace() && ch != '\n' && c.unicode() != 0x00a0U ) return TRUE; if ( c.unicode() == 0xad ) // soft hyphen return TRUE; if ( !ch ) { // not latin1, need to do more sophisticated checks for other scripts uchar row = c.row(); if ( row == 0x0e ) { // 0e00 - 0e7f == Thai if ( c.cell() < 0x80 ) { #ifdef HAVE_THAI_BREAKS // check for thai if( string != cachedString ) { // build up string of thai chars QTextCodec *thaiCodec = QTextCodec::codecForMib(2259); if ( !thaiCache ) thaiCache = new QCString; if ( !thaiIt ) thaiIt = ThBreakIterator::createWordInstance(); *thaiCache = thaiCodec->fromUnicode( s->string() ); } thaiIt->setText(thaiCache->data()); for(int i = thaiIt->first(); i != thaiIt->DONE; i = thaiIt->next() ) { if( i == pos ) return TRUE; if( i > pos ) return FALSE; } return FALSE; #else // if we don't have a thai line breaking lib, allow // breaks everywhere except directly before punctuation. return TRUE; #endif } else return FALSE; } if ( row < 0x11 ) // no asian font return FALSE; if ( row > 0x2d && row < 0xfb || row == 0x11 ) // asian line breaking. Everywhere allowed except directly // in front of a punctuation character. return TRUE; } return FALSE; } void QTextFormatter::insertLineStart( QTextParagraph *parag, int index, QTextLineStart *ls ) { if ( index > 0 ) { // we can assume that only first line starts are insrted multiple times parag->lineStartList().insert( index, ls ); return; } QMap<int, QTextLineStart*>::Iterator it; if ( ( it = parag->lineStartList().find( index ) ) == parag->lineStartList().end() ) { parag->lineStartList().insert( index, ls ); } else { delete *it; parag->lineStartList().remove( it ); parag->lineStartList().insert( index, ls ); } } /* Standard pagebreak algorithm using QTextFlow::adjustFlow. Returns the shift of the paragraphs bottom line. */ int QTextFormatter::formatVertically( QTextDocument* doc, QTextParagraph* parag ) { int oldHeight = parag->rect().height(); QMap<int, QTextLineStart*>& lineStarts = parag->lineStartList(); QMap<int, QTextLineStart*>::Iterator it = lineStarts.begin(); int h = parag->prev() ? QMAX(parag->prev()->bottomMargin(),parag->topMargin() ) / 2: 0; for ( ; it != lineStarts.end() ; ++it ) { QTextLineStart * ls = it.data(); ls->y = h; QTextStringChar *c = ¶g->string()->at(it.key()); if ( c && c->customItem() && c->customItem()->ownLine() ) { int h = c->customItem()->height; c->customItem()->pageBreak( parag->rect().y() + ls->y + ls->baseLine - h, doc->flow() ); int delta = c->customItem()->height - h; ls->h += delta; if ( delta ) parag->setMovedDown( TRUE ); } else { int shift = doc->flow()->adjustFlow( parag->rect().y() + ls->y, ls->w, ls->h ); ls->y += shift; if ( shift ) parag->setMovedDown( TRUE ); } h = ls->y + ls->h; } int m = parag->bottomMargin(); if ( !parag->next() ) m = 0; else m = QMAX(m, parag->next()->topMargin() ) / 2; h += m; parag->setHeight( h ); return h - oldHeight; } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ QTextFormatterBreakInWords::QTextFormatterBreakInWords() { } #define SPACE(s) doc?(s>0?s:0):s int QTextFormatterBreakInWords::format( QTextDocument *doc,QTextParagraph *parag, int start, const QMap<int, QTextLineStart*> & ) { QTextStringChar *c = 0; QTextStringChar *firstChar = 0; int left = doc ? parag->leftMargin() + doc->leftMargin() : 0; int x = left + ( doc ? parag->firstLineMargin() : 0 ); int dw = parag->documentVisibleWidth() - ( doc ? doc->rightMargin() : 0 ); int y = parag->prev() ? QMAX(parag->prev()->bottomMargin(),parag->topMargin()) / 2: 0; int h = y; int len = parag->length(); if ( doc ) x = doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), x, 4 ); int rm = parag->rightMargin(); int w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 ); bool fullWidth = TRUE; int minw = 0; int wused = 0; bool wrapEnabled = isWrapEnabled( parag ); start = 0; //######### what is the point with start?! (Matthias) if ( start == 0 ) c = ¶g->string()->at( 0 ); int i = start; QTextLineStart *lineStart = new QTextLineStart( y, y, 0 ); insertLineStart( parag, 0, lineStart ); QPainter *painter = QTextFormat::painter(); int col = 0; int ww = 0; QChar lastChr; for ( ; i < len; ++i, ++col ) { if ( c ) lastChr = c->c; c = ¶g->string()->at( i ); c->rightToLeft = FALSE; // ### the lines below should not be needed if ( painter ) c->format()->setPainter( painter ); if ( i > 0 ) { c->lineStart = 0; } else { c->lineStart = 1; firstChar = c; } if ( c->c.unicode() >= 32 || c->isCustom() ) { ww = parag->string()->width( i ); } else if ( c->c == '\t' ) { int nx = parag->nextTab( i, x - left ) + left; if ( nx < x ) ww = w - x; else ww = nx - x; } else { ww = c->format()->width( ' ' ); } if ( c->isCustom() && c->customItem()->ownLine() ) { x = doc ? doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left; w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 ); c->customItem()->resize( w - x ); w = dw; y += h; h = c->height(); lineStart = new QTextLineStart( y, h, h ); insertLineStart( parag, i, lineStart ); c->lineStart = 1; firstChar = c; x = 0xffffff; continue; } if ( wrapEnabled && ( wrapAtColumn() == -1 && x + ww > w || wrapAtColumn() != -1 && col >= wrapAtColumn() ) ) { x = doc ? parag->document()->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left; w = dw; y += h; h = c->height(); lineStart = formatLine( parag, parag->string(), lineStart, firstChar, SPACE(c-1) ); lineStart->y = y; insertLineStart( parag, i, lineStart ); lineStart->baseLine = c->ascent(); lineStart->h = c->height(); c->lineStart = 1; firstChar = c; col = 0; if ( wrapAtColumn() != -1 ) minw = QMAX( minw, w ); } else if ( lineStart ) { lineStart->baseLine = QMAX( lineStart->baseLine, c->ascent() ); h = QMAX( h, c->height() ); lineStart->h = h; } c->x = x; x += ww; wused = QMAX( wused, x ); } int m = parag->bottomMargin(); if ( !parag->next() ) m = 0; else m = QMAX(m, parag->next()->topMargin() ) / 2; parag->setFullWidth( fullWidth ); y += h + m; if ( doc ) minw += doc->rightMargin(); if ( !wrapEnabled ) minw = QMAX(minw, wused); thisminw = minw; thiswused = wused; return y; } // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ QTextFormatterBreakWords::QTextFormatterBreakWords() { } #define DO_FLOW( lineStart ) do{ if ( doc && doc->isPageBreakEnabled() ) { \ int yflow = lineStart->y + parag->rect().y();\ int shift = doc->flow()->adjustFlow( yflow, dw, lineStart->h ); \ lineStart->y += shift;\ y += shift;\ }}while(FALSE) int QTextFormatterBreakWords::format( QTextDocument *doc, QTextParagraph *parag, int start, const QMap<int, QTextLineStart*> & ) { QTextStringChar *c = 0; QTextStringChar *firstChar = 0; QTextString *string = parag->string(); int left = doc ? parag->leftMargin() + doc->leftMargin() : 0; int x = left + ( doc ? parag->firstLineMargin() : 0 ); int y = parag->prev() ? QMAX(parag->prev()->bottomMargin(),parag->topMargin()) / 2: 0; int h = y; int len = parag->length(); if ( doc ) x = doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), x, 0 ); int dw = parag->documentVisibleWidth() - ( doc ? ( left != x ? 0 : doc->rightMargin() ) : 0 ); int curLeft = x; int rm = parag->rightMargin(); int rdiff = doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 0 ) : 0; int w = dw - rdiff; bool fullWidth = TRUE; int marg = left + rdiff; int minw = 0; int wused = 0; int tminw = marg; int linespacing = doc ? parag->lineSpacing() : 0; bool wrapEnabled = isWrapEnabled( parag ); start = 0; if ( start == 0 ) c = ¶g->string()->at( 0 ); int i = start; QTextLineStart *lineStart = new QTextLineStart( y, y, 0 ); insertLineStart( parag, 0, lineStart ); int lastBreak = -1; int tmpBaseLine = 0, tmph = 0; bool lastWasNonInlineCustom = FALSE; int align = parag->alignment(); if ( align == Qt3::AlignAuto && doc && doc->alignment() != Qt3::AlignAuto ) align = doc->alignment(); align &= Qt3::AlignHorizontal_Mask; QPainter *painter = QTextFormat::painter(); int col = 0; int ww = 0; QChar lastChr; for ( ; i < len; ++i, ++col ) { if ( c ) lastChr = c->c; // ### next line should not be needed if ( painter ) c->format()->setPainter( painter ); c = &string->at( i ); c->rightToLeft = FALSE; if ( i > 0 && (x > curLeft || ww == 0) || lastWasNonInlineCustom ) { c->lineStart = 0; } else { c->lineStart = 1; firstChar = c; } if ( c->isCustom() && c->customItem()->placement() != QTextCustomItem::PlaceInline ) lastWasNonInlineCustom = TRUE; else lastWasNonInlineCustom = FALSE; if ( c->c.unicode() >= 32 || c->isCustom() ) { ww = string->width( i ); } else if ( c->c == '\t' ) { int nx = parag->nextTab( i, x - left ) + left; if ( nx < x ) ww = w - x; else ww = nx - x; } else { ww = c->format()->width( ' ' ); } // last character ("invisible" space) has no width if ( i == len - 1 ) ww = 0; QTextCustomItem* ci = c->customItem(); if ( c->isCustom() && ci->ownLine() ) { x = doc ? doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left; w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 ); QTextLineStart *lineStart2 = formatLine( parag, string, lineStart, firstChar, c-1, align, SPACE(w - x) ); ci->resize( w - x); if ( ci->width < w - x ) { if ( align & Qt::AlignHCenter ) x = ( w - ci->width ) / 2; else if ( align & Qt::AlignRight ) { x = w - ci->width; } } c->x = x; curLeft = x; if ( i == 0 || !isBreakable( string, i - 1 ) || string->at( i - 1 ).lineStart == 0 ) { y += QMAX( h, QMAX( tmph, linespacing ) ); tmph = c->height(); h = tmph; lineStart = lineStart2; lineStart->y = y; insertLineStart( parag, i, lineStart ); c->lineStart = 1; firstChar = c; } else { tmph = c->height(); h = tmph; delete lineStart2; } lineStart->h = h; lineStart->baseLine = h; tmpBaseLine = lineStart->baseLine; lastBreak = -2; x = 0xffffff; minw = QMAX( minw, tminw ); int tw = ci->minimumWidth() + ( doc ? doc->leftMargin() : 0 ); if ( tw < QWIDGETSIZE_MAX ) tminw = tw; else tminw = marg; wused = QMAX( wused, ci->width ); continue; } else if ( c->isCustom() && ci->placement() != QTextCustomItem::PlaceInline ) { int tw = ci->minimumWidth(); if ( tw < QWIDGETSIZE_MAX ) minw = QMAX( minw, tw ); } bool lastWasOwnLineCustomItem = lastBreak == -2; bool hadBreakableChar = lastBreak != -1; bool lastWasHardBreak = lastChr == QChar_linesep; // we break if // 1. the last character was a hard break (QChar_linesep) or // 2. the last charater was a own-line custom item (eg. table or ruler) or // 3. wrapping was enabled, it was not a space and following // condition is true: We either had a breakable character // previously or we ar allowed to break in words and - either // we break at w pixels and the current char would exceed that // or - we break at a column and the current character would // exceed that. if ( lastWasHardBreak || lastWasOwnLineCustomItem || ( wrapEnabled && ( (!c->c.isSpace() && (hadBreakableChar || allowBreakInWords()) && ( (wrapAtColumn() == -1 && x + ww > w) || (wrapAtColumn() != -1 && col >= wrapAtColumn()) ) ) ) ) ) { if ( wrapAtColumn() != -1 ) minw = QMAX( minw, x + ww ); // if a break was forced (no breakable char, hard break or own line custom item), break immediately.... if ( !hadBreakableChar || lastWasHardBreak || lastWasOwnLineCustomItem ) { if ( lineStart ) { lineStart->baseLine = QMAX( lineStart->baseLine, tmpBaseLine ); h = QMAX( h, tmph ); lineStart->h = h; DO_FLOW( lineStart ); } lineStart = formatLine( parag, string, lineStart, firstChar, c-1, align, SPACE(w - x) ); x = doc ? doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left; w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 ); if ( !doc && c->c == '\t' ) { // qt_format_text tab handling int nx = parag->nextTab( i, x - left ) + left; if ( nx < x ) ww = w - x; else ww = nx - x; } curLeft = x; y += QMAX( h, linespacing ); tmph = c->height(); h = 0; lineStart->y = y; insertLineStart( parag, i, lineStart ); lineStart->baseLine = c->ascent(); lineStart->h = c->height(); c->lineStart = 1; firstChar = c; tmpBaseLine = lineStart->baseLine; lastBreak = -1; col = 0; } else { // ... otherwise if we had a breakable char, break there DO_FLOW( lineStart ); i = lastBreak; lineStart = formatLine( parag, string, lineStart, firstChar, parag->at( lastBreak ),align, SPACE(w - string->at( i ).x) ); x = doc ? doc->flow()->adjustLMargin( y + parag->rect().y(), parag->rect().height(), left, 4 ) : left; w = dw - ( doc ? doc->flow()->adjustRMargin( y + parag->rect().y(), parag->rect().height(), rm, 4 ) : 0 ); if ( !doc && c->c == '\t' ) { // qt_format_text tab handling int nx = parag->nextTab( i, x - left ) + left; if ( nx < x ) ww = w - x; else ww = nx - x; } curLeft = x; y += QMAX( h, linespacing ); tmph = c->height(); h = tmph; lineStart->y = y; insertLineStart( parag, i + 1, lineStart ); lineStart->baseLine = c->ascent(); lineStart->h = c->height(); c->lineStart = 1; firstChar = c; tmpBaseLine = lineStart->baseLine; lastBreak = -1; col = 0; tminw = marg; continue; } } else if ( lineStart && isBreakable( string, i ) ) { if ( len <= 2 || i < len - 1 ) { tmpBaseLine = QMAX( tmpBaseLine, c->ascent() ); tmph = QMAX( tmph, c->height() ); } minw = QMAX( minw, tminw ); tminw = marg + ww; lineStart->baseLine = QMAX( lineStart->baseLine, tmpBaseLine ); h = QMAX( h, tmph ); lineStart->h = h; if ( i < len - 2 || c->c != ' ' ) lastBreak = i; } else { tminw += ww; int belowBaseLine = QMAX( tmph - tmpBaseLine, c->height()- c->ascent() ); tmpBaseLine = QMAX( tmpBaseLine, c->ascent() ); tmph = tmpBaseLine + belowBaseLine; } c->x = x; x += ww; wused = QMAX( wused, x ); } // ### hack. The last char in the paragraph is always invisible, // ### and somehow sometimes has a wrong format. It changes // ### between // layouting and printing. This corrects some // ### layouting errors in BiDi mode due to this. if ( len > 1 && !c->isAnchor() ) { c->format()->removeRef(); c->setFormat( string->at( len - 2 ).format() ); c->format()->addRef(); } if ( lineStart ) { lineStart->baseLine = QMAX( lineStart->baseLine, tmpBaseLine ); h = QMAX( h, tmph ); lineStart->h = h; // last line in a paragraph is not justified if ( align == Qt3::AlignJustify || lastChr == QChar_linesep ) align = Qt3::AlignAuto; DO_FLOW( lineStart ); lineStart = formatLine( parag, string, lineStart, firstChar, c, align, SPACE(w - x) ); delete lineStart; } minw = QMAX( minw, tminw ); if ( doc ) minw += doc->rightMargin(); int m = parag->bottomMargin(); if ( !parag->next() ) m = 0; else m = QMAX(m, parag->next()->topMargin() ) / 2; parag->setFullWidth( fullWidth ); y += QMAX( h, linespacing ) + m; wused += rm; if ( !wrapEnabled || wrapAtColumn() != -1 ) minw = QMAX(minw, wused); // This is the case where we are breaking wherever we darn well please // in cases like that, the minw should not be the length of the entire // word, because we necessarily want to show the word on the whole line. // example: word wrap in iconview if ( allowBreakInWords() && minw > wused ) minw = wused; thisminw = minw; thiswused = wused; return y; } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ QTextIndent::QTextIndent() { } // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ QTextFormatCollection::QTextFormatCollection() : cKey( 307 ) { defFormat = new QTextFormat( QApplication::font(), QApplication::palette().color( QPalette::Active, QColorGroup::Text ) ); lastFormat = cres = 0; cflags = -1; cKey.setAutoDelete( TRUE ); cachedFormat = 0; } QTextFormatCollection::~QTextFormatCollection() { delete defFormat; } QTextFormat *QTextFormatCollection::format( QTextFormat *f ) { if ( f->parent() == this || f == defFormat ) { lastFormat = f; lastFormat->addRef(); return lastFormat; } if ( f == lastFormat || ( lastFormat && f->key() == lastFormat->key() ) ) { lastFormat->addRef(); return lastFormat; } QTextFormat *fm = cKey.find( f->key() ); if ( fm ) { lastFormat = fm; lastFormat->addRef(); return lastFormat; } if ( f->key() == defFormat->key() ) return defFormat; lastFormat = createFormat( *f ); lastFormat->collection = this; cKey.insert( lastFormat->key(), lastFormat ); return lastFormat; } QTextFormat *QTextFormatCollection::format( QTextFormat *of, QTextFormat *nf, int flags ) { if ( cres && kof == of->key() && knf == nf->key() && cflags == flags ) { cres->addRef(); return cres; } cres = createFormat( *of ); kof = of->key(); knf = nf->key(); cflags = flags; if ( flags & QTextFormat::Bold ) cres->fn.setBold( nf->fn.bold() ); if ( flags & QTextFormat::Italic ) cres->fn.setItalic( nf->fn.italic() ); if ( flags & QTextFormat::Underline ) cres->fn.setUnderline( nf->fn.underline() ); if ( flags & QTextFormat::StrikeOut ) cres->fn.setStrikeOut( nf->fn.strikeOut() ); if ( flags & QTextFormat::Family ) cres->fn.setFamily( nf->fn.family() ); if ( flags & QTextFormat::Size ) { if ( of->usePixelSizes ) cres->fn.setPixelSize( nf->fn.pixelSize() ); else cres->fn.setPointSize( nf->fn.pointSize() ); } if ( flags & QTextFormat::Color ) cres->col = nf->col; if ( flags & QTextFormat::Misspelled ) cres->missp = nf->missp; if ( flags & QTextFormat::VAlign ) cres->ha = nf->ha; cres->update(); QTextFormat *fm = cKey.find( cres->key() ); if ( !fm ) { cres->collection = this; cKey.insert( cres->key(), cres ); } else { delete cres; cres = fm; cres->addRef(); } return cres; } QTextFormat *QTextFormatCollection::format( const QFont &f, const QColor &c ) { if ( cachedFormat && cfont == f && ccol == c ) { cachedFormat->addRef(); return cachedFormat; } QString key = QTextFormat::getKey( f, c, FALSE, QTextFormat::AlignNormal ); cachedFormat = cKey.find( key ); cfont = f; ccol = c; if ( cachedFormat ) { cachedFormat->addRef(); return cachedFormat; } if ( key == defFormat->key() ) return defFormat; cachedFormat = createFormat( f, c ); cachedFormat->collection = this; cKey.insert( cachedFormat->key(), cachedFormat ); if ( cachedFormat->key() != key ) owarn << "ASSERT: keys for format not identical: '" << cachedFormat->key().latin1() << " '" << key.latin1() << "'" << oendl; return cachedFormat; } void QTextFormatCollection::remove( QTextFormat *f ) { if ( lastFormat == f ) lastFormat = 0; if ( cres == f ) cres = 0; if ( cachedFormat == f ) cachedFormat = 0; cKey.remove( f->key() ); } #define UPDATE( up, lo, rest ) \ if ( font.lo##rest() != defFormat->fn.lo##rest() && fm->fn.lo##rest() == defFormat->fn.lo##rest() ) \ fm->fn.set##up##rest( font.lo##rest() ) void QTextFormatCollection::updateDefaultFormat( const QFont &font, const QColor &color, QStyleSheet *sheet ) { QDictIterator<QTextFormat> it( cKey ); QTextFormat *fm; bool usePixels = font.pointSize() == -1; bool changeSize = usePixels ? font.pixelSize() != defFormat->fn.pixelSize() : font.pointSize() != defFormat->fn.pointSize(); int base = usePixels ? font.pixelSize() : font.pointSize(); while ( ( fm = it.current() ) ) { ++it; UPDATE( F, f, amily ); UPDATE( W, w, eight ); UPDATE( B, b, old ); UPDATE( I, i, talic ); UPDATE( U, u, nderline ); if ( changeSize ) { fm->stdSize = base; fm->usePixelSizes = usePixels; if ( usePixels ) fm->fn.setPixelSize( fm->stdSize ); else fm->fn.setPointSize( fm->stdSize ); sheet->scaleFont( fm->fn, fm->logicalFontSize ); } if ( color.isValid() && color != defFormat->col && fm->col == defFormat->col ) fm->col = color; fm->update(); } defFormat->fn = font; defFormat->col = color; defFormat->update(); defFormat->stdSize = base; defFormat->usePixelSizes = usePixels; updateKeys(); } // the keys in cKey have changed, rebuild the hashtable void QTextFormatCollection::updateKeys() { if ( cKey.isEmpty() ) return; cKey.setAutoDelete( FALSE ); QTextFormat** formats = new QTextFormat*[ cKey.count() + 1 ]; QTextFormat **f = formats; QDictIterator<QTextFormat> it( cKey ); while ( ( *f = it.current() ) ) { ++it; ++f; } cKey.clear(); for ( f = formats; *f; f++ ) cKey.insert( (*f)->key(), *f ); cKey.setAutoDelete( TRUE ); delete [] formats; } // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ void QTextFormat::setBold( bool b ) { if ( b == fn.bold() ) return; fn.setBold( b ); update(); } void QTextFormat::setMisspelled( bool b ) { if ( b == (bool)missp ) return; missp = b; update(); } void QTextFormat::setVAlign( VerticalAlignment a ) { if ( a == ha ) return; ha = a; update(); } void QTextFormat::setItalic( bool b ) { if ( b == fn.italic() ) return; fn.setItalic( b ); update(); } void QTextFormat::setUnderline( bool b ) { if ( b == fn.underline() ) return; fn.setUnderline( b ); update(); } void QTextFormat::setStrikeOut( bool b ) { if ( b == fn.strikeOut() ) return; fn.setStrikeOut( b ); update(); } void QTextFormat::setFamily( const QString &f ) { if ( f == fn.family() ) return; fn.setFamily( f ); update(); } void QTextFormat::setPointSize( int s ) { if ( s == fn.pointSize() ) return; fn.setPointSize( s ); usePixelSizes = FALSE; update(); } void QTextFormat::setFont( const QFont &f ) { if ( f == fn && !k.isEmpty() ) return; fn = f; update(); } void QTextFormat::setColor( const QColor &c ) { if ( c == col ) return; col = c; update(); } QString QTextFormat::makeFormatChangeTags( QTextFormat* defaultFormat, QTextFormat *f, const QString& oldAnchorHref, const QString& anchorHref ) const { QString tag; if ( f ) tag += f->makeFormatEndTags( defaultFormat, oldAnchorHref ); if ( !anchorHref.isEmpty() ) tag += "<a href=\"" + anchorHref + "\">"; if ( font() != defaultFormat->font() || vAlign() != defaultFormat->vAlign() || color().rgb() != defaultFormat->color().rgb() ) { QString s; if ( font().family() != defaultFormat->font().family() ) s += QString(!!s?";":"") + "font-family:" + fn.family(); if ( font().italic() && font().italic() != defaultFormat->font().italic() ) s += QString(!!s?";":"") + "font-style:" + (font().italic() ? "italic" : "normal"); if ( font().pointSize() != defaultFormat->font().pointSize() ) s += QString(!!s?";":"") + "font-size:" + QString::number( fn.pointSize() ) + "pt"; if ( font().weight() != defaultFormat->font().weight() ) s += QString(!!s?";":"") + "font-weight:" + QString::number( fn.weight() * 8 ); if ( font().underline() != defaultFormat->font().underline() ) s += QString(!!s?";":"") + "text-decoration:" + ( font().underline() ? "underline" : "none"); if ( vAlign() != defaultFormat->vAlign() ) { s += QString(!!s?";":"") + "vertical-align:"; if ( vAlign() == QTextFormat::AlignSuperScript ) s += "super"; else if ( vAlign() == QTextFormat::AlignSubScript ) s += "sub"; else s += "normal"; } if ( color().rgb() != defaultFormat->color().rgb() ) s += QString(!!s?";":"") + "color:" + col.name(); if ( !s.isEmpty() ) tag += "<span style=\"" + s + "\">"; } return tag; } QString QTextFormat::makeFormatEndTags( QTextFormat* defaultFormat, const QString& anchorHref ) const { QString tag; if ( font().family() != defaultFormat->font().family() || font().pointSize() != defaultFormat->font().pointSize() || font().weight() != defaultFormat->font().weight() || font().italic() != defaultFormat->font().italic() || font().underline() != defaultFormat->font().underline() || font().strikeOut() != defaultFormat->font().strikeOut() || vAlign() != defaultFormat->vAlign() || color().rgb() != defaultFormat->color().rgb() ) tag += "</span>"; if ( !anchorHref.isEmpty() ) tag += "</a>"; return tag; } QTextFormat QTextFormat::makeTextFormat( const QStyleSheetItem *style, const QMap<QString,QString>& attr, double scaleFontsFactor ) const { QTextFormat format(*this); if (!style ) return format; if ( !style->isAnchor() && style->color().isValid() ) { // the style is not an anchor and defines a color. // It might be used inside an anchor and it should // override the link color. format.linkColor = FALSE; } switch ( style->verticalAlignment() ) { case QStyleSheetItem::VAlignBaseline: format.setVAlign( QTextFormat::AlignNormal ); break; case QStyleSheetItem::VAlignSuper: format.setVAlign( QTextFormat::AlignSuperScript ); break; case QStyleSheetItem::VAlignSub: format.setVAlign( QTextFormat::AlignSubScript ); break; } if ( style->fontWeight() != QStyleSheetItem::Undefined ) format.fn.setWeight( style->fontWeight() ); if ( style->fontSize() != QStyleSheetItem::Undefined ) { format.fn.setPointSize( style->fontSize() ); } else if ( style->logicalFontSize() != QStyleSheetItem::Undefined ) { format.logicalFontSize = style->logicalFontSize(); if ( format.usePixelSizes ) format.fn.setPixelSize( format.stdSize ); else format.fn.setPointSize( format.stdSize ); style->styleSheet()->scaleFont( format.fn, format.logicalFontSize ); } else if ( style->logicalFontSizeStep() ) { format.logicalFontSize += style->logicalFontSizeStep(); if ( format.usePixelSizes ) format.fn.setPixelSize( format.stdSize ); else format.fn.setPointSize( format.stdSize ); style->styleSheet()->scaleFont( format.fn, format.logicalFontSize ); } if ( !style->fontFamily().isEmpty() ) format.fn.setFamily( style->fontFamily() ); if ( style->color().isValid() ) format.col = style->color(); if ( style->definesFontItalic() ) format.fn.setItalic( style->fontItalic() ); if ( style->definesFontUnderline() ) format.fn.setUnderline( style->fontUnderline() ); if ( style->definesFontStrikeOut() ) format.fn.setStrikeOut( style->fontStrikeOut() ); if ( style->name() == "font") { if ( attr.contains("color") ) { QString s = attr["color"]; if ( !s.isEmpty() ) { format.col.setNamedColor( s ); format.linkColor = FALSE; } } if ( attr.contains("face") ) { QString a = attr["face"]; QString family = QTextDocument::section( a, ",", 0, 0 ); if ( !!family ) format.fn.setFamily( family ); } if ( attr.contains("size") ) { QString a = attr["size"]; int n = a.toInt(); if ( a[0] == '+' || a[0] == '-' ) n += format.logicalFontSize; format.logicalFontSize = n; if ( format.usePixelSizes ) format.fn.setPixelSize( format.stdSize ); else format.fn.setPointSize( format.stdSize ); style->styleSheet()->scaleFont( format.fn, format.logicalFontSize ); } } if ( attr.contains("style" ) ) { QString a = attr["style"]; for ( int s = 0; s < a.contains(';')+1; s++ ) { QString style = QTextDocument::section( a, ";", s, s ); if ( style.startsWith("font-size:" ) && QTextDocument::endsWith(style, "pt") ) { format.logicalFontSize = 0; format.setPointSize( int( scaleFontsFactor * style.mid( 10, style.length() - 12 ).toInt() ) ); } if ( style.startsWith("font-style:" ) ) { QString s = style.mid( 11 ).stripWhiteSpace(); if ( s == "normal" ) format.fn.setItalic( FALSE ); else if ( s == "italic" || s == "oblique" ) format.fn.setItalic( TRUE ); } else if ( style.startsWith("font-weight:" ) ) { QString s = style.mid( 12 ); bool ok = TRUE; int n = s.toInt( &ok ); if ( ok ) format.fn.setWeight( n/8 ); } else if ( style.startsWith("font-family:" ) ) { format.fn.setFamily( QTextDocument::section(style.mid(12),",",0,0).stripWhiteSpace() ); } else if ( style.startsWith("text-decoration:" ) ) { QString s = style.mid( 16 ).stripWhiteSpace(); format.fn.setUnderline( s == "underline" ); } else if ( style.startsWith("vertical-align:" ) ) { QString s = style.mid( 15 ).stripWhiteSpace(); if ( s == "sub" ) format.setVAlign( QTextFormat::AlignSubScript ); else if ( s == "super" ) format.setVAlign( QTextFormat::AlignSuperScript ); else format.setVAlign( QTextFormat::AlignNormal ); } else if ( style.startsWith("color:" ) ) { format.col.setNamedColor( style.mid(6) ); format.linkColor = FALSE; } } } format.update(); return format; } struct QPixmapInt { QPixmapInt() : ref( 0 ) {} QPixmap pm; int ref; }; static QMap<QString, QPixmapInt> *pixmap_map = 0; QTextImage::QTextImage( QTextDocument *p, const QMap<QString, QString> &attr, const QString& context, QMimeSourceFactory &factory ) - : QTextCustomItem( p ) + : QTextCustomItem( p ), reg( 0 ) { width = height = 0; if ( attr.contains("width") ) width = attr["width"].toInt(); if ( attr.contains("height") ) height = attr["height"].toInt(); - reg = 0; QString imageName = attr["src"]; if (!imageName) imageName = attr["source"]; if ( !imageName.isEmpty() ) { imgId = QString( "%1,%2,%3,%4" ).arg( imageName ).arg( width ).arg( height ).arg( (ulong)&factory ); if ( !pixmap_map ) pixmap_map = new QMap<QString, QPixmapInt>; if ( pixmap_map->contains( imgId ) ) { QPixmapInt& pmi = pixmap_map->operator[](imgId); pm = pmi.pm; pmi.ref++; width = pm.width(); height = pm.height(); } else { QImage img; const QMimeSource* m = factory.data( imageName, context ); if ( !m ) { owarn << "QTextImage: no mimesource for " << imageName.latin1() << "" << oendl; } else { if ( !QImageDrag::decode( m, img ) ) { owarn << "QTextImage: cannot decode " << imageName.latin1() << "" << oendl; } } if ( !img.isNull() ) { if ( width == 0 ) { width = img.width(); if ( height != 0 ) { width = img.width() * height / img.height(); } } if ( height == 0 ) { height = img.height(); if ( width != img.width() ) { height = img.height() * width / img.width(); } } if ( img.width() != width || img.height() != height ){ #ifndef QT_NO_IMAGE_SMOOTHSCALE img = img.smoothScale(width, height); #endif width = img.width(); height = img.height(); } pm.convertFromImage( img ); } if ( !pm.isNull() ) { QPixmapInt& pmi = pixmap_map->operator[](imgId); pmi.pm = pm; pmi.ref++; } } if ( pm.mask() ) { QRegion mask( *pm.mask() ); QRegion all( 0, 0, pm.width(), pm.height() ); reg = new QRegion( all.subtract( mask ) ); } } if ( pm.isNull() && (width*height)==0 ) width = height = 50; place = PlaceInline; if ( attr["align"] == "left" ) place = PlaceLeft; else if ( attr["align"] == "right" ) place = PlaceRight; tmpwidth = width; tmpheight = height; attributes = attr; } QTextImage::~QTextImage() { + delete reg; if ( pixmap_map && pixmap_map->contains( imgId ) ) { QPixmapInt& pmi = pixmap_map->operator[](imgId); pmi.ref--; if ( !pmi.ref ) { pixmap_map->remove( imgId ); if ( pixmap_map->isEmpty() ) { delete pixmap_map; pixmap_map = 0; } } } - delete reg; } QString QTextImage::richText() const { QString s; s += "<img "; QMap<QString, QString>::ConstIterator it = attributes.begin(); for ( ; it != attributes.end(); ++it ) s += it.key() + "=" + *it + " "; s += ">"; return s; } void QTextImage::adjustToPainter( QPainter* p ) { width = scale( tmpwidth, p ); height = scale( tmpheight, p ); } #if !defined(Q_WS_X11) #include <qbitmap.h> #include "qcleanuphandler.h" static QPixmap *qrt_selection = 0; static QSingleCleanupHandler<QPixmap> qrt_cleanup_pixmap; static void qrt_createSelectionPixmap( const QColorGroup &cg ) { qrt_selection = new QPixmap( 2, 2 ); qrt_cleanup_pixmap.set( &qrt_selection ); qrt_selection->fill( Qt::color0 ); QBitmap m( 2, 2 ); m.fill( Qt::color1 ); QPainter p( &m ); p.setPen( Qt::color0 ); for ( int j = 0; j < 2; ++j ) { p.drawPoint( j % 2, j ); } p.end(); qrt_selection->setMask( m ); qrt_selection->fill( cg.highlight() ); } #endif void QTextImage::draw( QPainter* p, int x, int y, int cx, int cy, int cw, int ch, const QColorGroup& cg, bool selected ) { if ( placement() != PlaceInline ) { x = xpos; y = ypos; } if ( pm.isNull() ) { p->fillRect( x , y, width, height, cg.dark() ); return; } if ( is_printer( p ) ) { p->drawPixmap( x, y, pm ); return; } if ( placement() != PlaceInline && !QRect( xpos, ypos, width, height ).intersects( QRect( cx, cy, cw, ch ) ) ) return; if ( placement() == PlaceInline ) p->drawPixmap( x , y, pm ); else p->drawPixmap( cx , cy, pm, cx - x, cy - y, cw, ch ); if ( selected && placement() == PlaceInline && is_printer( p ) ) { #if defined(Q_WS_X11) p->fillRect( QRect( QPoint( x, y ), pm.size() ), QBrush( cg.highlight(), QBrush::Dense4Pattern) ); #else // in WIN32 Dense4Pattern doesn't work correctly (transparency problem), so work around it if ( !qrt_selection ) qrt_createSelectionPixmap( cg ); p->drawTiledPixmap( x, y, pm.width(), pm.height(), *qrt_selection ); #endif } } void QTextHorizontalLine::adjustToPainter( QPainter* p ) { height = scale( tmpheight, p ); } QTextHorizontalLine::QTextHorizontalLine( QTextDocument *p, const QMap<QString, QString> &attr, const QString &, QMimeSourceFactory & ) : QTextCustomItem( p ) { height = tmpheight = 8; if ( attr.find( "color" ) != attr.end() ) color = QColor( *attr.find( "color" ) ); } QTextHorizontalLine::~QTextHorizontalLine() { } QString QTextHorizontalLine::richText() const { return "<hr>"; } void QTextHorizontalLine::draw( QPainter* p, int x, int y, int , int , int , int , const QColorGroup& cg, bool selected ) { QRect r( x, y, width, height); if ( is_printer( p ) ) { QPen oldPen = p->pen(); if ( !color.isValid() ) p->setPen( QPen( cg.text(), height/8 ) ); else p->setPen( QPen( color, height/8 ) ); p->drawLine( r.left()-1, y + height / 2, r.right() + 1, y + height / 2 ); p->setPen( oldPen ); } else { QColorGroup g( cg ); if ( color.isValid() ) g.setColor( QColorGroup::Dark, color ); if ( selected ) p->fillRect( r.left(), y, r.right(), y + height, g.highlight() ); qDrawShadeLine( p, r.left() - 1, y + height / 2, r.right() + 1, y + height / 2, g, TRUE, height / 8 ); } } /*****************************************************************/ // Small set of utility functions to make the parser a bit simpler // bool QTextDocument::hasPrefix(const QChar* doc, int length, int pos, QChar c) { if ( pos >= length ) return FALSE; return doc[ pos ].lower() == c.lower(); } bool QTextDocument::hasPrefix( const QChar* doc, int length, int pos, const QString& s ) { if ( pos + (int) s.length() >= length ) return FALSE; for ( int i = 0; i < (int)s.length(); i++ ) { if ( doc[ pos + i ].lower() != s[ i ].lower() ) return FALSE; } return TRUE; } static bool qt_is_cell_in_use( QPtrList<QTextTableCell>& cells, int row, int col ) { for ( QTextTableCell* c = cells.first(); c; c = cells.next() ) { if ( row >= c->row() && row < c->row() + c->rowspan() && col >= c->column() && col < c->column() + c->colspan() ) return TRUE; } return FALSE; } QTextCustomItem* QTextDocument::parseTable( const QMap<QString, QString> &attr, const QTextFormat &fmt, const QChar* doc, int length, int& pos, QTextParagraph *curpar ) { QTextTable* table = new QTextTable( this, attr ); int row = -1; int col = -1; QString rowbgcolor; QString rowalign; QString tablebgcolor = attr["bgcolor"]; QPtrList<QTextTableCell> multicells; QString tagname; (void) eatSpace(doc, length, pos); while ( pos < length) { if (hasPrefix(doc, length, pos, QChar('<')) ){ if (hasPrefix(doc, length, pos+1, QChar('/'))) { tagname = parseCloseTag( doc, length, pos ); if ( tagname == "table" ) { return table; } } else { QMap<QString, QString> attr2; bool emptyTag = FALSE; tagname = parseOpenTag( doc, length, pos, attr2, emptyTag ); if ( tagname == "tr" ) { rowbgcolor = attr2["bgcolor"]; rowalign = attr2["align"]; row++; col = -1; } else if ( tagname == "td" || tagname == "th" ) { col++; while ( qt_is_cell_in_use( multicells, row, col ) ) { col++; } if ( row >= 0 && col >= 0 ) { const QStyleSheetItem* s = sheet_->item(tagname); if ( !attr2.contains("bgcolor") ) { if (!rowbgcolor.isEmpty() ) attr2["bgcolor"] = rowbgcolor; else if (!tablebgcolor.isEmpty() ) attr2["bgcolor"] = tablebgcolor; } if ( !attr2.contains("align") ) { if (!rowalign.isEmpty() ) attr2["align"] = rowalign; } // extract the cell contents int end = pos; while ( end < length && !hasPrefix( doc, length, end, "</td") && !hasPrefix( doc, length, end, "<td") && !hasPrefix( doc, length, end, "</th") && !hasPrefix( doc, length, end, "<th") && !hasPrefix( doc, length, end, "<td") && !hasPrefix( doc, length, end, "</tr") && !hasPrefix( doc, length, end, "<tr") && !hasPrefix( doc, length, end, "</table") ) { if ( hasPrefix( doc, length, end, "<table" ) ) { // nested table int nested = 1; ++end; while ( end < length && nested != 0 ) { if ( hasPrefix( doc, length, end, "</table" ) ) nested--; if ( hasPrefix( doc, length, end, "<table" ) ) nested++; end++; } } end++; } QTextTableCell* cell = new QTextTableCell( table, row, col, attr2, s, fmt.makeTextFormat( s, attr2, scaleFontsFactor ), contxt, *factory_, sheet_, QString( doc, length).mid( pos, end - pos ) ); cell->richText()->parentPar = curpar; if ( cell->colspan() > 1 || cell->rowspan() > 1 ) multicells.append( cell ); col += cell->colspan()-1; pos = end; } } } } else { ++pos; } } return table; } bool QTextDocument::eatSpace(const QChar* doc, int length, int& pos, bool includeNbsp ) { int old_pos = pos; while (pos < length && doc[pos].isSpace() && ( includeNbsp || (doc[pos] != QChar::nbsp ) ) ) pos++; return old_pos < pos; } bool QTextDocument::eat(const QChar* doc, int length, int& pos, QChar c) { bool ok = pos < length && doc[pos] == c; if ( ok ) pos++; return ok; } /*****************************************************************/ struct Entity { const char * name; Q_UINT16 code; }; static const Entity entitylist [] = { { "AElig", 0x00c6 }, { "Aacute", 0x00c1 }, { "Acirc", 0x00c2 }, { "Agrave", 0x00c0 }, { "Alpha", 0x0391 }, { "AMP", 38 }, { "Aring", 0x00c5 }, { "Atilde", 0x00c3 }, { "Auml", 0x00c4 }, { "Beta", 0x0392 }, { "Ccedil", 0x00c7 }, { "Chi", 0x03a7 }, { "Dagger", 0x2021 }, { "Delta", 0x0394 }, { "ETH", 0x00d0 }, { "Eacute", 0x00c9 }, { "Ecirc", 0x00ca }, { "Egrave", 0x00c8 }, { "Epsilon", 0x0395 }, { "Eta", 0x0397 }, { "Euml", 0x00cb }, { "Gamma", 0x0393 }, { "GT", 62 }, { "Iacute", 0x00cd }, { "Icirc", 0x00ce }, { "Igrave", 0x00cc }, { "Iota", 0x0399 }, { "Iuml", 0x00cf }, { "Kappa", 0x039a }, { "Lambda", 0x039b }, { "LT", 60 }, { "Mu", 0x039c }, { "Ntilde", 0x00d1 }, { "Nu", 0x039d }, { "OElig", 0x0152 }, { "Oacute", 0x00d3 }, { "Ocirc", 0x00d4 }, { "Ograve", 0x00d2 }, { "Omega", 0x03a9 }, { "Omicron", 0x039f }, { "Oslash", 0x00d8 }, { "Otilde", 0x00d5 }, { "Ouml", 0x00d6 }, { "Phi", 0x03a6 }, { "Pi", 0x03a0 }, { "Prime", 0x2033 }, { "Psi", 0x03a8 }, { "QUOT", 34 }, { "Rho", 0x03a1 }, { "Scaron", 0x0160 }, { "Sigma", 0x03a3 }, { "THORN", 0x00de }, { "Tau", 0x03a4 }, { "Theta", 0x0398 }, { "Uacute", 0x00da }, { "Ucirc", 0x00db }, { "Ugrave", 0x00d9 }, { "Upsilon", 0x03a5 }, { "Uuml", 0x00dc }, { "Xi", 0x039e }, { "Yacute", 0x00dd }, { "Yuml", 0x0178 }, { "Zeta", 0x0396 }, { "aacute", 0x00e1 }, { "acirc", 0x00e2 }, { "acute", 0x00b4 }, { "aelig", 0x00e6 }, { "agrave", 0x00e0 }, { "alefsym", 0x2135 }, { "alpha", 0x03b1 }, { "amp", 38 }, { "and", 0x22a5 }, { "ang", 0x2220 }, { "apos", 0x0027 }, { "aring", 0x00e5 }, { "asymp", 0x2248 }, { "atilde", 0x00e3 }, { "auml", 0x00e4 }, { "bdquo", 0x201e }, { "beta", 0x03b2 }, { "brvbar", 0x00a6 }, { "bull", 0x2022 }, { "cap", 0x2229 }, { "ccedil", 0x00e7 }, { "cedil", 0x00b8 }, { "cent", 0x00a2 }, { "chi", 0x03c7 }, { "circ", 0x02c6 }, { "clubs", 0x2663 }, { "cong", 0x2245 }, { "copy", 0x00a9 }, { "crarr", 0x21b5 }, { "cup", 0x222a }, { "curren", 0x00a4 }, { "dArr", 0x21d3 }, { "dagger", 0x2020 }, { "darr", 0x2193 }, { "deg", 0x00b0 }, { "delta", 0x03b4 }, { "diams", 0x2666 }, { "divide", 0x00f7 }, { "eacute", 0x00e9 }, { "ecirc", 0x00ea }, { "egrave", 0x00e8 }, { "empty", 0x2205 }, { "emsp", 0x2003 }, { "ensp", 0x2002 }, { "epsilon", 0x03b5 }, { "equiv", 0x2261 }, { "eta", 0x03b7 }, { "eth", 0x00f0 }, { "euml", 0x00eb }, { "euro", 0x20ac }, { "exist", 0x2203 }, { "fnof", 0x0192 }, { "forall", 0x2200 }, { "frac12", 0x00bd }, { "frac14", 0x00bc }, { "frac34", 0x00be }, { "frasl", 0x2044 }, { "gamma", 0x03b3 }, { "ge", 0x2265 }, { "gt", 62 }, { "hArr", 0x21d4 }, { "harr", 0x2194 }, { "hearts", 0x2665 }, { "hellip", 0x2026 }, { "iacute", 0x00ed }, { "icirc", 0x00ee }, { "iexcl", 0x00a1 }, { "igrave", 0x00ec }, { "image", 0x2111 }, { "infin", 0x221e }, { "int", 0x222b }, { "iota", 0x03b9 }, { "iquest", 0x00bf }, { "isin", 0x2208 }, { "iuml", 0x00ef }, { "kappa", 0x03ba }, { "lArr", 0x21d0 }, { "lambda", 0x03bb }, { "lang", 0x2329 }, { "laquo", 0x00ab }, { "larr", 0x2190 }, { "lceil", 0x2308 }, { "ldquo", 0x201c }, { "le", 0x2264 }, { "lfloor", 0x230a }, { "lowast", 0x2217 }, { "loz", 0x25ca }, { "lrm", 0x200e }, { "lsaquo", 0x2039 }, { "lsquo", 0x2018 }, { "lt", 60 }, { "macr", 0x00af }, { "mdash", 0x2014 }, { "micro", 0x00b5 }, { "middot", 0x00b7 }, { "minus", 0x2212 }, { "mu", 0x03bc }, { "nabla", 0x2207 }, { "nbsp", 0x00a0 }, { "ndash", 0x2013 }, { "ne", 0x2260 }, { "ni", 0x220b }, { "not", 0x00ac }, { "notin", 0x2209 }, { "nsub", 0x2284 }, { "ntilde", 0x00f1 }, { "nu", 0x03bd }, { "oacute", 0x00f3 }, { "ocirc", 0x00f4 }, { "oelig", 0x0153 }, { "ograve", 0x00f2 }, { "oline", 0x203e }, { "omega", 0x03c9 }, { "omicron", 0x03bf }, { "oplus", 0x2295 }, { "or", 0x22a6 }, { "ordf", 0x00aa }, { "ordm", 0x00ba }, { "oslash", 0x00f8 }, { "otilde", 0x00f5 }, { "otimes", 0x2297 }, { "ouml", 0x00f6 }, { "para", 0x00b6 }, { "part", 0x2202 }, { "percnt", 0x0025 }, { "permil", 0x2030 }, { "perp", 0x22a5 }, { "phi", 0x03c6 }, { "pi", 0x03c0 }, { "piv", 0x03d6 }, { "plusmn", 0x00b1 }, { "pound", 0x00a3 }, { "prime", 0x2032 }, { "prod", 0x220f }, { "prop", 0x221d }, { "psi", 0x03c8 }, { "quot", 34 }, { "rArr", 0x21d2 }, { "radic", 0x221a }, { "rang", 0x232a }, { "raquo", 0x00bb }, { "rarr", 0x2192 }, { "rceil", 0x2309 }, { "rdquo", 0x201d }, { "real", 0x211c }, { "reg", 0x00ae }, { "rfloor", 0x230b }, { "rho", 0x03c1 }, { "rlm", 0x200f }, { "rsaquo", 0x203a }, { "rsquo", 0x2019 }, { "sbquo", 0x201a }, { "scaron", 0x0161 }, { "sdot", 0x22c5 }, { "sect", 0x00a7 }, { "shy", 0x00ad }, { "sigma", 0x03c3 }, { "sigmaf", 0x03c2 }, { "sim", 0x223c }, { "spades", 0x2660 }, { "sub", 0x2282 }, { "sube", 0x2286 }, { "sum", 0x2211 }, { "sup1", 0x00b9 }, { "sup2", 0x00b2 }, { "sup3", 0x00b3 }, { "sup", 0x2283 }, { "supe", 0x2287 }, { "szlig", 0x00df }, { "tau", 0x03c4 }, { "there4", 0x2234 }, { "theta", 0x03b8 }, { "thetasym", 0x03d1 }, { "thinsp", 0x2009 }, { "thorn", 0x00fe }, { "tilde", 0x02dc }, { "times", 0x00d7 }, { "trade", 0x2122 }, { "uArr", 0x21d1 }, { "uacute", 0x00fa }, { "uarr", 0x2191 }, { "ucirc", 0x00fb }, { "ugrave", 0x00f9 }, { "uml", 0x00a8 }, { "upsih", 0x03d2 }, { "upsilon", 0x03c5 }, { "uuml", 0x00fc }, { "weierp", 0x2118 }, { "xi", 0x03be }, { "yacute", 0x00fd }, { "yen", 0x00a5 }, { "yuml", 0x00ff }, { "zeta", 0x03b6 }, { "zwj", 0x200d }, { "zwnj", 0x200c }, { "", 0x0000 } }; static QMap<QCString, QChar> *html_map = 0; static void qt_cleanup_html_map() { delete html_map; html_map = 0; } static QMap<QCString, QChar> *htmlMap() { if ( !html_map ) { html_map = new QMap<QCString, QChar>; qAddPostRoutine( qt_cleanup_html_map ); const Entity *ent = entitylist; while( ent->code ) { html_map->insert( ent->name, QChar(ent->code) ); ent++; } } return html_map; } QChar QTextDocument::parseHTMLSpecialChar(const QChar* doc, int length, int& pos) { QCString s; pos++; int recoverpos = pos; while ( pos < length && doc[pos] != ';' && !doc[pos].isSpace() && pos < recoverpos + 6) { s += doc[pos]; pos++; } if (doc[pos] != ';' && !doc[pos].isSpace() ) { pos = recoverpos; return '&'; } pos++; if ( s.length() > 1 && s[0] == '#') { int num = s.mid(1).toInt(); if ( num == 151 ) // ### hack for designer manual return '-'; return num; } QMap<QCString, QChar>::Iterator it = htmlMap()->find(s); if ( it != htmlMap()->end() ) { return *it; } pos = recoverpos; return '&'; } QString QTextDocument::parseWord(const QChar* doc, int length, int& pos, bool lower) { QString s; if (doc[pos] == '"') { pos++; while ( pos < length && doc[pos] != '"' ) { s += doc[pos]; pos++; } eat(doc, length, pos, '"'); } else { static QString term = QString::fromLatin1("/>"); while( pos < length && (doc[pos] != '>' && !hasPrefix( doc, length, pos, term)) && doc[pos] != '<' && doc[pos] != '=' && !doc[pos].isSpace()) { if ( doc[pos] == '&') s += parseHTMLSpecialChar( doc, length, pos ); else { s += doc[pos]; pos++; } } if (lower) s = s.lower(); } return s; } QChar QTextDocument::parseChar(const QChar* doc, int length, int& pos, QStyleSheetItem::WhiteSpaceMode wsm ) { if ( pos >= length ) return QChar::null; QChar c = doc[pos++]; if (c == '<' ) return QChar::null; if ( c.isSpace() && c != QChar::nbsp ) { if ( wsm == QStyleSheetItem::WhiteSpacePre ) { if ( c == '\n' ) return QChar_linesep; else return c; } else { // non-pre mode: collapse whitespace except nbsp while ( pos< length && doc[pos].isSpace() && doc[pos] != QChar::nbsp ) pos++; if ( wsm == QStyleSheetItem::WhiteSpaceNoWrap ) return QChar::nbsp; else return ' '; } } else if ( c == '&' ) return parseHTMLSpecialChar( doc, length, --pos ); else return c; } QString QTextDocument::parseOpenTag(const QChar* doc, int length, int& pos, QMap<QString, QString> &attr, bool& emptyTag) { emptyTag = FALSE; pos++; if ( hasPrefix(doc, length, pos, '!') ) { if ( hasPrefix( doc, length, pos+1, "--")) { pos += 3; // eat comments QString pref = QString::fromLatin1("-->"); while ( !hasPrefix(doc, length, pos, pref ) && pos < length ) pos++; if ( hasPrefix(doc, length, pos, pref ) ) { pos += 3; eatSpace(doc, length, pos, TRUE); } emptyTag = TRUE; return QString::null; } else { // eat strange internal tags while ( !hasPrefix(doc, length, pos, '>') && pos < length ) pos++; if ( hasPrefix(doc, length, pos, '>') ) { pos++; eatSpace(doc, length, pos, TRUE); } return QString::null; } } QString tag = parseWord(doc, length, pos ); eatSpace(doc, length, pos, TRUE); static QString term = QString::fromLatin1("/>"); static QString s_TRUE = QString::fromLatin1("TRUE"); while (doc[pos] != '>' && ! (emptyTag = hasPrefix(doc, length, pos, term) )) { QString key = parseWord(doc, length, pos ); eatSpace(doc, length, pos, TRUE); if ( key.isEmpty()) { // error recovery while ( pos < length && doc[pos] != '>' ) pos++; break; } QString value; if (hasPrefix(doc, length, pos, '=') ){ pos++; eatSpace(doc, length, pos); value = parseWord(doc, length, pos, FALSE); } else value = s_TRUE; attr.insert(key.lower(), value ); eatSpace(doc, length, pos, TRUE); } if (emptyTag) { eat(doc, length, pos, '/'); eat(doc, length, pos, '>'); } else eat(doc, length, pos, '>'); return tag; } QString QTextDocument::parseCloseTag( const QChar* doc, int length, int& pos ) { pos++; pos++; QString tag = parseWord(doc, length, pos ); eatSpace(doc, length, pos, TRUE); eat(doc, length, pos, '>'); return tag; } QTextFlow::QTextFlow() { w = pagesize = 0; leftItems.setAutoDelete( FALSE ); rightItems.setAutoDelete( FALSE ); } QTextFlow::~QTextFlow() { } void QTextFlow::clear() { leftItems.clear(); rightItems.clear(); } void QTextFlow::setWidth( int width ) { w = width; } int QTextFlow::adjustLMargin( int yp, int, int margin, int space ) { for ( QTextCustomItem* item = leftItems.first(); item; item = leftItems.next() ) { if ( item->ypos == -1 ) continue; if ( yp >= item->ypos && yp < item->ypos + item->height ) margin = QMAX( margin, item->xpos + item->width + space ); } return margin; } int QTextFlow::adjustRMargin( int yp, int, int margin, int space ) { for ( QTextCustomItem* item = rightItems.first(); item; item = rightItems.next() ) { if ( item->ypos == -1 ) continue; if ( yp >= item->ypos && yp < item->ypos + item->height ) margin = QMAX( margin, w - item->xpos - space ); } return margin; } int QTextFlow::adjustFlow( int y, int /*w*/, int h ) { if ( pagesize > 0 ) { // check pages int yinpage = y % pagesize; if ( yinpage <= border_tolerance ) return border_tolerance - yinpage; else if ( yinpage + h > pagesize - border_tolerance ) return ( pagesize - yinpage ) + border_tolerance; } return 0; } void QTextFlow::unregisterFloatingItem( QTextCustomItem* item ) { leftItems.removeRef( item ); rightItems.removeRef( item ); } void QTextFlow::registerFloatingItem( QTextCustomItem* item ) { if ( item->placement() == QTextCustomItem::PlaceRight ) { if ( !rightItems.contains( item ) ) rightItems.append( item ); } else if ( item->placement() == QTextCustomItem::PlaceLeft && !leftItems.contains( item ) ) { leftItems.append( item ); } } QRect QTextFlow::boundingRect() const { QRect br; QPtrListIterator<QTextCustomItem> l( leftItems ); while( l.current() ) { br = br.unite( l.current()->geometry() ); ++l; } QPtrListIterator<QTextCustomItem> r( rightItems ); while( r.current() ) { br = br.unite( r.current()->geometry() ); ++r; } return br; } void QTextFlow::drawFloatingItems( QPainter* p, int cx, int cy, int cw, int ch, const QColorGroup& cg, bool selected ) { QTextCustomItem *item; for ( item = leftItems.first(); item; item = leftItems.next() ) { if ( item->xpos == -1 || item->ypos == -1 ) continue; item->draw( p, item->xpos, item->ypos, cx, cy, cw, ch, cg, selected ); } for ( item = rightItems.first(); item; item = rightItems.next() ) { if ( item->xpos == -1 || item->ypos == -1 ) continue; item->draw( p, item->xpos, item->ypos, cx, cy, cw, ch, cg, selected ); } } // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ void QTextCustomItem::pageBreak( int /*y*/ , QTextFlow* /*flow*/ ) { } QTextTable::QTextTable( QTextDocument *p, const QMap<QString, QString> & attr ) : QTextCustomItem( p ) { cells.setAutoDelete( FALSE ); cellspacing = 2; if ( attr.contains("cellspacing") ) cellspacing = attr["cellspacing"].toInt(); cellpadding = 1; if ( attr.contains("cellpadding") ) cellpadding = attr["cellpadding"].toInt(); border = innerborder = 0; if ( attr.contains("border" ) ) { QString s( attr["border"] ); if ( s == "TRUE" ) border = 1; else border = attr["border"].toInt(); } us_b = border; innerborder = us_ib = border ? 1 : 0; if ( border ) cellspacing += 2; us_ib = innerborder; us_cs = cellspacing; us_cp = cellpadding; outerborder = cellspacing + border; us_ob = outerborder; layout = new QGridLayout( 1, 1, cellspacing ); fixwidth = 0; stretch = 0; if ( attr.contains("width") ) { bool b; QString s( attr["width"] ); int w = s.toInt( &b ); if ( b ) { fixwidth = w; } else { s = s.stripWhiteSpace(); if ( s.length() > 1 && s[ (int)s.length()-1 ] == '%' ) stretch = s.left( s.length()-1).toInt(); } } place = PlaceInline; if ( attr["align"] == "left" ) place = PlaceLeft; else if ( attr["align"] == "right" ) place = PlaceRight; cachewidth = 0; attributes = attr; pageBreakFor = -1; } QTextTable::~QTextTable() { delete layout; } QString QTextTable::richText() const { QString s; s = "<table "; QMap<QString, QString>::ConstIterator it = attributes.begin(); for ( ; it != attributes.end(); ++it ) s += it.key() + "=" + *it + " "; s += ">\n"; int lastRow = -1; bool needEnd = FALSE; QPtrListIterator<QTextTableCell> it2( cells ); while ( it2.current() ) { QTextTableCell *cell = it2.current(); ++it2; if ( lastRow != cell->row() ) { if ( lastRow != -1 ) s += "</tr>\n"; s += "<tr>"; lastRow = cell->row(); needEnd = TRUE; } s += "<td"; it = cell->attributes.begin(); for ( ; it != cell->attributes.end(); ++it ) s += " " + it.key() + "=" + *it; s += ">"; s += cell->richText()->richText(); s += "</td>"; } if ( needEnd ) s += "</tr>\n"; s += "</table>\n"; return s; } void QTextTable::adjustToPainter( QPainter* p ) { cellspacing = scale( us_cs, p ); cellpadding = scale( us_cp, p ); border = scale( us_b , p ); innerborder = scale( us_ib, p ); outerborder = scale( us_ob ,p ); width = 0; cachewidth = 0; for ( QTextTableCell* cell = cells.first(); cell; cell = cells.next() ) cell->adjustToPainter( p ); } void QTextTable::adjustCells( int y , int shift ) { QPtrListIterator<QTextTableCell> it( cells ); QTextTableCell* cell; bool enlarge = FALSE; while ( ( cell = it.current() ) ) { ++it; QRect r = cell->geometry(); if ( y <= r.top() ) { r.moveBy(0, shift ); cell->setGeometry( r ); enlarge = TRUE; } else if ( y <= r.bottom() ) { r.rBottom() += shift; cell->setGeometry( r ); enlarge = TRUE; } } if ( enlarge ) height += shift; } void QTextTable::pageBreak( int yt, QTextFlow* flow ) { if ( flow->pageSize() <= 0 ) return; if ( layout && pageBreakFor > 0 && pageBreakFor != yt ) { layout->invalidate(); int h = layout->heightForWidth( width-2*outerborder ); layout->setGeometry( QRect(0, 0, width-2*outerborder, h) ); height = layout->geometry().height()+2*outerborder; } pageBreakFor = yt; QPtrListIterator<QTextTableCell> it( cells ); QTextTableCell* cell; while ( ( cell = it.current() ) ) { ++it; int y = yt + outerborder + cell->geometry().y(); int shift = flow->adjustFlow( y - cellspacing, width, cell->richText()->height() + 2*cellspacing ); adjustCells( y - outerborder - yt, shift ); } } void QTextTable::draw(QPainter* p, int x, int y, int cx, int cy, int cw, int ch, const QColorGroup& cg, bool selected ) { if ( placement() != PlaceInline ) { x = xpos; y = ypos; } for (QTextTableCell* cell = cells.first(); cell; cell = cells.next() ) { if ( cx < 0 && cy < 0 || QRect( cx, cy, cw, ch ).intersects( QRect( x + outerborder + cell->geometry().x(), y + outerborder + cell->geometry().y(), cell->geometry().width(), cell->geometry().height() ) ) ) { cell->draw( p, x+outerborder, y+outerborder, cx, cy, cw, ch, cg, selected ); if ( border ) { QRect r( x+outerborder+cell->geometry().x() - innerborder, y+outerborder+cell->geometry().y() - innerborder, cell->geometry().width() + 2 * innerborder, cell->geometry().height() + 2 * innerborder ); if ( is_printer( p ) ) { QPen oldPen = p->pen(); diff --git a/noncore/apps/tinykate/libkate/document/katehighlight.cpp b/noncore/apps/tinykate/libkate/document/katehighlight.cpp index 539d356..89024f7 100644 --- a/noncore/apps/tinykate/libkate/document/katehighlight.cpp +++ b/noncore/apps/tinykate/libkate/document/katehighlight.cpp @@ -1,1422 +1,1427 @@ /* Copyright (C) 1998, 1999 Jochen Wilhelmy digisnap@cs.tu-berlin.de (C) 2002, 2001 The Kate Team <kwrite-devel@kde.org> (C) 2002 Joseph Wenninger <jowenn@kde.org> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "katehighlight.h" #include "katetextline.h" #include "katedocument.h" #include "katesyntaxdocument.h" #include "kglobal.h" //#include "kinstance.h" //#include "kmimemagic.h" #include "klocale.h" //#include "kregexp.h" #include "kglobalsettings.h" #include "kdebug.h" #include "kstddirs.h" /* OPIE */ #include <opie2/odebug.h> #include <qpe/config.h> /* QT */ #include <qtextstream.h> /* STD */ #include <string.h> HlManager *HlManager::s_pSelf = 0; enum Item_styles { dsNormal,dsKeyword,dsDataType,dsDecVal,dsBaseN,dsFloat,dsChar,dsString,dsComment,dsOthers}; static bool trueBool = true; static QString stdDeliminator = QString ("!%&()*+,-./:;<=>?[]^{|}~ \t\\"); int getDefStyleNum(QString name) { if (name=="dsNormal") return dsNormal; if (name=="dsKeyword") return dsKeyword; if (name=="dsDataType") return dsDataType; if (name=="dsDecVal") return dsDecVal; if (name=="dsBaseN") return dsBaseN; if (name=="dsFloat") return dsFloat; if (name=="dsChar") return dsChar; if (name=="dsString") return dsString; if (name=="dsComment") return dsComment; if (name=="dsOthers") return dsOthers; return dsNormal; } bool ustrchr(const QChar *s, uint len, QChar c) { for (int z=0; z < len; z++) { if (*s == c) return true; s++; } return false; } HlItem::HlItem(int attribute, int context) : attr(attribute), ctx(context) {subItems=0; } HlItem::~HlItem() { //kdDebug(13010)<<"In hlItem::~HlItem()"<<endl; if (subItems!=0) {subItems->setAutoDelete(true); subItems->clear(); delete subItems;} } bool HlItem::startEnable(QChar c) { return true; } HlCharDetect::HlCharDetect(int attribute, int context, QChar c) : HlItem(attribute,context), sChar(c) { } const QChar *HlCharDetect::checkHgl(const QChar *str, int len, bool) { if (*str == sChar) return str + 1; return 0L; } Hl2CharDetect::Hl2CharDetect(int attribute, int context, QChar ch1, QChar ch2) : HlItem(attribute,context) { sChar1 = ch1; sChar2 = ch2; } const QChar *Hl2CharDetect::checkHgl(const QChar *str, int len, bool) { if (str[0] == sChar1 && str[1] == sChar2) return str + 2; return 0L; } HlStringDetect::HlStringDetect(int attribute, int context, const QString &s, bool inSensitive) : HlItem(attribute, context), str(inSensitive ? s.upper():s), _inSensitive(inSensitive) { } HlStringDetect::~HlStringDetect() { } const QChar *HlStringDetect::checkHgl(const QChar *s, int len, bool) { if (!_inSensitive) {if (memcmp(s, str.unicode(), str.length()*sizeof(QChar)) == 0) return s + str.length();} else { QString tmp=QString(s,str.length()).upper(); if (tmp==str) return s+str.length(); } return 0L; } HlRangeDetect::HlRangeDetect(int attribute, int context, QChar ch1, QChar ch2) : HlItem(attribute,context) { sChar1 = ch1; sChar2 = ch2; } const QChar *HlRangeDetect::checkHgl(const QChar *s, int len, bool) { if (*s == sChar1) { do { s++; len--; if (len == 0) return 0L; } while (*s != sChar2); return s + 1; } return 0L; } HlKeyword::HlKeyword (int attribute, int context,bool casesensitive, const QChar *deliminator, uint deliLen) : HlItem(attribute,context), dict (113, casesensitive) { deliminatorChars = deliminator; deliminatorLen = deliLen; _caseSensitive=casesensitive; } HlKeyword::~HlKeyword() { } bool HlKeyword::startEnable(QChar c) { return ustrchr(deliminatorChars, deliminatorLen, c); } // If we use a dictionary for lookup we don't really need // an item as such we are using the key to lookup void HlKeyword::addWord(const QString &word) { words.append(word); dict.insert(word,&trueBool); } void HlKeyword::addList(const QStringList& list) { words+=list; for(uint i=0;i<list.count();i++) dict.insert(list[i], &trueBool); } const QChar *HlKeyword::checkHgl(const QChar *s, int len, bool b) { if (len == 0) return 0L; const QChar *s2 = s; while ( (len > 0) && (!ustrchr(deliminatorChars, deliminatorLen, *s2)) ) { s2++; len--; } if (s2 == s) return 0L; QString lookup = QString(s,s2-s); if ( dict.find(lookup) ) return s2; return 0L; } HlInt::HlInt(int attribute, int context) : HlItem(attribute,context) { } const QChar *HlInt::checkHgl(const QChar *str, int len, bool) { const QChar *s,*s1; s = str; while (s->isDigit()) s++; if (s > str) { if (subItems) { for (HlItem *it=subItems->first();it;it=subItems->next()) { s1=it->checkHgl(s, len, false); if (s1) return s1; } } return s; } return 0L; } HlFloat::HlFloat(int attribute, int context) : HlItem(attribute,context) { } const QChar *HlFloat::checkHgl(const QChar *s, int len, bool) { bool b, p; const QChar *s1; b = false; while (s->isDigit()){ s++; b = true; } if (p = (*s == '.')) { s++; while (s->isDigit()) { s++; b = true; } } if (!b) return 0L; if ((*s&0xdf) == 'E') s++; else if (!p) return 0L; else { if (subItems) { for (HlItem *it=subItems->first();it;it=subItems->next()) { s1=it->checkHgl(s, len, false); if (s1) return s1; } } return s; } if ((*s == '-')||(*s =='+')) s++; b = false; while (s->isDigit()) { s++; b = true; } if (b) { if (subItems) { for (HlItem *it=subItems->first();it;it=subItems->next()) { s1=it->checkHgl(s, len, false); if (s1) return s1; } } return s; } else return 0L; } HlCInt::HlCInt(int attribute, int context) : HlInt(attribute,context) { } const QChar *HlCInt::checkHgl(const QChar *s, int len, bool lineStart) { // if (*s == '0') s++; else s = HlInt::checkHgl(s); s = HlInt::checkHgl(s, len, lineStart); if (s != 0L) { int l = 0; int u = 0; const QChar *str; do { str = s; if ((*s&0xdf) == 'L' ) { l++; if (l > 2) return 0L; s++; } if ((*s&0xdf) == 'U' ){ u++; if (u > 1) return 0L; s++; } } while (s != str); } return s; } HlCOct::HlCOct(int attribute, int context) : HlItem(attribute,context) { } const QChar *HlCOct::checkHgl(const QChar *str, int len, bool) { const QChar *s; if (*str == '0') { str++; s = str; while (*s >= '0' && *s <= '7') s++; if (s > str) { if ((*s&0xdf) == 'L' || (*s&0xdf) == 'U' ) s++; return s; } } return 0L; } HlCHex::HlCHex(int attribute, int context) : HlItem(attribute,context) { } const QChar *HlCHex::checkHgl(const QChar *str, int len, bool) { const QChar *s=str; #if 0 int i; for (i=0;(*s)!='\0';s++,i++); QString line(str,i); QRegExp3 rx("0[xX][a-fA-F\\d]+[UuLl]?"); // this matches but is also matching parenthesis int pos=rx.search(line,0); if(pos > -1) return str+rx.matchedLength(); else return 0L; #else if (str[0] == '0' && ((str[1]&0xdf) == 'X' )) { str += 2; s = str; while (s->isDigit() || ((*s&0xdf) >= 'A' && (*s&0xdf) <= 'F') /*|| (*s >= 'a' && *s <= 'f')*/) s++; if (s > str) { if ((*s&0xdf) == 'L' || (*s&0xdf) == 'U' ) s++; return s; } } return 0L; #endif } HlCFloat::HlCFloat(int attribute, int context) : HlFloat(attribute,context) { } const QChar *HlCFloat::checkHgl(const QChar *s, int len, bool lineStart) { s = HlFloat::checkHgl(s, len, lineStart); if (s && ((*s&0xdf) == 'F' )) s++; return s; } HlAnyChar::HlAnyChar(int attribute, int context, const QChar* charList, uint len) : HlItem(attribute, context) { _charList=charList; _charListLen=len; } const QChar *HlAnyChar::checkHgl(const QChar *s, int len, bool) { if (ustrchr(_charList, _charListLen, *s)) return s +1; return 0L; } HlRegExpr::HlRegExpr(int attribute, int context,QString regexp) - : HlItem(attribute, context) { + : HlItem(attribute, context), Expr(0) { handlesLinestart=regexp.startsWith("^"); if(!handlesLinestart) regexp.prepend("^"); Expr=new QRegExp3(regexp); } +HlRegExpr::~HlRegExpr() +{ + delete Expr; +} + const QChar *HlRegExpr::checkHgl(const QChar *s, int len, bool lineStart) { if ((!lineStart) && handlesLinestart) return 0; QString line(s,len); int pos = Expr->search( line, 0 ); if (pos==-1) return 0L; else return (s+Expr->matchedLength()); }; HlLineContinue::HlLineContinue(int attribute, int context) : HlItem(attribute,context) { } const QChar *HlLineContinue::checkHgl(const QChar *s, int len, bool) { if ((s[0].latin1() == '\\') && (len == 1)) { return s + 1; } return 0L; } HlCStringChar::HlCStringChar(int attribute, int context) : HlItem(attribute,context) { } //checks for hex and oct (for example \x1b or \033) const QChar *checkCharHexOct(const QChar *str) { const QChar *s; s=str; int n; if (*s == 'x') { n = 0; do { s++; n *= 16; if (s->isDigit()) n += *s - '0'; else if ((*s&0xdf) >= 'A' && (*s&0xdf) <= 'F') n += (*s&0xdf) - 'A' + 10; // else if (*s >= 'a' && *s <= 'f') n += *s - 'a' + 10; else break; if (n >= 256) return 0L; } while (true); if (s - str == 1) return 0L; } else { if (!(*s >= '0' && *s <= '7')) return 0L; n = *s - '0'; do { s++; n *= 8; if (*s >= '0' && *s <= '7') n += *s - '0'; else break; if (n >= 256) return s; } while (s - str < 3); } return s; } // checks for C escaped chars \n and escaped hex/octal chars const QChar *checkEscapedChar(const QChar *s, int len) { int i; if (s[0] == '\\' && (len > 1) ) { s++; switch(*s){ case 'a': // checks for control chars case 'b': // we want to fall through case 'e': case 'f': case 'n': case 'r': case 't': case 'v': case '\'': case '\"': case '?' : // added ? ANSI C classifies this as an escaped char case '\\': s++; break; case 'x': // if it's like \xff s++; // eat the x // these for loops can probably be // replaced with something else but // for right now they work // check for hexdigits for(i=0;i<2 &&(*s >= '0' && *s <= '9' || (*s&0xdf) >= 'A' && (*s&0xdf) <= 'F');i++,s++); if(i==0) return 0L; // takes care of case '\x' break; case '0': case '1': case '2': case '3' : case '4': case '5': case '6': case '7' : for(i=0;i < 3 &&(*s >='0'&& *s<='7');i++,s++); break; default: return 0L; } return s; } return 0L; } const QChar *HlCStringChar::checkHgl(const QChar *str, int len, bool) { return checkEscapedChar(str, len); } HlCChar::HlCChar(int attribute, int context) : HlItem(attribute,context) { } const QChar *HlCChar::checkHgl(const QChar *str, int len, bool) { const QChar *s; if ((len > 1) && (str[0] == '\'') && (str[1] != '\'')) { s = checkEscapedChar(&str[1], len); //try to match escaped char if (!s) s = &str[2]; //match single non-escaped char if (*s == '\'') return s + 1; } return 0L; } //-------- ItemStyle::ItemStyle() : selCol(Qt::white), bold(false), italic(false) { } ItemStyle::ItemStyle(const QColor &col, const QColor &selCol, bool bold, bool italic) : col(col), selCol(selCol), bold(bold), italic(italic) { } ItemData::ItemData(const QString name, int defStyleNum) : name(name), defStyleNum(defStyleNum), defStyle(true) { } ItemData::ItemData(const QString name, int defStyleNum, const QColor &col, const QColor &selCol, bool bold, bool italic) : ItemStyle(col,selCol,bold,italic), name(name), defStyleNum(defStyleNum), defStyle(false) { } HlData::HlData(const QString &wildcards, const QString &mimetypes, const QString &identifier) : wildcards(wildcards), mimetypes(mimetypes), identifier(identifier) { //JW itemDataList.setAutoDelete(true); } HlContext::HlContext(int attribute, int lineEndContext, int _lineBeginContext) : attr(attribute), ctx(lineEndContext),lineBeginContext(_lineBeginContext) { items.setAutoDelete(true); } Hl2CharDetect::Hl2CharDetect(int attribute, int context, const QChar *s) : HlItem(attribute,context) { sChar1 = s[0]; sChar2 = s[1]; } Highlight::Highlight(syntaxModeListItem *def) : refCount(0) { noHl = false; if (def == 0) { noHl = true; iName = I18N_NOOP("Normal"); iSection = ""; } else { iName = def->name; iSection = def->section; iWildcards = def->extension; iMimetypes = def->mimetype; identifier = def->identifier; } deliminator = stdDeliminator; deliminatorChars = deliminator.unicode(); deliminatorLen = deliminator.length(); } Highlight::~Highlight() { } int Highlight::doHighlight(int ctxNum, TextLine *textLine) { if (noHl) { textLine->setAttribs(0,0,textLine->length()); textLine->setAttr(0); return 0; } HlContext *context; const QChar *s2; HlItem *item; context = contextList[ctxNum]; if (context->lineBeginContext!=-1) { ctxNum=context->lineBeginContext; context=contextList[ctxNum]; } QChar lastChar = ' '; // first char const QChar *str = textLine->getText(); // non space char - index of that char const QChar *s1 = textLine->firstNonSpace(); uint z = textLine->firstChar(); // length of textline uint len = textLine->length(); bool found = false; while (z < len) { found = false; for (item = context->items.first(); item != 0L; item = context->items.next()) { if (item->startEnable(lastChar)) { s2 = item->checkHgl(s1, len-z, z==0); if (s2 > s1) { odebug << "An item has been detected" << oendl; textLine->setAttribs(item->attr,s1 - str,s2 - str); ctxNum = item->ctx; context = contextList[ctxNum]; z = z + s2 - s1 - 1; s1 = s2 - 1; found = true; break; } } } // nothing found: set attribute of one char if (!found) textLine->setAttribs(context->attr,s1 - str,s1 - str + 1); lastChar = *s1; s1++; z++; } //set "end of line"-properties textLine->setAttr(context->attr); //return new context return context->ctx; } KateConfig *Highlight::getKateConfig() { KateConfig *config; config=KGlobal::config(); config->setGroup(iName + QString(" Highlight")); return config; } QString Highlight::getWildcards() { KateConfig *config; config = getKateConfig(); //if wildcards not yet in config, then use iWildCards as default return config->readEntry("Wildcards", iWildcards); } QString Highlight::getMimetypes() { KateConfig *config; config = getKateConfig(); return config->readEntry("Mimetypes", iMimetypes); } HlData *Highlight::getData() { KateConfig *config; HlData *hlData; config = getKateConfig(); // iWildcards = config->readEntry("Wildcards"); // iMimetypes = config->readEntry("Mimetypes"); // hlData = new HlData(iWildcards,iMimetypes); hlData = new HlData( config->readEntry("Wildcards", iWildcards), config->readEntry("Mimetypes", iMimetypes), config->readEntry("Identifier", identifier)); getItemDataList(hlData->itemDataList, config); return hlData; } void Highlight::setData(HlData *hlData) { KateConfig *config; config = getKateConfig(); // iWildcards = hlData->wildcards; // iMimetypes = hlData->mimetypes; config->writeEntry("Wildcards",hlData->wildcards); config->writeEntry("Mimetypes",hlData->mimetypes); setItemDataList(hlData->itemDataList,config); } void Highlight::getItemDataList(ItemDataList &list) { KateConfig *config; config = getKateConfig(); getItemDataList(list, config); } void Highlight::getItemDataList(ItemDataList &list, KateConfig *config) { ItemData *p; QString s; QRgb col, selCol; list.clear(); //JW list.setAutoDelete(true); createItemData(list); for (p = list.first(); p != 0L; p = list.next()) { s = config->readEntry(p->name); if (!s.isEmpty()) { sscanf(s.latin1(),"%d,%X,%X,%d,%d", &p->defStyle,&col,&selCol,&p->bold,&p->italic); p->col.setRgb(col); p->selCol.setRgb(selCol); } } } /******************************************************************************************* Highlight - setItemDataList saves the ItemData / attribute / style definitions to the apps configfile. Especially needed for user overridden values. * input: ItemDataList &list :reference to the list, whose * items should be saved * KateConfig *config :Pointer KDE configuration * class, which should be used * as storage ************* * output: none ************* * return value: none *******************************************************************************************/ void Highlight::setItemDataList(ItemDataList &list, KateConfig *config) { ItemData *p; QString s; for (p = list.first(); p != 0L; p = list.next()) { s.sprintf("%d,%X,%X,%d,%d", p->defStyle,p->col.rgb(),p->selCol.rgb(),p->bold,p->italic); config->writeEntry(p->name,s); } } /******************************************************************************************* Highlight - use Increase the usage count and trigger initialization if needed * input: none ************* * output: none ************* * return value: none *******************************************************************************************/ void Highlight::use() { if (refCount == 0) init(); refCount++; } /******************************************************************************************* Highlight - release Decrease the usage count and trigger a cleanup if needed * input: none ************* * output: none ************* * return value: none *******************************************************************************************/ void Highlight::release() { refCount--; if (refCount == 0) done(); } /******************************************************************************************* Highlight - init If it's the first time a particular highlighting is used create the needed contextlist * input: none ************* * output: none ************* * return value: none *******************************************************************************************/ void Highlight::init() { if (noHl) return; for (int z = 0; z < nContexts; z++) contextList[z] = 0L; makeContextList(); } /******************************************************************************************* Highlight - done If the there is no document using the highlighting style free the complete context structure. * input: none ************* * output: none ************* * return value: none *******************************************************************************************/ void Highlight::done() { if (noHl) return; for (int z = 0; z < nContexts; z++) delete contextList[z]; } /******************************************************************************************* Highlight - createItemData This function reads the itemData entries from the config file, which specifies the default attribute styles for matched items/contexts. * input: none ************* * output: ItemDataList &list :A reference to the internal list containing the parsed default config ************* * return value: none *******************************************************************************************/ void Highlight::createItemData(ItemDataList &list) { odebug << "Highlight::createItemData" << oendl; // If no highlighting is selected we need only one default. if (noHl) { list.append(new ItemData(I18N_NOOP("Normal Text"), dsNormal)); return; } QString color; QString selColor; QString bold; QString italic; // If the internal list isn't already available read the config file if (internalIDList.count()==0) { //if all references to the list are destried the contents will also be deleted internalIDList.setAutoDelete(true); syntaxContextData *data; odebug << "Trying to read itemData section" << oendl; //Tell the syntax document class which file we want to parse and which data group HlManager::self()->syntax->setIdentifier(identifier); data=HlManager::self()->syntax->getGroupInfo("highlighting","itemData"); //begin with the real parsing while (HlManager::self()->syntax->nextGroup(data)) { odebug << "Setting up one itemData element" << oendl; // read all attributes color=HlManager::self()->syntax->groupData(data,QString("color")); selColor=HlManager::self()->syntax->groupData(data,QString("selColor")); bold=HlManager::self()->syntax->groupData(data,QString("bold")); italic=HlManager::self()->syntax->groupData(data,QString("italic")); //check if the user overrides something if ( (!color.isEmpty()) && (!selColor.isEmpty()) && (!bold.isEmpty()) && (!italic.isEmpty())) { //create a user defined style internalIDList.append(new ItemData( HlManager::self()->syntax->groupData(data,QString("name")).simplifyWhiteSpace(), getDefStyleNum(HlManager::self()->syntax->groupData(data,QString("defStyleNum"))), QColor(color),QColor(selColor),(bold=="true") || (bold=="1"), (italic=="true") || (italic=="1") )); } else { //assign a default style internalIDList.append(new ItemData( HlManager::self()->syntax->groupData(data,QString("name")).simplifyWhiteSpace(), getDefStyleNum(HlManager::self()->syntax->groupData(data,QString("defStyleNum"))))); } } //clean up if (data) HlManager::self()->syntax->freeGroupInfo(data); } //set the ouput reference list=internalIDList; } /******************************************************************************************* Highlight - lookupAttrName This function is a helper for makeContextList and createHlItem. It looks the given attribute name in the itemData list up and returns it's index * input: QString &name :the attribute name to lookup * ItemDataList &iDl :the list containing all * available attributes ************* * output: none ************* * return value: int :The index of the attribute * or 0 *******************************************************************************************/ int Highlight::lookupAttrName(const QString& name, ItemDataList &iDl) { for (int i=0;i<iDl.count();i++) { if (iDl.at(i)->name==name) return i; } kdDebug(13010)<<"Couldn't resolve itemDataName"<<endl; return 0; } /******************************************************************************************* Highlight - createHlItem This function is a helper for makeContextList. It parses the xml file for information, how single or multi line comments are marked * input: syntaxContextData *data : Data about the item read from * the xml file * ItemDataList &iDl : List of all available itemData * entries. Needed for attribute * name->index translation ************* * output: none ************* * return value: HlItem * : Pointer to the newly created item * object *******************************************************************************************/ HlItem *Highlight::createHlItem(syntaxContextData *data, ItemDataList &iDl) { // No highlighting -> exit if (noHl) return 0; // get the (tagname) itemd type QString dataname=HlManager::self()->syntax->groupItemData(data,QString("")); // BEGIN - Translation of the attribute parameter QString tmpAttr=HlManager::self()->syntax->groupItemData(data,QString("attribute")).simplifyWhiteSpace(); int attr; if (QString("%1").arg(tmpAttr.toInt())==tmpAttr) attr=tmpAttr.toInt(); else attr=lookupAttrName(tmpAttr,iDl); // END - Translation of the attribute parameter // Info about context switch int context=((HlManager::self()->syntax->groupItemData(data,QString("context"))).toInt()); // Get the char parameter (eg DetectChar) char chr; if (! HlManager::self()->syntax->groupItemData(data,QString("char")).isEmpty()) chr= (HlManager::self()->syntax->groupItemData(data,QString("char")).latin1())[0]; else chr=0; // Get the String parameter (eg. StringDetect) QString stringdata=HlManager::self()->syntax->groupItemData(data,QString("String")); // Get a second char parameter (char1) (eg Detect2Chars) char chr1; if (! HlManager::self()->syntax->groupItemData(data,QString("char1")).isEmpty()) chr1= (HlManager::self()->syntax->groupItemData(data,QString("char1")).latin1())[0]; else chr1=0; // Will be removed eventuall. Atm used for StringDetect bool insensitive=(HlManager::self()->syntax->groupItemData(data,QString("insensitive"))==QString("TRUE")); //Create the item corresponding to it's type and set it's parameters if (dataname=="keyword") { HlKeyword *keyword=new HlKeyword(attr,context,casesensitive, deliminatorChars, deliminatorLen); //Get the entries for the keyword lookup list keyword->addList(HlManager::self()->syntax->finddata("highlighting",stringdata)); return keyword; } else if (dataname=="Float") return (new HlFloat(attr,context)); else if (dataname=="Int") return(new HlInt(attr,context)); else if (dataname=="DetectChar") return(new HlCharDetect(attr,context,chr)); else if (dataname=="Detect2Chars") return(new Hl2CharDetect(attr,context,chr,chr1)); else if (dataname=="RangeDetect") return(new HlRangeDetect(attr,context, chr, chr1)); else if (dataname=="LineContinue") return(new HlLineContinue(attr,context)); else if (dataname=="StringDetect") return(new HlStringDetect(attr,context,stringdata,insensitive)); else if (dataname=="AnyChar") return(new HlAnyChar(attr,context,stringdata.unicode(), stringdata.length())); else if (dataname=="RegExpr") return(new HlRegExpr(attr,context,stringdata)); else if(dataname=="HlCChar") return ( new HlCChar(attr,context));else if(dataname=="HlCHex") return (new HlCHex(attr,context));else if(dataname=="HlCOct") return (new HlCOct(attr,context)); else if(dataname=="HlCStringChar") return (new HlCStringChar(attr,context)); else { // oops, unknown type. Perhaps a spelling error in the xml file return 0; } } /******************************************************************************************* Highlight - isInWord * input: Qchar c Character to investigate ************* * output: none ************* * return value: returns true, if c is no deliminator *******************************************************************************************/ bool Highlight::isInWord(QChar c) { return !ustrchr(deliminatorChars, deliminatorLen, c); } /******************************************************************************************* Highlight - readCommentConfig This function is a helper for makeContextList. It parses the xml file for information, how single or multi line comments are marked * input: none ************* * output: none ************* * return value: none *******************************************************************************************/ void Highlight::readCommentConfig() { cslStart = ""; HlManager::self()->syntax->setIdentifier(identifier); syntaxContextData *data=HlManager::self()->syntax->getGroupInfo("general","comment"); if (data) { // kdDebug(13010)<<"COMMENT DATA FOUND"<<endl; while (HlManager::self()->syntax->nextGroup(data)) { if (HlManager::self()->syntax->groupData(data,"name")=="singleLine") cslStart=HlManager::self()->syntax->groupData(data,"start"); if (HlManager::self()->syntax->groupData(data,"name")=="multiLine") { cmlStart=HlManager::self()->syntax->groupData(data,"start"); cmlEnd=HlManager::self()->syntax->groupData(data,"end"); } } HlManager::self()->syntax->freeGroupInfo(data); } } /******************************************************************************************* Highlight - readGlobalKeyWordConfig This function is a helper for makeContextList. It parses the xml file for information, if keywords should be treated case(in)sensitive and creates the keyword delimiter list. Which is the default list, without any given weak deliminiators * input: none ************* * output: none ************* * return value: none *******************************************************************************************/ void Highlight::readGlobalKeywordConfig() { // Tell the syntax document class which file we want to parse HlManager::self()->syntax->setIdentifier(identifier); // Get the keywords config entry syntaxContextData * data=HlManager::self()->syntax->getConfig("general","keywords"); if (data) { kdDebug(13010)<<"Found global keyword config"<<endl; if (HlManager::self()->syntax->groupItemData(data,QString("casesensitive"))!="0") casesensitive=true; else {casesensitive=false; kdDebug(13010)<<"Turning on case insensitiveness"<<endl;} //get the weak deliminators weakDeliminator=(!HlManager::self()->syntax->groupItemData(data,QString("weakDeliminator"))); // remove any weakDelimitars (if any) from the default list and store this list. int f; for (int s=0; s < weakDeliminator.length(); s++) { f = 0; f = deliminator.find (weakDeliminator[s]); if (f > -1) deliminator.remove (f, 1); } deliminatorChars = deliminator.unicode(); deliminatorLen = deliminator.length(); HlManager::self()->syntax->freeGroupInfo(data); } else { //Default values casesensitive=true; weakDeliminator=QString(""); } } /******************************************************************************************* Highlight - makeContextList That's the most important initialization function for each highlighting. It's called each time a document gets a highlighting style assigned. parses the xml file and creates a corresponding internal structure * input: none ************* * output: none ************* * return value: none *******************************************************************************************/ void Highlight::makeContextList() { if (noHl) return; HlKeyword *keyword=0, *dataType=0; syntaxContextData *data, *datasub; HlItem *c; readCommentConfig(); readGlobalKeywordConfig(); // Let the syntax document class know, which file we'd like to parse HlManager::self()->syntax->setIdentifier(identifier); // This list is needed for the translation of the attribute parameter, if the itemData name is given instead of the index ItemDataList iDl; createItemData(iDl); //start the real work data=HlManager::self()->syntax->getGroupInfo("highlighting","context"); int i=0; if (data) { while (HlManager::self()->syntax->nextGroup(data)) { // BEGIN - Translation of the attribute parameter QString tmpAttr=HlManager::self()->syntax->groupData(data,QString("attribute")).simplifyWhiteSpace(); int attr; if (QString("%1").arg(tmpAttr.toInt())==tmpAttr) attr=tmpAttr.toInt(); else attr=lookupAttrName(tmpAttr,iDl); // END - Translation of the attribute parameter contextList[i]=new HlContext( attr, (HlManager::self()->syntax->groupData(data,QString("lineEndContext"))).toInt(), (HlManager::self()->syntax->groupData(data,QString("lineBeginContext"))).isEmpty()?-1: (HlManager::self()->syntax->groupData(data,QString("lineBeginContext"))).toInt()); //Let's create all items for the context while (HlManager::self()->syntax->nextItem(data)) { // kdDebug(13010)<< "In make Contextlist: Item:"<<endl; c=createHlItem(data,iDl); if (c) { contextList[i]->items.append(c); // Not supported completely atm and only one level. Subitems.(all have to be matched to at once) datasub=HlManager::self()->syntax->getSubItems(data); bool tmpbool; if (tmpbool=HlManager::self()->syntax->nextItem(datasub)) { c->subItems=new QList<HlItem>; for (;tmpbool;tmpbool=HlManager::self()->syntax->nextItem(datasub)) c->subItems->append(createHlItem(datasub,iDl)); } HlManager::self()->syntax->freeGroupInfo(datasub); // end of sublevel } // kdDebug(13010)<<"Last line in loop"<<endl; } i++; } } HlManager::self()->syntax->freeGroupInfo(data); } HlManager::HlManager() : QObject(0L) { syntax = new SyntaxDocument(); SyntaxModeList modeList = syntax->modeList(); hlList.setAutoDelete(true); hlList.append(new Highlight(0)); uint i=0; while (i < modeList.count()) { hlList.append(new Highlight(modeList.at(i))); i++; } } HlManager::~HlManager() { if(syntax) delete syntax; } HlManager *HlManager::self() { if ( !s_pSelf ) s_pSelf = new HlManager; return s_pSelf; } Highlight *HlManager::getHl(int n) { if (n < 0 || n >= (int) hlList.count()) n = 0; return hlList.at(n); } int HlManager::defaultHl() { KateConfig *config; config = KGlobal::config(); config->setGroup("General Options"); #warning fixme return nameFind(config->readEntry("Highlight")); } int HlManager::nameFind(const QString &name) { int z; for (z = hlList.count() - 1; z > 0; z--) { if (hlList.at(z)->iName == name) break; } return z; } int HlManager::wildcardFind(const QString &fileName) { Highlight *highlight; int p1, p2; QString w; for (highlight = hlList.first(); highlight != 0L; highlight = hlList.next()) { p1 = 0; w = highlight->getWildcards(); while (p1 < (int) w.length()) { p2 = w.find(';',p1); if (p2 == -1) p2 = w.length(); if (p1 < p2) { QRegExp regExp(w.mid(p1,p2 - p1),true,true); if (regExp.match(fileName) == 0) return hlList.at(); } p1 = p2 + 1; } } return -1; } int HlManager::makeAttribs(Highlight *highlight, Attribute *a, int maxAttribs) { ItemStyleList defaultStyleList; ItemStyle *defaultStyle; ItemDataList itemDataList; ItemData *itemData; int nAttribs, z; odebug << "HlManager::makeAttribs" << oendl; defaultStyleList.setAutoDelete(true); getDefaults(defaultStyleList); // itemDataList.setAutoDelete(true); highlight->getItemDataList(itemDataList); nAttribs = itemDataList.count(); for (z = 0; z < nAttribs; z++) { odebug << "HlManager::makeAttribs: createing one attribute definition" << oendl; itemData = itemDataList.at(z); if (itemData->defStyle) { // default style defaultStyle = defaultStyleList.at(itemData->defStyleNum); a[z].col = defaultStyle->col; a[z].selCol = defaultStyle->selCol; a[z].bold = defaultStyle->bold; a[z].italic = defaultStyle->italic; } else { // custom style a[z].col = itemData->col; a[z].selCol = itemData->selCol; a[z].bold = itemData->bold; a[z].italic = itemData->italic; } } for (; z < maxAttribs; z++) { a[z].col = black; a[z].selCol = black; a[z].bold = defaultStyle->bold; a[z].italic = defaultStyle->italic; } return nAttribs; } int HlManager::defaultStyles() { return 10; } QString HlManager::defaultStyleName(int n) { static QStringList names; if (names.isEmpty()) { names << i18n("Normal"); names << i18n("Keyword"); names << i18n("Data Type"); names << i18n("Decimal/Value"); names << i18n("Base-N Integer"); names << i18n("Floating Point"); names << i18n("Character"); names << i18n("String"); names << i18n("Comment"); names << i18n("Others"); } return names[n]; } void HlManager::getDefaults(ItemStyleList &list) { KateConfig *config; int z; ItemStyle *i; QString s; QRgb col, selCol; list.setAutoDelete(true); //ItemStyle(color, selected color, bold, italic) list.append(new ItemStyle(black,white,false,false)); //normal list.append(new ItemStyle(black,white,true,false)); //keyword list.append(new ItemStyle(darkRed,white,false,false)); //datatype list.append(new ItemStyle(blue,cyan,false,false)); //decimal/value list.append(new ItemStyle(darkCyan,cyan,false,false)); //base n list.append(new ItemStyle(darkMagenta,cyan,false,false));//float list.append(new ItemStyle(magenta,magenta,false,false)); //char list.append(new ItemStyle(red,red,false,false)); //string list.append(new ItemStyle(darkGray,gray,false,true)); //comment list.append(new ItemStyle(darkGreen,green,false,false)); //others #warning fixme /* config = KateFactory::instance()->config(); config->setGroup("Default Item Styles"); for (z = 0; z < defaultStyles(); z++) { i = list.at(z); s = config->readEntry(defaultStyleName(z)); if (!s.isEmpty()) { sscanf(s.latin1(),"%X,%X,%d,%d",&col,&selCol,&i->bold,&i->italic); i->col.setRgb(col); i->selCol.setRgb(selCol); } } */ } void HlManager::setDefaults(ItemStyleList &list) { KateConfig *config; int z; ItemStyle *i; char s[64]; #warning fixme /* diff --git a/noncore/apps/tinykate/libkate/document/katehighlight.h b/noncore/apps/tinykate/libkate/document/katehighlight.h index fddf585..f0be27b 100644 --- a/noncore/apps/tinykate/libkate/document/katehighlight.h +++ b/noncore/apps/tinykate/libkate/document/katehighlight.h @@ -1,349 +1,349 @@ /* Copyright (C) 1998, 1999 Jochen Wilhelmy digisnap@cs.tu-berlin.de (C) 2002, 2001 The Kate Team <kwrite-devel@kde.org> (C) 2002 Joseph Wenninger <jowenn@kde.org> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _HIGHLIGHT_H_ #define _HIGHLIGHT_H_ #include <qlist.h> #include <qdialog.h> #include <kcolorbtn.h> #include <qstrvec.h> #include <qdict.h> #include <qregexp.h> #include "../qt3back/qregexp3.h" #include <kdebug.h> class SyntaxDocument; struct syntaxModeListItem; struct syntaxContextData; class QCheckBox; class QComboBox; class QLineEdit; class TextLine; class Attribute; class HlItem { public: HlItem(int attribute, int context); virtual ~HlItem(); virtual bool startEnable(QChar); virtual const QChar *checkHgl(const QChar *, int len, bool) = 0; QList<HlItem> *subItems; int attr; int ctx; }; class HlCharDetect : public HlItem { public: HlCharDetect(int attribute, int context, QChar); virtual const QChar *checkHgl(const QChar *, int len, bool); protected: QChar sChar; }; class Hl2CharDetect : public HlItem { public: Hl2CharDetect(int attribute, int context, QChar ch1, QChar ch2); Hl2CharDetect(int attribute, int context, const QChar *ch); virtual const QChar *checkHgl(const QChar *, int len, bool); protected: QChar sChar1; QChar sChar2; }; class HlStringDetect : public HlItem { public: HlStringDetect(int attribute, int context, const QString &, bool inSensitive=false); virtual ~HlStringDetect(); virtual const QChar *checkHgl(const QChar *, int len, bool); protected: const QString str; bool _inSensitive; }; class HlRangeDetect : public HlItem { public: HlRangeDetect(int attribute, int context, QChar ch1, QChar ch2); virtual const QChar *checkHgl(const QChar *, int len, bool); protected: QChar sChar1; QChar sChar2; }; class HlKeyword : public HlItem { public: HlKeyword(int attribute, int context,bool casesensitive, const QChar *deliminator, uint deliLen); virtual ~HlKeyword(); virtual void addWord(const QString &); virtual void addList(const QStringList &); virtual const QChar *checkHgl(const QChar *, int len, bool); QStringList getList() { return words;}; virtual bool startEnable(QChar c); protected: QStringList words; QDict<bool> dict; bool _caseSensitive; const QChar *deliminatorChars; uint deliminatorLen; }; class HlPHex : public HlItem { public: HlPHex(int attribute,int context); virtual const QChar *checkHgl(const QChar *, int len, bool); }; class HlInt : public HlItem { public: HlInt(int attribute, int context); virtual const QChar *checkHgl(const QChar *, int len, bool); }; class HlFloat : public HlItem { public: HlFloat(int attribute, int context); virtual const QChar *checkHgl(const QChar *, int len, bool); }; class HlCInt : public HlInt { public: HlCInt(int attribute, int context); virtual const QChar *checkHgl(const QChar *, int len, bool); }; class HlCOct : public HlItem { public: HlCOct(int attribute, int context); virtual const QChar *checkHgl(const QChar *, int len, bool); }; class HlCHex : public HlItem { public: HlCHex(int attribute, int context); virtual const QChar *checkHgl(const QChar *, int len, bool); }; class HlCFloat : public HlFloat { public: HlCFloat(int attribute, int context); virtual const QChar *checkHgl(const QChar *, int len, bool); }; class HlLineContinue : public HlItem { public: HlLineContinue(int attribute, int context); virtual bool endEnable(QChar c) {return c == '\0';} virtual const QChar *checkHgl(const QChar *, int len, bool); }; class HlCStringChar : public HlItem { public: HlCStringChar(int attribute, int context); virtual const QChar *checkHgl(const QChar *, int len, bool); }; class HlCChar : public HlItem { public: HlCChar(int attribute, int context); virtual const QChar *checkHgl(const QChar *, int len, bool); }; class HlAnyChar : public HlItem { public: HlAnyChar(int attribute, int context, const QChar* charList, uint len); virtual const QChar *checkHgl(const QChar *, int len, bool); const QChar* _charList; uint _charListLen; }; class HlRegExpr : public HlItem { public: HlRegExpr(int attribute, int context,QString expr); - ~HlRegExpr(){delete Expr;}; + ~HlRegExpr(); virtual const QChar *checkHgl(const QChar *, int len, bool); QRegExp3 *Expr; bool handlesLinestart; }; //-------- //Item Style: color, selected color, bold, italic class ItemStyle { public: ItemStyle(); // ItemStyle(const ItemStyle &); ItemStyle(const QColor &, const QColor &, bool bold, bool italic); ItemStyle(ItemStyle *its){col=its->col;selCol=its->selCol; bold=its->bold; italic=its->italic;} // void setData(const ItemStyle &); QColor col; QColor selCol; int bold; //boolean value int italic; //boolean value }; typedef QList<ItemStyle> ItemStyleList; //Item Properties: name, Item Style, Item Font class ItemData : public ItemStyle { public: ItemData(const QString name, int defStyleNum); ItemData(const QString name, int defStyleNum, const QColor&, const QColor&, bool bold, bool italic); ItemData(ItemData *itd):ItemStyle((ItemStyle*)itd),name(itd->name),defStyleNum(itd->defStyleNum),defStyle(itd->defStyle){;} const QString name; int defStyleNum; int defStyle; //boolean value }; typedef QList<ItemData> ItemDataList; class HlData { public: HlData(const QString &wildcards, const QString &mimetypes,const QString &identifier); ItemDataList itemDataList; QString wildcards; QString mimetypes; QString identifier; }; typedef QList<HlData> HlDataList; class HlManager; class KateConfig; //context class HlContext { public: HlContext(int attribute, int lineEndContext,int _lineBeginContext); QList<HlItem> items; int attr; int ctx; int lineBeginContext; }; class Highlight { friend class HlManager; public: Highlight(syntaxModeListItem *def); ~Highlight(); int doHighlight(int ctxNum, TextLine *); KateConfig *getKateConfig(); QString getWildcards(); QString getMimetypes(); HlData *getData(); void setData(HlData *); void getItemDataList(ItemDataList &); void getItemDataList(ItemDataList &, KateConfig *); void setItemDataList(ItemDataList &, KateConfig *); QString name() {return iName;} QString section() {return iSection;} void use(); void release(); bool isInWord(QChar c); QString getCommentStart() {return cmlStart;}; QString getCommentEnd() {return cmlEnd;}; QString getCommentSingleLineStart() { return cslStart;}; protected: void init(); void done(); void makeContextList (); void createItemData (ItemDataList &list); void readGlobalKeywordConfig(); void readCommentConfig(); HlItem *createHlItem(struct syntaxContextData *data, ItemDataList &iDl); int lookupAttrName(const QString& name, ItemDataList &iDl); ItemDataList internalIDList; static const int nContexts = 32; HlContext *contextList[nContexts]; bool noHl; bool casesensitive; QString weakDeliminator; QString deliminator; const QChar *deliminatorChars; uint deliminatorLen; QString cmlStart; QString cmlEnd; QString cslStart; QString iName; QString iSection; QString iWildcards; QString iMimetypes; QString identifier; int refCount; }; class HlManager : public QObject { Q_OBJECT public: HlManager(); ~HlManager(); static HlManager *self(); Highlight *getHl(int n); int defaultHl(); int nameFind(const QString &name); int wildcardFind(const QString &fileName); int findHl(Highlight *h) {return hlList.find(h);} int makeAttribs(Highlight *, Attribute *, int maxAttribs); int defaultStyles(); QString defaultStyleName(int n); void getDefaults(ItemStyleList &); void setDefaults(ItemStyleList &); int highlights(); QString hlName(int n); QString hlSection(int n); void getHlDataList(HlDataList &); void setHlDataList(HlDataList &); SyntaxDocument *syntax; signals: void changed(); protected: QList<Highlight> hlList; static HlManager *s_pSelf; }; #endif //_HIGHLIGHT_H_ |