Logo Search packages:      
Sourcecode: qps version File versions  Download package

htable.cpp

// Warning !!!:
//    very dirty and toooo complex code ( fasthyun@magicn.com) 

//    1. this htable be made for small table size

// htable.cpp 
// This program is free software. See the file COPYING for details.
// Author: Mattias Engdegård, 1997-1999

// TODO:
// * autoscroll speed proportional to distance from edge  
// * interface to add/remove rows (for disclosure triangles)
// * interface to display pixmaps in cells (for disclosure triangles etc)
// * include sorting functionality here for more generality

#include <stdlib.h>

#include <qaccel.h>
#include <qbitmap.h>
#include <qpainter.h>
#include <qpixmap.h>

#include "htable.h"
#include "svec.cpp"
#include "qps.h"



// HeadingTip: tooltips for headings
HeadingTip::HeadingTip(QWidget *parent)   : QToolTip(parent)
{
}


void HeadingTip::maybeTip(const QPoint &pos)
{
      ((TableHead *)parentWidget())->tip(pos);
}

// TableHead: the horizontally scrollable table head
TableHead::TableHead(HeadedTable *parent)
      : QtTableView(parent),
      htable(parent),
      left_pressed(FALSE),
      dragging(FALSE)
{
      setBackgroundColor(colorGroup().background());
      setTableFlags(Tbl_smoothHScrolling | Tbl_scrollLastHCell);
      setNumRows(1);
      if(htable->options & HTBL_HEADING_TOOLTIPS)
            htip = new HeadingTip(this); 
}

QString TableHead::text(int row,int col)
{ 
    return htable->title(col); 
}
// Why Mac ? 
void TableHead::drawMacPanel(QPainter *p, int x, int y, int w, int h, bool sunken)
{
      QColor c2;
      if(colorGroup().light()==colorGroup().background())
            c2 =  colorGroup().light().dark(115);
      else c2 =  colorGroup().light();

      if(sunken) {
            p->fillRect(x , y , w , h ,colorGroup().background().dark(109));
      } else {
            // when moving head field
            p->fillRect(x , y , w , h ,colorGroup().background());
      }

      p->setPen(c2);
      p->drawLine(x, y, x, y + h );  //vertical left
      p->drawLine(x, y, x + w , y);  //horizontal Top
      p->drawLine(x + w  , y , x + w  , y + h ); //vertical right
      p->drawLine(x , y + h -1 , x + w , y + h -1);  //horizontal Bottom
}

void TableHead::eraseRight(QPainter *p,QRect &rect )
{
      int i;
      int x;
      int w;
      QRect vrh = viewRect();
      int lastx = totalWidth() - xOffset();
      drawMacPanel(p,lastx,0,vrh.width() - lastx ,rect.height(),false);
}

// Description : draw a field name of table  when DRAGGing !!
//          called by paintHeading()
//          called by QtTableView::repaint() 
void TableHead::paintCell(QPainter *p, int row, int col,bool update)
{
      static int count=0;
      if(update==true)  // check cached value
      {
            if(isCellContentsChanged(row,col)==false)
                  return;
      }

      //if( col ==11 )  printf("head: %d  (%d) \n",col,count++);
      int gap = 6;
      int w = htable->max_widths[col]; 
    QString title=htable->title(col);

      drawMacPanel(p, 0, 0, w , cellheight, col == htable->sorted_col);
      p->setPen(colorGroup().buttonText());

      int a = htable->alignment_col[col];

      if(a == AlignRight)
          p->drawText(0, 0, w - gap, height(), AlignVCenter | a ,title);
      else
          p->drawText(gap, 0, w , height(), AlignVCenter | a ,title);

      if(0) //if(col == htable->ncols-1)
      {
            int i, w;
            w=0;
            for(i=0;i<htable->ncols;i++)
                  w+=htable->max_widths[i];

            if(w< width())
                  drawMacPanel(p,htable->max_widths[col ], 0, width()-w , cellheight,false );
      }
}

//virtual !
int TableHead::cellWidth(int col)
{
      return htable->max_widths[col];
}

void TableHead::scrollSideways(int val)
{
      setXOffset(val);
}

// draw a physical column heading in the "sunken" state
void TableHead::drawSunken(int col)
{
      int oldsorted = htable->sorted_col;
      htable->sorted_col = col;
      updateCell(0, col, true);
      htable->sorted_col = oldsorted;
}

// paint a (unsunken) heading of physical column at offset x
void TableHead::paintHeading(int x, int col)
{
      int w = htable->max_widths[col];
      int h = height();
      
      QPainter p(this);
      p.setClipRect(x, 0, w+1, h);  // +1 (by fasthyun@magicn.com) 
      p.translate(x, 0);                        // ???(by fasthyun@magicn.com) 
      int oldsorted = htable->sorted_col;
      htable->sorted_col = -1;
      paintCell(&p, 0, col,false);
      htable->sorted_col = oldsorted;
}

void TableHead::mousePressEvent(QMouseEvent *e)
{
      int col = findCol(e->x());
      if(col == -1) return;
      if(e->button() == RightButton && htable->options & HTBL_HEADING_CONTEXT_MENU) 
      {
            htable->emit_right_click_heading_signal(mapToGlobal(e->pos()),col);

      } else if(e->button() == LeftButton
                  && htable->options & HTBL_HEADING_CLICK) {
            left_pressed = TRUE;
            press = e->pos();
            drawSunken(col);
      }
      click_col = col;
}


void TableHead::mouseMoveEvent(QMouseEvent *e)
{
      if(left_pressed) {
            if(htable->options & HTBL_REORDER_COLS
                        && (dragging || abs(e->x() - press.x()) > drag_threshold)) {
                  if(click_col < 0)
                        click_col = findCol(press.x());
                  int w = cellWidth(click_col);
                  if(!dragging) {
                        dragging = TRUE;
                        updateCell(0, click_col);
                        drag_offset = press.x() - htable->colOffset(click_col) + xOffset();
                  } else {
                        repaint(drag_pos - drag_offset, 0, w, height()); // need
                        htable->body->drawGhostCol(drag_pos - drag_offset, w);
                  }
                  htable->body->drawGhostCol(e->x() - drag_offset, w);
                  paintHeading(e->x() - drag_offset, click_col);
                  drag_pos = e->x();
                  return;
            }
            int col = findCol(e->x());
            if(col == findCol(press.x())) {
                  if(click_col < 0) {
                        drawSunken(col);
                        click_col = col;
                  }
            } else {
                  if(click_col >= 0) {
                        updateCell(0, click_col);
                        click_col = -1;
                  }
            }
      }
}

void TableHead::mouseReleaseEvent(QMouseEvent *e)
{
      if(left_pressed) {
            left_pressed = FALSE;
            if(dragging) {
                  int w = cellWidth(click_col);
                  repaint(drag_pos - drag_offset, 0, w, height());
                  htable->body->drawGhostCol(drag_pos - drag_offset, w);
                  dragging = FALSE;
                  int col = findCol(e->x());
                  if(col < 0)
                        col = (e->x() < 0) ? 0 : htable->ncols - 1;
                  htable->moveCol(click_col, col);
                  return;
            }
            int col = findCol(e->x());
            if(col == findCol(press.x())) {
                  htable->emit_click_signal(col);
            } else if(click_col >= 0)
                  updateCell(0, click_col);
      }
}

void TableHead::tip(const QPoint &pos)
{
      int col = findCol(pos.x());
      if(col != -1) {
            QString s = htable->tipText(col);
            if(!s.isEmpty()) {
                  int x;
                  colXPos(col, &x);
                  htip->tip(QRect(x, 0, cellWidth(col), height()), s);
            }
      }
}
// TableBody: the table body, scrollable in all ways
TableBody::TableBody(HeadedTable *parent) : 
      QtTableView(parent), htable(parent)
{
      setBackgroundColor(colorGroup().background().light(124));   
      color_text=colorGroup().text(); //DEL
      setTableFlags(Tbl_autoScrollBars | Tbl_smoothScrolling); 
      
      ((QScrollBar *)horizontalScrollBar())->setTracking(TRUE);
      
      first_drag_row = prev_drag_row = -1;
      autoscrolling = FALSE;
      gadget_click = FALSE;
      setMouseTracking (true);
}

QString TableBody::text(int row, int col)
{
    return htable->text(row,col);
}

class CellAttribute 
{
      public:
      QString text;
      bool selected;
      bool sorted;
      
      QColor      backColor;
      QColor  foreColor;
      int xpos;
      int ypos;
      int   w;
      int depth;
      int   folded;
};


bool TableHead::isCellContentsChanged(int row,int col)
{
      CellAttribute *attr;
      int idx=col;
      int xpos;
      int ypos;
      int w;
      static int count=0;

      bool sorted =( htable->sortedCol()==col );

      w=htable->max_widths[col];
      xpos=htable->colXPos(col);
      attr=htable->cached_attr_h[col];
      if(attr==NULL)
      {
            attr=new CellAttribute();
            
            attr->text=text(row,col);
            attr->sorted=sorted;
            attr->xpos=xpos;
            attr->w=w;
            
            htable->cached_attr_h.insert(idx,attr);
            if(htable->cached_attr_h.count() >= htable->cached_attr_h.size())
                  htable->cached_attr_h.resize(htable->cached_attr_h.count()*2);

            return true;
      }
      else
      {
            if(
                        attr->text==text(row,col) 
                        and attr->sorted==sorted
                        and attr->xpos==xpos
                        and attr->w==w
                  );
            else
            {
                  attr->text=text(row,col);
                  attr->sorted=sorted;
                  attr->xpos=xpos;
                  attr->w=w;
                  //printf("head: %d,%d\n",row,col);
                  return true;
            }
      }           
      return false;
}

// 1. text
// 2. forColor,BackColor
// 3. 
bool HeadedTable::isBodyCellContentsChanged(int row,int col,bool head)
{
      CellAttribute *attr;
      int idx;
      int xpos;
      int   ypos;
      int   w;
      bool sorted = ( sortedCol()==col );
      bool selected;
      
      w=max_widths[col];
      xpos=colXPos(col);
      selected =isSelected(row);
      //int yoffrel= body->yOffsetRel();  // check func
      //printf("yoffrel=%d\n",yoffrel);
      //printf("yoff=%d\n",body->yOffset());
      //ypos-=yoffrel;
      //ypos+=body->yOffset();
      
      /*
      if(last_row!=row)
      {
            //printf("row=%d ypos=%d yoff=%d\n",row,ypos,body->yOffset());
            last_row=row;
      }
      */
      //convert2view(row,col);
      //int left = leftCell();
      //int top    = topCell();
      //int vrow= row-top;
      //int vcol= col-left;   
      //if(vrow<0) printf("kkk-row=%d \n",vrow); //idx=(vrow<<16)+vcol;
      if(head)
            idx=0+col;
      else 
            idx=(row<<16)+col;

      attr=cached_attr[idx];
      if(attr==NULL)
      {
            attr=new CellAttribute();
            
            attr->text=text(row,col);
            attr->selected=selected;
            attr->sorted=sorted;
            attr->xpos=xpos;
            //attr->ypos=ypos;
            attr->w=w;
            attr->depth=rowDepth(row); //level
            attr->folded=folded(row);

            cached_attr.insert(idx,attr);
            if(cached_attr.count() >= cached_attr.size())
                  cached_attr.resize(cached_attr.count()*2);
            
            return true;
      }
      else
      {
            bool result=false;
            if(         attr->text==text(row,col)
                        and attr->selected==isSelected(row) 
                        and attr->sorted==sorted
                        and attr->xpos==xpos
            //          and attr->ypos==ypos
                        and attr->w==w
                  )
            {

            }
            else
            {
                  attr->text=text(row,col);
                  attr->selected=isSelected(row);
                  attr->sorted=sorted;
                  attr->xpos=xpos;
            //    attr->ypos=ypos;
                  attr->w=w;
                  //attr->depth=rowDepth(row);
                  //attr->folded=folded(row);
                  result=true;
            }

            if(col==0)
            {
                  if( attr->depth==rowDepth(row)
                        and attr->folded==folded(row))
                        ;
                  else
                  {
                        attr->depth=rowDepth(row);
                        attr->folded=folded(row);
                        result=true;
                  }
            }

            return result;
      }           
      return false;
}

bool TableBody::isCellContentsChanged(int row,int col)
{
    return htable->isBodyCellContentsChanged(row,col,0);
}


void TableBody::eraseRight(QPainter *p,QRect &updateR)
{
      int i;
      int x;
      int w;
      QRect vrh = viewRect();
      int lastx = totalWidth() - xOffset();

      int firstRow = findRow( updateR.y() );
    int firstCol = findCol( updateR.x() );
    int      xStart, yStart;
      
      int r;
      //p->fillRect(updateR.x() ,updateR.y() , updateR.width() , updateR.height() ,colorGroup().highlight() );
      p->eraseRect(updateR);

      int h = cellheight - 1;
//    for(i=0;;);
//          p->fillRect(updateR.x() ,updateR.y() , updateR.width() , cellheight ,colorGroup().highlight() );

      //drawMacPanel(p,lastx,0,vrh.width() - lastx ,rect.height(),false);

      /*
      int real_w=htable->max_widths[col];
      int w;
      int h;
      bool sort;

      {
            int i, wid;
            wid=0;
            for(i=0;i<htable->ncols;i++)
                  wid+=htable->max_widths[i];//wid+=cellWidth(i);

            if(wid< width())
            {

//                if(htable->isSelected(row))
                        //p->setBackgroundColor(colorGroup().highlight()); 
//                      p->fillRect(real_w , 0 , width()-wid , h ,colorGroup().highlight() );
                  else 
                        //p->setBackgroundColor(normal_back);
                        p->fillRect(real_w , 0 , width()-wid , h ,normal_back);
                  
                  //p->eraseRect(real_w, 0, width()-wid, h);
                  p->setPen(normal_back.dark(107));
                  p->drawLine(real_w, cellheight - 1,real_w+width()-wid, cellheight - 1);
            }
            return;
      }*/

}

// DRAFT CODE !!  BOTTLENECK !!!
// Description : draw a cell of table  
//          1. draw the background of a cell
//          2. draw the text of a cell
//
// called by
//          1.QtTableView::paintEvent()
//                      
void TableBody::paintCell(QPainter *p, int row, int col,bool update)
{
      int real_w=htable->max_widths[col];
      int w,h;
      bool sort;
 
      QColor normal_back=colorGroup().background().light(124);
      

      // trick... fill the most right column  
      if(0) //if(col == htable->ncols+1)
      {
            int i, wid;
            wid=0;
            for(i=0;i<htable->ncols;i++)
                  wid+=htable->max_widths[i];//wid+=cellWidth(i);

            if(wid< width())
            {

                  if(htable->isSelected(row))
                        //p->setBackgroundColor(colorGroup().highlight()); 
                        p->fillRect(real_w , 0 , width()-wid , h ,colorGroup().highlight() );
                  else 
                        //p->setBackgroundColor(normal_back);
                        p->fillRect(real_w , 0 , width()-wid , h ,normal_back);
                  
                  //p->eraseRect(real_w, 0, width()-wid, h);
                  p->setPen(normal_back.dark(107));
                  p->drawLine(real_w, cellheight - 1,real_w+width()-wid, cellheight - 1);
            }
            return;
      }

      // *** sequence important !!!
      if(isCellContentsChanged(row,col)==false)
      {
            if(update==true)  return;
      }

      w=real_w;
      sort = col == htable->sortedCol();
      
      p->setPen(normal_back.dark(105));
      p->drawLine(0, cellheight - 1, w, cellheight - 1); // underline

      h = cellheight - 1;
      if(htable->isSelected(row)) {  
            if(sort)
                  p->fillRect(0 , 0 , real_w , h ,colorGroup().highlight().light(100*0xd7/0xee) );
            else
                  p->fillRect(0 , 0 , real_w , h ,colorGroup().highlight() );
            
            p->setPen(colorGroup().highlightedText()); // text 
      } 
      else 
      {
            if(sort){ 
                  p->fillRect(0, 0 ,real_w+1,h , normal_back );  // side |   |
                  p->fillRect(1 , 0 , real_w-1 ,h , normal_back.dark(107) );
            }
            else {
                  p->fillRect(0, 0 , real_w+1,h , normal_back );
            }
            p->setPen(colorGroup().text());      //text
      }
      
      htable->drawCellContents(row, col,real_w, cellheight, p);
}


void TableBody::scrollUp()
{
      setYOffset(yOffset() - cellheight);
}

void TableBody::scrollDown()
{
      setYOffset(yOffset() + cellheight);
}

void TableBody::pageUp()
{
      setYOffset(yOffset() - viewHeight());
}

void TableBody::pageDown()
{
      setYOffset(yOffset() + viewHeight());
}

void TableBody::scrollLeft()
{     
      setXOffset(xOffset() - cellheight);
}

void TableBody::scrollRight()
{
      // Qt bug: setXOffset() doesn't clamp to maximum offset
      setXOffset(QMIN(xOffset() + cellheight, maxXOffset()));
}

//DEL , Home key 
void TableBody::jumpTop()
{
      setYOffset(0);
}

//DEL, End Key
void TableBody::jumpBottom()
{
      setYOffset(maxYOffset());
}

void TableBody::centerVertically(int row)
{
      int topcell = row - viewHeight() / (cellheight * 2);
      setTopCell(QMAX(topcell, 0));
      update();
}

//??
void TableBody::showRange(int from, int to)
{
      int h = viewHeight() / cellheight;
      if(to >= topCell() + h)
            setTopCell(QMAX(0, QMIN(from, to - h + 1)));
}

//virtual
//called by 
//    1.
int TableBody::cellWidth(int col)
{
      return htable->max_widths[col];
}

// **** fix !!
void TableBody::updateRow(int row)
{
      for(int col = 0; col < htable->ncols; col++)
            //updateCell(row, col,false);
            updateCell(row, col);
}

void TableBody::wheelEvent ( QWheelEvent * e )
{
      int i, count; 
      int vrows;
      vrows=viewHeight()/cellheight;
      count=htable->nrows/vrows;
      count*=2;

      if( count > vrows) 
            count=vrows;

      if(e->delta() > 0)
      {
            for(i=0;i<count;i++)
                  scrollUp();
                  ///setYOffset(yOffset() - cellheight);
      }
      else 
      {
            for(i=0;i<count;i++)
                  scrollDown();
      }
}


void TableBody::mousePressEvent(QMouseEvent *e)
{
      if(numRows()==0) return;  // *** prevent out of range 

      int row = findRow(e->y());
      
      if((htable->options & HTBL_ROW_SELECTION) && e->button() == LeftButton) {
            if(row == -1) {
                  htable->clearAllSelections();
                  if(e->y() >= 0)
                        row = numRows();
                  first_drag_row = prev_drag_row = row;
            } else {
                  if(e->state() & Qt::ShiftButton) {
                        int col = findCol(e->x());
                        if(col >= 0) {
                              QString s = htable->text(row, col);
                              for(int i = 0; i < numRows(); i++) {
                                    if(s == htable->text(i, col))
                                          htable->setSelected(i, TRUE);
                                    else if(!(e->state() & ShiftButton))
                                          htable->setSelected(i, FALSE);
                              }
                        }
                  } else {
                        if(htable->treemode && htable->folding
                                    && e->x() < htable->gadget_space
                                    + htable->treestep * htable->rowDepth(row)
                                    && htable->folded(row) != HeadedTable::Leaf) {
                              htable->emit_fold(row);
                              gadget_click = TRUE;
                              return;
                        }
                        if(e->state() & Qt::ControlButton)
                              htable->setSelected(row, !htable->isSelected(row));
                        else
                              htable->selectOnly(row);
                        first_drag_row = prev_drag_row = row;
                  }
            }
            htable->selectionNotify();

      } else if((htable->options & HTBL_ROW_CONTEXT_MENU)
                  && e->button() == RightButton && row != -1) {
            if((htable->options & HTBL_ROW_SELECTION) && !htable->isSelected(row))
                  htable->selectOnly(row);
            htable->selectionNotify();
            htable->emit_right_click_signal(mapToGlobal(e->pos()));
      }
}

void TableBody::mouseDoubleClickEvent(QMouseEvent *e)
{
      if(htable->options & HTBL_ROW_DOUBLE_CLICK && e->button() == LeftButton) {
            int row = findRow(e->y());
            if(row != -1) {
                  if(htable->options & HTBL_ROW_SELECTION
                              && !htable->isSelected(row))
                        htable->selectOnly(row);
                  htable->selectionNotify();
                  htable->emit_double_click_signal(row);
            }
      }
}

#include "global.h"
#include "misc.h"
void TableBody::mouseMoveEvent(QMouseEvent *e)
{
      if(numRows()==0) return;  // *** prevent out of range 
      
      //DRAFT CODE !
      if(infobox!=NULL)
      {     
            if(htable->nselected>=2)
            {
                  infobox->show();
                  infobox->move(10+e->x(),htable->y()+e->y());
                  int col=findCol(e->x());
                  char *str=htable->total_selectedRow(col);
                  
                  if(str>0)
                  {
                        infobox->setText(str);
                  }
                  else
                        infobox->hide();
            }
            else 
                  infobox->hide();
      }
      
      if(e->state()== Qt::NoButton) return;

      if(!(htable->options & HTBL_ROW_SELECTION)
                  || e->state() & ControlButton || gadget_click)
            return;
      int row = findRow(e->y());
      if(row != prev_drag_row) {
            if(row == -1) {
                  if(!autoscrolling) {
                        // dragging outside table, cause scrolling
                        scrolldir = (e->y() < 0) ? UP : DOWN;
                        killTimers();
                        startTimer(scroll_delay);
                        autoscrolling = TRUE;
                  }
            } else {
                  killTimers();
                  autoscrolling = FALSE;
                  dragSelectTo(row);
            }
      }
}

void TableBody::mouseReleaseEvent(QMouseEvent *)
{
      gadget_click = FALSE;
      if(autoscrolling) {
            killTimers();           // no more autoscrolling
            first_drag_row = prev_drag_row = -1;
            autoscrolling = FALSE;
      }
}

void TableBody::timerEvent(QTimerEvent *)
{
      if(!autoscrolling) return;
      killTimers();
      if(scrolldir == UP) {
            int top = topCell();
            setTopCell((top > 1) ? top - 1 : 0);
            dragSelectTo(topCell());
      } else {
            setTopCell(topCell() + 1);
            int bottom = lastRowVisible();
            dragSelectTo((bottom < numRows()) ? bottom : numRows() - 1);
      }
      startTimer(scroll_delay);
}

// change drag selection point from previous drag position to row
void TableBody::dragSelectTo(int row)
{
      int dir = (row > prev_drag_row) ? 1 : -1;
      if((prev_drag_row - first_drag_row) * dir >= 0) {
            // moving away from start point
            for(int i = prev_drag_row + dir; i - dir != row; i += dir)
                  htable->setSelected(i, TRUE);
      } else {
            // moving towards start point
            for(int i = prev_drag_row; i != row; i += dir)
                  htable->setSelected(i, FALSE);
      }
      prev_drag_row = row;
      htable->selectionNotify();
}

// heuristic for determining a good XOR color: This is in general a hard
// problem but since we know (most of) the background and the foreground,
// we can try. Note that this function might not return an allocated QColor,
// so it is only useful for XOR drawing.

QColor TableBody::getXorColor()
{
      QColor fg=colorGroup().foreground();
      return QColor(0, fg.pixel() ^ backgroundColor().pixel());
}

void TableBody::drawGhostCol(int x, int w)
{
      static QColor xorcol = getXorColor();

      QPainter p(this);
      p.setPen(xorcol);
      p.setRasterOp(XorROP);
      p.drawLine(x, 0, x, height());
      //p.drawLine(x + w-1, 0, x + w-1, height());
      p.drawLine(x + w, 0, x + w, height());
}

// HeadedTable: the actually useable class
HeadedTable::HeadedTable(QWidget *parent, int opts): QWidget(parent),
      options(opts)
{
      folding = FALSE;
      closed_pm=NULL;
      open_pm=NULL;
      head = new TableHead(this);
      body = new TableBody(this);
      sorted_col = -1;
      nrows = ncols = -1;
      nrows_prev=ncols_prev=-1;
      nselected   = 0;
      treemode    = false;
      lines       = true;
      gadget_space = 0;
      cached_attr.setAutoDelete (true);
      cached_attr_h.setAutoDelete (true);

      // connect keyboard shortcuts
      QAccel *acc = new QAccel(this);
      acc->connectItem(acc->insertItem(Key_Up),body, SLOT(scrollUp()));
      acc->connectItem(acc->insertItem(Key_Down),body, SLOT(scrollDown()));
      acc->connectItem(acc->insertItem(Key_Left),body, SLOT(scrollLeft()));
      acc->connectItem(acc->insertItem(Key_Right),body, SLOT(scrollRight()));
      acc->connectItem(acc->insertItem(Key_Prior),body, SLOT(pageUp()));
      acc->connectItem(acc->insertItem(Key_Next),body, SLOT(pageDown()));
      acc->connectItem(acc->insertItem(Key_Home),body, SLOT(jumpTop()));
      acc->connectItem(acc->insertItem(Key_End),body, SLOT(jumpBottom()));
      acc->connectItem(acc->insertItem(CTRL+Key_A),this, SLOT(selectAll()));
      // connect( sb, SIGNAL(valueChanged(int)),  SLOT(verSbValue(int)));

    // synchronize horizontal scrolling of head and body
      connect(body->horizontalScrollBar(), SIGNAL(valueChanged(int)),head, SLOT(scrollSideways(int)));
      fontChange( font()) ; // *** need for init 
}

HeadedTable::~HeadedTable()
{
      if(closed_pm)
      {
            delete closed_pm;
            delete open_pm;
      }
}

//ok
void HeadedTable::fontChange( const QFont & oldFont ) 
{
      //printf("fontChange()\n");
      int cellheight = fontMetrics().lineSpacing();
      head->setCellHeight(cellheight+4);
      body->setCellHeight(cellheight);
      treestep = cellheight;
      gadget_space = folding ? cellheight + (cellheight >> 1) : 0;
      make_gadgets();
//    QWidget::fontChange ( oldFont );
}

void HeadedTable::setNumRows(int rows)
{
      nrows_prev=nrows;
      selected.fill(FALSE, rows);
      nselected = 0;
      nrows = rows;
      body->setNumRows(rows);
}

void HeadedTable::setNumCols(int cols)
{
      ncols_prev=ncols;
      ncols = cols;
      resetWidths();
      head->setNumCols(cols);
      body->setNumCols(cols);
      
      for(int i = 0; i < numCols(); i++)
      {
            if(i==numCols()+1)
            {
                  alignment_col[i]=0;
                  max_widths[i] = 100;
            }
            else
            {
                  alignment_col[i]=alignment(i);
                  updateColWidth(i);

            }
      }
}
//???
// Update the QtTableView's notion of horizontal offset in case column
// widths have changed. Nothing is repainted.
void HeadedTable::updateColWidths()
{
      // Updating the internal state is only done in QtTableView::setOffset(),
      // so we are forced to the following contortion. The bug has been
      // reported (QtTableView::updateTableSize() should have done it but
      // doesn't).

      //printf("DEBUG : updateColWidths !!! check this function\n");
      int xo = head->xOffset();
      setAutoUpdate(FALSE);
      head->setOffset(0, head->yOffset(), FALSE);
      head->setOffset(xo, head->yOffset(), FALSE);
      body->setOffset(0, body->yOffset(), FALSE);
      body->setOffset(xo, body->yOffset(), FALSE);
      setAutoUpdate(TRUE);
}

// DRAFT
void HeadedTable::moveCol(int col, int place)
{
      //if(treemode && (place == 0 || oldplace == 0)) {
      //    resetWidth(col);
      //    resetWidth(place);
      //}
      //updateColWidths();
      //if(treemode && (place == 0 || oldplace == 0))
      //    repaintAll();
      //else
      //    repaintColumns(QMIN(place, oldplace), QMAX(place, oldplace));
      emit colMoved(col, place);
}


// distance (in table coords) from left table edge of physical column
int HeadedTable::colOffset(int col)
{
      int x = 0;
      for(int c = 0; c < col; c++)
            x += max_widths[c];
      return x;
}

inline int HeadedTable::colXPos(int col)
{
      int x = 0;
      for(int c = 0; c < col; c++)
            x += max_widths[c];
      return x;
}



// repaint columns from col0 to col1. If col1 is -1, repaint all
// the way to the right edge of the table.
// called by 
//          1.void Qps::update_table(int col)
void HeadedTable::repaintColumns(int col0, int col1)
{
      QRect bvr = body->viewRect();
      QRect hvr = head->viewRect();
      int x0 = colOffset(col0) - body->xOffset();
      if(x0 > hvr.width())
            return;
      if(x0 < 0)
            x0 = 0;
      bvr.setLeft(x0);
      hvr.setLeft(x0);
      if(col1 >= 0) {
            int x1 = colOffset(col1) + max_widths[col1] - body->xOffset();
            if(x1 < hvr.width()) {
                  hvr.setRight(x1);
                  bvr.setRight(x1);
            }
      }
      head->repaint(hvr);
      body->repaint(bvr);
}

//DEL ? 
void HeadedTable::setTreeMode(bool tm)
{
      if(tm != treemode) {
            treemode = tm;
            if(ncols >= 1)
                  resetWidth(0);
      }
}


static void paint_triangle(QPixmap *pm, int c /* cell height */, bool closed)
{
      int s = c / 3;    
      pm->resize(s * 2 + 1, s * 2 + 1);
      pm->fill(Qt::white);
      QPointArray a(3);
      QPainter p(pm);
      p.setBrush(Qt::white);
      if(closed) {
            a[0] = QPoint(s - 2, 0);
            a[1] = QPoint(s * 2 - 2, s);
            a[2] = QPoint(s - 2, s * 2);
      } else {
            a[0] = QPoint(0, s - 2);
            a[1] = QPoint(s * 2, s - 2);
            a[2] = QPoint(s, s * 2 - 2);
      }
      p.drawPolygon(a);
      p.setPen(QColor(0x606060));
      if(closed) {
            p.drawLine(s * 2 - 2, s + 1, s - 1, s * 2);
      } else {
            p.drawLine(s * 2, s - 1, s + 1, s * 2 - 2);
      }
      pm->setMask(pm->createHeuristicMask());
}

void HeadedTable::make_gadgets()
{
      int c = body->cellheight;
      if(closed_pm==NULL)
      {
            closed_pm=new QPixmap();
            open_pm=new QPixmap();
      }
      paint_triangle(closed_pm, c, TRUE);
      paint_triangle(open_pm, c, FALSE);
}

void HeadedTable::enableFolding(bool enable)
{
      if(folding != enable) {
            folding = enable;
            int c = body->cellheight;
            gadget_space = folding ? c + (c >> 1) : 0;
            if(treemode) {
                  if(ncols >= 1)
                        resetWidth(0);
                  topAndRepaint();
            }
      }
}

void HeadedTable::enableLines(bool enable)
{
      if(lines != enable) {
            lines = enable;
            if(treemode) {
                  // repaint  column 0
                  QRect r = body->viewRect();
                  r.setLeft(body->xOffset());
                  r.setRight(max_widths[0] - body->xOffset());
                  //body->repaint(r);
                  body->update(r);
            }
      }
}


// set sorted  column
void HeadedTable::setSortedCol(int col)
{

      if(col != sorted_col) {
            int old_sorted = sorted_col;
            sorted_col = col;
//          printf("old_sorted=%d\n",old_sorted);
//          printf("sorted_col=%d\n",sorted_col);
            if(old_sorted != -1 && old_sorted < ncols)  // ncols bug
                  updateHeading(old_sorted);
            if(col != -1 && col < ncols)
                  updateHeading(col);
      }
}

void HeadedTable::setSelected(int row, bool sel, bool update)
{
      if(isSelected(row) != sel) {
            selected.setBit(row, sel);
            if(sel)
                  nselected++;
            else
                  nselected--;
            if(update) {
                  body->updateRow(row);
                  affected_rows.add(row);
            }
      }
}

void HeadedTable::selectionNotify()
{
      if(!affected_rows.size())
            return;
      emit selectionChanged(&affected_rows);
      affected_rows.clear();
}

void HeadedTable::clearAllSelections()
{
      for(int row = 0; row < nrows; row++)
            setSelected(row, FALSE);
}

void HeadedTable::selectOnly(int row)
{
      for(int r = 0; r < nrows; r++)
            setSelected(r, r == row);
}

void HeadedTable::selectAll()
{
      for(int r = 0; r < nrows; r++)
            setSelected(r, true);
      selectionNotify();
}


void HeadedTable::resizeEvent(QResizeEvent *)
{
      head->setGeometry(0, 0, width(), head->cellheight);
      int ybody = head->height();
      body->setGeometry(0, ybody, width(), height() - ybody);
}

void HeadedTable::keyPressEvent ( QKeyEvent * e )
{
      //if(e->key()==(Qt::CTRL +Qt::Key_A))
      if(e->key()==(Qt::Key_A))
      {
            //printf("A:dddzcvcxzvcxz\n");
            selectAll();
            selectionNotify();
            return;
      }

      QWidget::keyPressEvent ( e );
}

void HeadedTable::emit_click_signal(int col)
{
      emit titleClicked(col);
}

void HeadedTable::emit_double_click_signal(int row)
{
      emit doubleClicked(row);
}

void HeadedTable::emit_right_click_signal(QPoint where)
{
      emit rightClickedRow(where);
}

void HeadedTable::emit_right_click_heading_signal(QPoint where, int col)
{
      emit rightClickedHeading(where, col);
}

void HeadedTable::emit_fold(int row)
{
      emit foldSubTree(row);
}

// default implementation returns a null string (no tip displayed)
QString HeadedTable::tipText(int)
{
      return "";
}
char* HeadedTable::total_selectedRow(int col)
{
      return 0;
}


// Descrition :   draw the content of a cell of table 
//          This is called after cell background has been painted
//
// called by
//          1.void TableBody::paintCell(QPainter *p, int row, int col)
void HeadedTable::drawCellContents(int row, int col, int w, int h, QPainter *p)
{

      int gap=6;
      if(treemode==true && col == 0) {
            int d = rowDepth(row);  // virtual 
            int c = body->cellheight;
        
        if(lines) {
                  p->save();
                  p->setPen(0x888888); // less visually obtrusive than black
                  int dx = folding ? gadget_space : 6;
                  for(int i = d, prow = row; i > 0 && prow >= 0;i--, prow = parentRow(prow)) 
            {
                        int x = dx - c + i * treestep;
                        if(!lastChild(prow))
                              p->drawLine(x, 0, x, c - 1);        // |
                        else if(i == d)
                              p->drawLine(x, 0, x, c / 2);        // +
                  }
                  if(d > 0) {
                        int x = dx - c + d * treestep;
                        p->drawLine(x, c / 2, x + c / 2, c / 2);// -
                  }
                  p->restore();
            }

            if(folding) {
                  NodeState fs = folded(row);
                  if(fs != Leaf) {
                        QPixmap *pm = (fs == Closed) ? closed_pm : open_pm;
                        p->drawPixmap(c / 4 + d * treestep, (c - pm->height()) / 2, *pm);
                  }
            }
            gap =  gadget_space + d * treestep;
      } 
      
    QString s=text(row,col);
      int pos=s.find(">>!");
      if(pos>=0)
      {
                  
      }
      //p->setPen(color_text);

      if(alignment_col[col] == AlignRight)
            p->drawText(0, 0, w - 4, h, AlignVCenter | alignment_col[col],s);
      else 
            p->drawText(gap, 0, w , h, AlignVCenter | alignment_col[col],s);
      
}


// default implementation for treeless tables
int HeadedTable::rowDepth(int)
{
      return 0;
}

// default implementation for treeless tables
HeadedTable::NodeState HeadedTable::folded(int)
{
      return Leaf;
}

// default implementation for treeless tables
int HeadedTable::parentRow(int)
{
      return 0;
}

// default implementation for treeless tables
bool HeadedTable::lastChild(int)
{
      return FALSE;
}

// updates the table size of the table (size and presence of scrollbars)
void HeadedTable::updateTableSize()
{     
      //printf("updateTableSize\n");
      if(body->xOffset() > body->maxXOffset())
            body->setXOffset(body->maxXOffset());

      head->updateTableSize();
      body->updateTableSize();
      updateColWidths();
}

// move to top and repaint
void HeadedTable::topAndRepaint()
{
      body->setAutoUpdate(FALSE);
      body->setYOffset(0);
      body->setAutoUpdate(TRUE);

      repaintAll();
}

// compute width of text in body cell with current font
int HeadedTable::bodyTextWidth(const char *s)
{
      return body->fontMetrics().width(s);
}

// compute width of text in heading with current font
int HeadedTable::headTextWidth(const char *s)
{
      return head->fontMetrics().width(s) + 4;
}

// clear (i.e. repaint) table to the right of all columns, if visible
void HeadedTable::clearRight()
{
      QRect vrh = head->viewRect();
      int lastx = head->totalWidth() - head->xOffset();
      if(lastx < vrh.width()) {
            head->repaint(lastx + vrh.x(), vrh.y(),
                        vrh.width() - lastx, vrh.height());
            QRect vrb = body->viewRect();
            body->repaint(lastx + vrb.x(), vrb.y(),
                        vrb.width() - lastx, vrb.height());
      }
}

// clear the are below all rows, if visible
void HeadedTable::clearBelow()
{
      QRect vr = body->viewRect();
      vr.setTop(body->totalHeight());
      body->repaint(vr);
}

// find Max width of a column 
//
// called by 
//          1.  void HeadedTable::setNumCols(int cols)
int HeadedTable::updateColWidth(int col)
{
      QFontMetrics fontmetric=body->fontMetrics();
      QFontMetrics hfontmetric=head->fontMetrics();
      int w = 0;
      int sw= 0;
      int hw= 0;
      int i = 0;
      int r = numRows(); 
      bool treecol = treemode && col == 0;

      for(i = 0; i < r; i++) {
            sw = fontmetric.width(text(i,col))+10;
            if(treecol) sw += treestep * rowDepth(i);
            if(sw > w) w = sw;
      }
      if(treecol) 
            w += gadget_space;
      // don't forget the width of the heading
      hw = hfontmetric.width(title(col))+12;
      if(hw > w) w = hw;
      
      sw=fontmetric.width("0")*colWidth(col);
      if(sw>w) w=sw;

      max_widths[col] = w;
      return 0;
}

void HeadedTable::resetWidths()
{
      for(int i = 0; i < numCols()+1; i++)
            max_widths[i]=0;
}

// called by 
// dont use cached text
void HeadedTable::repaintAll()
{
      body->update();
      head->update(); 
}


// DRAFT CODE !!! DRAFT CODE !!!
// 1. paintEvent()
// 2. 
// tmp:: drawCellContents()
// updateColWidth(int col)
void HeadedTable::repaint_changed()
{
//    head->updateView();
//    body->updateView();
//    head->setXOffset(body->xOffset()); //  Temporary test(by fasthyun@magicn.com) 
//    return;
      // view_port range
      /* 
       *          +----------------------------+
       *          |                                          |
       *          |                                          |
       *          +----------------------------+
       */
      int rows = numRows();
      int cols = numCols();
      int left = leftCell(), right = lastColVisible();
      int top      = topCell(), bottom = lastRowVisible();
      
      if(right    >= cols) right = cols - 1; //???
      if(bottom   >= rows) bottom = rows - 1;
      // if width[col] be changed ,then the right of [col] should be repainted !
      // repaintColumns(c,-1);
      //printf("left=%d \n",left);

      for(int c = left ; c <= right; c++)
      {
        head->updateCell(0, c,false); 
            if(c>=ncols_prev) head->updateCell(0, c,true); 
      }

      for(int r = top; r <= bottom; r++) {
            for(int c = left; c <= right; c++) {
                  body->updateCell(r, c,false);
                  if(c>=ncols_prev)
                        body->updateCell(r, c,true); // forced rewrite
            }
            if( r>=nrows_prev  ) 
                  body->updateRow(r);
      }
      // clear left
      clearRight();
      clearBelow();

      head->setXOffset(body->xOffset()); //  Temporary test(by fasthyun@magicn.com) 
      return;
}



Generated by  Doxygen 1.6.0   Back to index