📄 htmltable.cpp
字号:
/* This file is part of the KDE libraries Copyright (C) 1997 Martin Jones (mjones@kde.org) (C) 1997 Torben Weis (weis@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.*///// KDE HTML Widget//#include <kurl.h>#include "htmlchain.h"#include "htmlobj.h"#include "htmlclue.h"#include "htmltable.h"#include "html.h"#include <stdio.h>#include <stdlib.h>#include <ctype.h>#include <string.h>#include <qimage.h>#include <qdrawutil.h>//#define CLUE_DEBUG//#define DEBUG_ALIGN//-----------------------------------------------------------------------------HTMLTableCell::HTMLTableCell( int _x, int _y, int _max_width, int _percent, int rs, int cs, int pad ) : HTMLClueV( _x, _y, _max_width, _percent ){ refcount = 0; rspan = rs; cspan = cs; padding = pad; width = _max_width; if(percent == 0) setFixedWidth(true);}void HTMLTableCell::setMaxWidth( int _max_width ){ HTMLObject *obj; max_width = _max_width; if (max_width > 0) { if ( percent > 0 ) width = _max_width * percent / 100; else if ( !isFixedWidth() ) width = max_width; } for ( obj = head; obj != 0; obj = obj->next() ) obj->setMaxWidth( max_width );}void HTMLTableCell::setWidth(int _width){ HTMLObject *obj; width = _width; if(!isFixedWidth()) max_width = width; for ( obj = head; obj != 0; obj = obj->next() ) obj->setMaxWidth( width );}int HTMLTableCell::calcMinWidth(){ HTMLObject *obj; int minWidth = 0; for ( obj = head; obj != 0; obj = obj->next() ) { int w = obj->calcMinWidth(); if ( w > minWidth ) minWidth = w; } if ( isFixedWidth() ) { // Our minimum width is at least our fixed width if (max_width > minWidth) minWidth = max_width; // And our actual width is at least our minimum width. if (width < minWidth) width = minWidth; } return minWidth;}bool HTMLTableCell::print( QPainter *_painter, int _x, int _y, int _width, int _height, int _tx, int _ty, bool toPrinter ){ if ( _y + _height < y - getAscent() || _y > y + descent ) return false; if ( bg.isValid() ) { int top = _y - ( y - getAscent() ); int bottom = top + _height; if ( top < -padding ) top = -padding; if ( bottom > getAscent() + padding ) bottom = getAscent() + padding; QBrush brush( bg ); _painter->fillRect( _tx + x - padding, _ty + y - ascent + top, width + padding * 2, bottom - top, brush ); // another hack... HTMLObject *obj; for ( obj = head; obj != 0; obj = obj->next() ) obj->setBgColor(bg); } return HTMLClueV::print( _painter, _x, _y, _width, _height, _tx, _ty, toPrinter );}void HTMLTableCell::print( QPainter *_painter, HTMLChain *_chain, int _x, int _y, int _width, int _height, int _tx, int _ty ){ if ( bg.isValid() ) { int top = _y - ( y - getAscent() ); int bottom = top + _height; if ( top < -padding ) top = -padding; if ( bottom > getAscent() + padding ) bottom = getAscent() + padding; int left = _x - x; int right = left + _width; if ( left < -padding ) left = -padding; if ( right > width + padding ) right = width + padding; QBrush brush( bg ); _painter->fillRect( _tx + x + left, _ty + y - ascent + top, right - left, bottom - top, brush ); // another hack... HTMLObject *obj; for ( obj = head; obj != 0; obj = obj->next() ) obj->setBgColor(bg); } HTMLClue::print( _painter, _chain, _x, _y, _width, _height, _tx, _ty );}//-----------------------------------------------------------------------------HTMLTable::HTMLTable( int _x, int _y, int _max_width, int _width, int _percent, int _padding, int _spacing, int _border ) : HTMLObject(){ x = _x; y = _y; max_width = _max_width; width = _width; percent = _percent; padding = _padding; spacing = _spacing; border = _border; caption = 0L; setFixedWidth( false ); row = 0; col = 0; totalCols = 1; // this should be expanded to the maximum number of cols // by the first row parsed totalRows = 1; allocRows = 5; // allocate five rows initially cells = new HTMLTableCell ** [allocRows]; for ( unsigned int r = 0; r < allocRows; r++ ) { cells[r] = new HTMLTableCell * [totalCols]; memset( cells[r], 0, totalCols * sizeof( HTMLTableCell * ) ); } if ( percent > 0 ) width = max_width * percent / 100; else if ( width == 0 ) width = max_width; else {//WABA does this make sense? //Lars: sorry... no, it makes some tbales look _really_ ugly max_width = width; setFixedWidth( TRUE ); }}void HTMLTable::startRow(){ col = 0;}void HTMLTable::addCell( HTMLTableCell *cell ){ while ( col < totalCols && cells[row][col] != 0L ) col++; setCells( row, col, cell ); col++;}void HTMLTable::endRow(){ while ( col < totalCols && cells[row][col] != 0 ) col++; if ( col ) row++;}void HTMLTable::setCells( unsigned int r, unsigned int c, HTMLTableCell *cell ){ unsigned int endRow = r + cell->rowSpan(); unsigned int endCol = c + cell->colSpan(); // The first row sets the number of columns. Do not allow subsequent // rows to change the number of columns.//WABA: Why not? Let's give crappy HTML a chance// if ( row != 0 && endCol > totalCols )// endCol = totalCols; if ( endCol > totalCols ) addColumns( endCol - totalCols ); if ( endRow >= allocRows ) addRows( endRow - allocRows + 10 ); if ( endRow > totalRows ) totalRows = endRow; for ( ; r < endRow; r++ ) { for ( unsigned int tc = c; tc < endCol; tc++ ) { // WABA: We do semi-automatic reference counting :] if (cells[r][tc]) cells[r][tc]->unlink(); cells[r][tc] = cell; cell->link(); } }}void HTMLTable::addRows( int num ){ HTMLTableCell ***newRows = new HTMLTableCell ** [allocRows + num]; memcpy( newRows, cells, allocRows * sizeof(HTMLTableCell **) ); delete [] cells; cells = newRows; for ( unsigned int r = allocRows; r < allocRows + num; r++ ) { cells[r] = new HTMLTableCell * [totalCols]; memset( cells[r], 0, totalCols * sizeof( HTMLTableCell * ) ); } allocRows += num;}void HTMLTable::addColumns( int num ){ HTMLTableCell **newCells; for ( unsigned int r = 0; r < allocRows; r++ ) { newCells = new HTMLTableCell * [totalCols+num]; memcpy( newCells, cells[r], totalCols * sizeof( HTMLTableCell * ) ); memset( newCells + totalCols, 0, num * sizeof( HTMLTableCell * ) ); delete [] cells[r]; cells[r] = newCells; } totalCols += num;}void HTMLTable::endTable(){// totalRows = row; // calculate min/max widths calcColInfo(); calcColumnWidths();}void HTMLTable::calcAbsolutePos( int _x, int _y ){ int lx = _x + x; int ly = _y + y - ascent; HTMLTableCell *cell; unsigned int r, c; for ( r = 0; r < totalRows; r++ ) { for ( c = 0; c < totalCols; c++ ) { if ( ( cell = cells[r][c] ) == 0 ) continue; if ( c < totalCols - 1 && cell == cells[r][c+1] ) continue; if ( r < totalRows - 1 && cells[r+1][c] == cell ) continue; cell->calcAbsolutePos( lx, ly ); } }}bool HTMLTable::getObjectPosition( const HTMLObject *objp, int &xp, int &yp ){ HTMLTableCell *cell; xp += x; yp += (y - ascent); unsigned int r, c; for ( r = 0; r < totalRows; r++ ) { for ( c = 0; c < totalCols; c++ ) { if ( ( cell = cells[r][c] ) == 0 ) continue; if ( c < totalCols - 1 && cell == cells[r][c+1] ) continue; if ( r < totalRows - 1 && cells[r+1][c] == cell ) continue; if ( cell->getObjectPosition( objp, xp, yp ) ) return true; } } xp -= x; yp -= (y - ascent); return false;}HTMLAnchor* HTMLTable::findAnchor( const char *_name, QPoint *_p ){ HTMLAnchor *ret; HTMLTableCell *cell; _p->setX( _p->x() + x ); _p->setY( _p->y() + y - ascent ); unsigned int r, c; for ( r = 0; r < totalRows; r++ ) { for ( c = 0; c < totalCols; c++ ) { if ( ( cell = cells[r][c] ) == 0 ) continue; if ( c < totalCols - 1 && cell == cells[r][c+1] ) continue; if ( r < totalRows - 1 && cells[r+1][c] == cell ) continue; ret = cell->findAnchor( _name, _p ); if ( ret != 0 ) return ret; } } _p->setX( _p->x() - x ); _p->setY( _p->y() - y + ascent ); return 0;}void HTMLTable::reset(){ unsigned int r, c; HTMLTableCell *cell; for ( r = 0; r < totalRows; r++ ) { for ( c = 0; c < totalCols; c++ ) { if ( ( cell = cells[r][c] ) == 0 ) continue; if ( c < totalCols - 1 && cell == cells[r][c+1] ) continue; if ( r < totalRows - 1 && cells[r+1][c] == cell ) continue; cell->reset(); } } calcColInfo();}void HTMLTable::calcSize( HTMLClue * ){ unsigned int r, c; int indx; HTMLTableCell *cell; // recalculate min/max widths calcColumnWidths(); // If it doesn't fit... MAKE IT FIT! for ( c = 0; c < totalCols; c++ ) { if (columnPos[c+1] > max_width-border) columnPos[c+1] = max_width-border; } // Attempt to get sensible cell widths optimiseCellWidth(); // set cell widths and then calculate cell sizes for ( r = 0; r < totalRows; r++ ) { for ( c = 0; c < totalCols; c++ ) { if ( ( cell = cells[r][c] ) == 0 ) continue; if ( c < totalCols - 1 && cell == cells[r][c+1] ) continue; if ( r < totalRows - 1 && cell == cells[r+1][c] ) continue; if ( ( indx = c-cell->colSpan()+1 ) < 0 ) indx = 0; int w = columnOpt[c+1] - columnOpt[ indx ] - spacing - padding - padding; cell->setWidth( w ); cell->calcSize(); } } if ( caption ) { caption->setMaxWidth( columnOpt[ totalCols ] + border ); caption->calcSize(); if ( capAlign == HTMLClue::Top ) caption->setPos( 0, caption->getAscent() ); } // We have the cell sizes now, so calculate the vertical positions calcRowHeights(); // set cell positions for ( r = 0; r < totalRows; r++ ) { int cellHeight; ascent = rowHeights[r+1] - padding - spacing; if ( caption && capAlign == HTMLClue::Top ) ascent += caption->getHeight(); for ( c = 0; c < totalCols; c++ ) { if ( ( cell = cells[r][c] ) == 0 ) continue; if ( c < totalCols - 1 && cell == cells[r][c+1] ) continue; if ( r < totalRows - 1 && cell == cells[r+1][c] ) continue; if ( ( indx = c-cell->colSpan()+1 ) < 0 ) indx = 0; cell->setPos( columnOpt[indx] + padding, ascent - cell->getDescent() ); if ( ( indx = r-cell->rowSpan()+1 ) < 0 ) indx = 0; cellHeight = rowHeights[r+1] - rowHeights[indx] - padding - padding - spacing; cell->setMaxAscent( cellHeight ); } } if ( caption && capAlign == HTMLClue::Bottom ) caption->setPos( 0, rowHeights[ totalRows ] + border + caption->getAscent() );// CRH 2 borders for size// width = columnOpt[ totalCols ] + border;// ascent = rowHeights[ totalRows ] + border; width = columnOpt[ totalCols ] + (border * 2); ascent = rowHeights[ totalRows ] + (border * 2); if ( caption ) ascent += caption->getHeight();}// Both the minimum and preferred column sizes are calculated here.// The hard part is choosing the actual sizes based on these two.void HTMLTable::calcColumnWidths(){ unsigned int r, c; int indx, borderExtra = ( border == 0 ) ? 0 : 1; colType.resize( totalCols+1 ); colType.fill( Variable ); columnPos.resize( totalCols+1 ); columnPos[0] = border + spacing; columnPrefPos.resize( totalCols+1 ); columnPrefPos[0] = border + spacing; colSpan.resize( totalCols+1 ); colSpan.fill( 1 ); for ( c = 0; c < totalCols; c++ ) { columnPos[c+1] = 0; columnPrefPos[c+1] = 0; for ( r = 0; r < totalRows; r++ ) { HTMLTableCell *cell = cells[r][c]; int colPos; if ( cell == 0 ) continue; if ( c < totalCols - 1 && cells[r][c+1] == cell ) continue; if ( r < totalRows - 1 && cells[r+1][c] == cell ) continue; if ( ( indx = c-cell->colSpan()+1 ) < 0 ) indx = 0; // calculate minimum pos. colPos = columnPos[indx] + cell->calcMinWidth() + padding + padding + spacing + borderExtra; if ( columnPos[c + 1] < colPos ) columnPos[c + 1] = colPos; if ( colType[c + 1] != Variable ) { continue; } // calculate preferred pos if ( cell->getPercent() > 0 ) { colPos = columnPrefPos[indx] + ( max_width * cell->getPercent() / 100 ) + padding + padding + spacing + borderExtra; colType[c + 1] = Percent; colSpan[c + 1] = cell->colSpan(); columnPrefPos[c + 1] = colPos; } else if ( cell->isFixedWidth() ) { colPos = columnPrefPos[indx] + cell->getWidth() + padding + padding + spacing + borderExtra; colType[c + 1] = Fixed; colSpan[c + 1] = cell->colSpan(); columnPrefPos[c + 1] = colPos; } else { colPos = cell->calcPreferredWidth(); colPos += columnPrefPos[indx] + padding + padding + spacing + borderExtra; if ( columnPrefPos[c + 1] < colPos ) columnPrefPos[c + 1] = colPos; } if ( columnPrefPos[c + 1] < columnPos[c + 1] ) columnPrefPos[c + 1] = columnPos[c + 1]; } if (columnPos[c + 1] <= columnPos[c]) columnPos[c + 1] = columnPos[c]; if (columnPrefPos[c + 1] <= columnPrefPos[c]) columnPrefPos[c + 1] = columnPrefPos[c]+1; }}// Use the minimum and preferred cell widths to produce an optimum// cell spacing. When this has been done columnOpt contains// the optimum cell widths.void HTMLTable::optimiseCellWidth()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -