]> SALOME platform Git repositories - modules/gui.git/commitdiff
Salome HOME
Cell properties support
authorstv <stv@opencascade.com>
Wed, 11 Oct 2006 12:29:28 +0000 (12:29 +0000)
committerstv <stv@opencascade.com>
Wed, 11 Oct 2006 12:29:28 +0000 (12:29 +0000)
Cell foreground and background colors.
Rich text support in headers.
Multiheaders support
Horizontal span in headers.

src/Qtx/QtxTable.cxx
src/Qtx/QtxTable.h

index 657babab3b7c41b96ba96f436f5dfcdfdf3fbea9..d2c6ca8ecdfd487c2b487d2a96c8cf18f31f3ea0 100644 (file)
 
 #ifndef QT_NO_TABLE
 
+#include "QtxStyleWrap.h"
+
+#include <qstyle.h>
+#include <qtextedit.h>
 #include <qlineedit.h>
 #include <qmemarray.h>
+#include <qtoolbutton.h>
+#include <qstylesheet.h>
+#include <qapplication.h>
+#include <qsimplerichtext.h>
+
+/*!
+  Class QtxTable::StyleItem
+*/
+
+class QtxTable::StyleItem : public QtxStyleWrapItem
+{
+public:
+  StyleItem( QtxStyleWrap* );
+  ~StyleItem();
+
+  virtual bool drawControl( QStyle::ControlElement, QPainter*, const QWidget*, const QRect&,
+                            const QColorGroup&, QStyle::SFlags, const QStyleOption& ) const;
+};
+
+QtxTable::StyleItem::StyleItem( QtxStyleWrap* wrap )
+: QtxStyleWrapItem( wrap )
+{
+}
+
+QtxTable::StyleItem::~StyleItem()
+{
+}
+
+bool QtxTable::StyleItem::drawControl( QStyle::ControlElement element, QPainter* p, const QWidget* widget,
+                                       const QRect& r, const QColorGroup& cg, QStyle::SFlags flags,
+                                       const QStyleOption& opt ) const
+{
+  if ( element != QStyle::CE_HeaderLabel )
+    return false;
+
+       const QHeader* header = (const QHeader*)widget;
+       int section = opt.headerSection();
+
+  QString lab = header->label( section );
+  if ( !QStyleSheet::mightBeRichText( lab ) )
+    return false;
+
+  QRect rect = r;
+  QIconSet* icon = header->iconSet( section );
+  if ( icon )
+  {
+         QPixmap pixmap = icon->pixmap( QIconSet::Small, flags & QStyle::Style_Enabled ? QIconSet::Normal :
+                                                                                    QIconSet::Disabled );
+    int pixw = pixmap.width();
+               int pixh = pixmap.height();
+
+               QRect pixRect = rect;
+               pixRect.setY( rect.center().y() - (pixh - 1) / 2 );
+    if ( style() )
+                 style()->drawItem( p, pixRect, AlignVCenter, cg, flags & QStyle::Style_Enabled, &pixmap, QString::null );
+    rect.setLeft( rect.left() + pixw + 2 );
+  }
+
+  QStyleSheet sheet;
+  QStyleSheetItem* i = sheet.item( "p" );
+  if ( i )
+    i->setMargin( QStyleSheetItem::MarginAll, 0 );
+
+  QSimpleRichText rt( lab, header->font(), QString::null, &sheet );
+  rt.setWidth( rect.width() );
+  rt.draw( p, rect.x(), rect.y() + ( rect.height() - rt.height() ) / 2, rect, cg );
+
+  return true;
+}
+
+/*!
+  Class QtxTable::Header
+  Internal header for QtxTable
+*/
+
+class QtxTable::Header : public QHeader
+{
+public:
+  Header( int, QtxTable*, const char* = 0 );
+  virtual ~Header();
+
+  QtxTable*     table() const;
+
+  int           horizontalSpan( const int ) const;
+  void          setHorizontalSpan( const int, const int );
+
+  int           verticalSpan( const int ) const;
+  void          setVerticalSpan( const int, const int );
+
+  void          removeSection( const int );
+  virtual void  setLabel( int, const QString&, int = -1 );
+
+  QRect         indexRect( const int, int* = 0 );
+  void          swapSections( const int, const int );
+
+  virtual QSize sizeHint() const;
+
+protected:
+  virtual void  mouseMoveEvent( QMouseEvent* );
+  virtual void  mousePressEvent( QMouseEvent* );
+  virtual void  mouseReleaseEvent( QMouseEvent* );
+  virtual void  paintSection( QPainter*, int, const QRect& );
+
+private:
+  typedef QMap<int, int>        SpanMap;
+  typedef QPair<int, int>       SpanRange;
+  typedef QValueList<SpanRange> SpanRangeList;
+
+private:
+  QHeader*      mainHeader() const;
+  bool          filterEvent( QMouseEvent* ) const;
+
+  SpanRange     findSpanRange( const int ) const;
+  void          spanRanges( SpanRangeList& ) const;
+
+  QPoint        sectionCenter( const int, const QPoint& = QPoint() ) const;
+
+private:
+  SpanMap       myHSpan;
+  SpanMap       myVSpan;
+  QtxTable*     myTable;
+  int           myPressed;
+};
+
+QtxTable::Header::Header( int n, QtxTable* table, const char* name )
+: QHeader( n, table, name ),
+myTable( table ),
+myPressed( -1 )
+{
+}
+
+QtxTable::Header::~Header()
+{
+}
+
+QtxTable* QtxTable::Header::table() const
+{
+  return myTable;
+}
+
+QSize QtxTable::Header::sizeHint() const
+{
+  QSize sz = QHeader::sizeHint();
+
+  int size = orientation() == Horizontal ? sz.height() : sz.width();
+
+  for ( int i = 0; i < (int)count(); i++ )
+  {
+    QString lab = label( mapToSection( i ) );
+    if ( !QStyleSheet::mightBeRichText( lab ) )
+      continue;
+
+    int s = 0;
+    QIconSet* icon = iconSet( mapToSection( i ) );
+    if ( icon )
+    {
+           QPixmap pixmap = icon->pixmap( QIconSet::Small, QIconSet::Normal );
+      s = orientation() == Horizontal ? pixmap.height() : pixmap.width();
+    }
+
+    QStyleSheet sheet;
+    QStyleSheetItem* item = sheet.item( "p" );
+    if ( item )
+      item->setMargin( QStyleSheetItem::MarginAll, 0 );
+
+    QSimpleRichText rt( lab, font(), QString::null, &sheet );
+    if ( orientation() == Horizontal )
+      rt.setWidth( sectionSize( mapToSection( i ) ) );
+    s += orientation() == Horizontal ? rt.height() : rt.width();
+    size = QMAX( size, s );
+  }
+
+  if ( orientation() == Horizontal )
+    sz.setHeight( size );
+  else
+    sz.setWidth( size );
+
+  return sz;
+}
+
+void QtxTable::Header::removeSection( const int section )
+{
+  int old = count();
+
+  removeLabel( section );
+
+  if ( old == count() )
+    return;
+
+  SpanMap newHMap, newVMap;
+  for ( SpanMap::ConstIterator hIt = myHSpan.begin(); hIt != myHSpan.end(); ++hIt )
+  {
+    if ( hIt.key() == section )
+      continue;
+    newHMap.insert( hIt.key() < section ? hIt.key() : hIt.key() - 1, hIt.data() );
+  }
+  myHSpan = newHMap;
+
+  for ( SpanMap::ConstIterator vIt = myVSpan.begin(); vIt != myVSpan.end(); ++vIt )
+  {
+    if ( vIt.key() == section )
+      continue;
+    newVMap.insert( vIt.key() < section ? vIt.key() : vIt.key() - 1, vIt.data() );
+  }
+  myVSpan = newVMap;
+}
+
+void QtxTable::Header::setLabel( int section, const QString& s, int size )
+{
+  QHeader::setLabel( section, s, size );
+  if ( table() && isUpdatesEnabled() )
+    table()->updateHeaderGeometries( orientation() );
+}
+
+int QtxTable::Header::horizontalSpan( const int section ) const
+{
+  return myHSpan.contains( section ) ? myHSpan[section] : 1;
+}
+
+void QtxTable::Header::setHorizontalSpan( const int section, const int sp )
+{
+  if ( horizontalSpan( section ) == sp )
+    return;
+
+  myHSpan.insert( section, sp );
+  repaint( indexRect( mapToIndex( section ) ) );
+}
+
+int QtxTable::Header::verticalSpan( const int section ) const
+{
+  return myVSpan.contains( section ) ? myVSpan[section] : 1;
+}
+
+void QtxTable::Header::setVerticalSpan( const int section, const int sp )
+{
+  if ( verticalSpan( section ) == sp )
+    return;
+
+  myVSpan.insert( section, sp );
+  repaint( indexRect( mapToIndex( section ) ) );
+}
+
+void QtxTable::Header::swapSections( const int oldIdx, const int newIdx )
+{
+  QIconSet oldIconSet, newIconSet;
+  if ( iconSet( oldIdx ) )
+         oldIconSet = *iconSet( oldIdx );
+  if ( iconSet( newIdx ) )
+         newIconSet = *iconSet( newIdx );
+  QString oldLabel = label( oldIdx );
+  QString newLabel = label( newIdx );
+  QHeader::setLabel( oldIdx, newIconSet, newLabel );
+  QHeader::setLabel( newIdx, oldIconSet, oldLabel );
+
+  int oldHSpan = horizontalSpan( oldIdx );
+  int newHSpan = horizontalSpan( newIdx );
+  setHorizontalSpan( oldIdx, newHSpan );
+  setHorizontalSpan( newIdx, oldHSpan );
+
+  int oldVSpan = verticalSpan( oldIdx );
+  int newVSpan = verticalSpan( newIdx );
+  setVerticalSpan( oldIdx, newVSpan );
+  setVerticalSpan( newIdx, oldVSpan );
+}
+
+void QtxTable::Header::mouseMoveEvent( QMouseEvent* e )
+{
+  if ( e->button() == NoButton && filterEvent( e ) )
+    return;
+
+  QHeader::mouseMoveEvent( e );
+  if ( mainHeader() )
+    QApplication::sendEvent( mainHeader(), e );
+}
+
+void QtxTable::Header::mousePressEvent( QMouseEvent* e )
+{
+  if ( filterEvent( e ) )
+    return;
+
+  int index = mapToIndex( sectionAt( ( orientation() == Horizontal ? e->pos().x() : e->pos().y() ) + offset() ) );
+  SpanRange range = findSpanRange( index );
+
+  bool shift = e->state() & ShiftButton;
+  if ( mainHeader() )
+    QApplication::sendEvent( mainHeader(), e );
+
+  for ( int i = range.second; i >= range.first && !shift; i-- )
+  {
+    QPoint pos = sectionCenter( i, e->pos() );
+    QMouseEvent me( e->type(), pos, e->button(), e->state() | ControlButton );
+    if ( i == range.first )
+      QHeader::mousePressEvent( &me );
+    if ( mainHeader() )
+      QApplication::sendEvent( mainHeader(), &me );
+  }
+
+  if ( !shift )
+  {
+    QMouseEvent me( e->type(), sectionCenter( index, e->pos() ), e->button(), e->state() | ControlButton );
+    if ( mainHeader() )
+      QApplication::sendEvent( mainHeader(), &me );
+  }
+
+  myPressed = range.first;
+  repaint( indexRect( range.first ) );
+}
+
+void QtxTable::Header::mouseReleaseEvent( QMouseEvent* e )
+{
+  QHeader::mouseReleaseEvent( e );
+  if ( mainHeader() )
+    QApplication::sendEvent( mainHeader(), e );
+
+  repaint( indexRect( myPressed ) );
+  myPressed = -1;
+}
+
+void QtxTable::Header::paintSection( QPainter* p, int index, const QRect& fr )
+{
+  int idx = index;
+  QRect r = fr;
+  if ( index < count() )
+    r = indexRect( index, &idx );
+  QHeader::paintSection( p, idx, r );
+}
+
+bool QtxTable::Header::filterEvent( QMouseEvent* e ) const
+{
+  int c = orientation() == Horizontal ? e->pos().x() : e->pos().y();
+  c += offset();
+/*
+  if ( reverse() )
+         c = d->lastPos - c;
+*/
+  int section = sectionAt( c );
+  if ( section < 0 )
+    return false;
+
+  int handleIdx = -1;
+  int margin = style().pixelMetric( QStyle::PM_HeaderGripMargin );
+  int index = mapToIndex( section );
+
+  QRect r = sectionRect( section );
+  int size = sectionSize( section );
+  int pos = ( orientation() == Horizontal ? r.x() : r.y() ) + offset();
+  if ( c < pos + margin )
+         handleIdx = index - 1;
+  else if ( c > pos + size - margin )
+         handleIdx = index;
+
+  if ( handleIdx == -1 )
+    return false;
+
+  bool ok = false;
+  SpanRangeList ranges;
+  spanRanges( ranges );
+  for ( SpanRangeList::const_iterator it = ranges.begin(); it != ranges.end() && !ok; ++it )
+    ok = (*it).second == handleIdx;
+
+  return !ok;
+}
+
+QPoint QtxTable::Header::sectionCenter( const int index, const QPoint& p ) const
+{
+  QPoint pos = p;
+  if ( orientation() == Horizontal )
+    pos.setX( sectionPos( mapToSection( index ) ) + sectionSize( mapToSection( index ) ) / 2 - offset() );
+  else
+    pos.setY( sectionPos( mapToSection( index ) ) + sectionSize( mapToSection( index ) ) / 2 - offset() );
+
+  if ( p.isNull() )
+  {
+    if ( orientation() == Horizontal )
+      pos.setY( height() / 2 );
+    else
+      pos.setX( width() / 2 );
+  }
+  return pos;
+}
+
+void QtxTable::Header::spanRanges( SpanRangeList& lst ) const
+{
+  lst.clear();
+  for ( int i = 0; i < (int)count(); i++ )
+  {
+    int sp = horizontalSpan( mapToSection( i ) );
+    SpanRange range( i, QMIN( i + sp - 1, count() - 1 ) );
+    lst.append( range );
+    i += sp - 1;
+  }
+}
+
+QtxTable::Header::SpanRange QtxTable::Header::findSpanRange( const int index ) const
+{
+  SpanRangeList ranges;
+  spanRanges( ranges );
+
+  SpanRange res( -1, -1 );
+  for ( SpanRangeList::const_iterator it = ranges.begin(); it != ranges.end() && res.first < 0; ++it )
+  {
+    if ( (*it).first <= index && index <= (*it).second )
+      res = *it;
+  }
+  return res;
+}
+
+QRect QtxTable::Header::indexRect( const int index, int* start )
+{
+  SpanRange range = findSpanRange( index );
+
+  if ( start )
+    *start = range.first;
+
+  QRect r;
+  for ( int i = range.first; i <= range.second; i++ )
+    r = r.unite( sRect( i ) );
+  return r;
+}
+
+QHeader* QtxTable::Header::mainHeader() const
+{
+  if ( !table() )
+    return 0;
+
+  return orientation() == Horizontal ? table()->horizontalHeader() :
+                                       table()->verticalHeader();
+}
+
+/*!
+  Class QtxTable
+*/
 
 /*!
   Constructor
 */
 QtxTable::QtxTable( QWidget* parent, const char* name )
 : QTable( parent, name ),
+myStyleWrapper( 0 ),
 myHeaderEditor( 0 ),
 myEditedHeader( 0 ),
-myEditedSection( -1 )
+myEditedSection( -1 ),
+mySelectAll( 0 )
 {
+  myVerHeaders.setAutoDelete( true );
+  myHorHeaders.setAutoDelete( true );
+
+  verticalHeader()->setStyle( styleWrapper() );
+  horizontalHeader()->setStyle( styleWrapper() );
+
   connect( verticalHeader(), SIGNAL( sizeChange( int, int, int ) ),
            this, SLOT( onHeaderSizeChange( int, int, int ) ) );
   connect( horizontalHeader(), SIGNAL( sizeChange( int, int, int ) ),
            this, SLOT( onHeaderSizeChange( int, int, int ) ) );
   connect( verticalScrollBar(), SIGNAL( valueChanged( int ) ), this, SLOT( onScrollBarMoved( int ) ) );
   connect( horizontalScrollBar(), SIGNAL( valueChanged( int ) ), this, SLOT( onScrollBarMoved( int ) ) );
+
+  updateHeaders( Horizontal );
+  updateHeaders( Vertical );
 }
 
 /*!
@@ -48,10 +496,18 @@ myEditedSection( -1 )
 */
 QtxTable::QtxTable( int numRows, int numCols, QWidget* parent, const char* name )
 : QTable( numRows, numCols, parent, name ),
+myStyleWrapper( 0 ),
 myHeaderEditor( 0 ),
 myEditedHeader( 0 ),
-myEditedSection( -1 )
+myEditedSection( -1 ),
+mySelectAll( 0 )
 {
+  myVerHeaders.setAutoDelete( true );
+  myHorHeaders.setAutoDelete( true );
+
+  verticalHeader()->setStyle( styleWrapper() );
+  horizontalHeader()->setStyle( styleWrapper() );
+
   connect( verticalHeader(), SIGNAL( sizeChange( int, int, int ) ),
            this, SLOT( onHeaderSizeChange( int, int, int ) ) );
   connect( horizontalHeader(), SIGNAL( sizeChange( int, int, int ) ),
@@ -65,6 +521,65 @@ myEditedSection( -1 )
 */
 QtxTable::~QtxTable()
 {
+  delete myStyleWrapper;
+}
+
+bool QtxTable::isSelectAllEnabled() const
+{
+  return mySelectAll;
+}
+
+void QtxTable::setSelectAllEnabled( const bool on )
+{
+  if ( isSelectAllEnabled() == on )
+    return;
+
+  if ( on )
+    connect( mySelectAll = new QToolButton( this ), SIGNAL( clicked() ), this, SLOT( selectAll() ) );
+  else
+  {
+    delete mySelectAll;
+    mySelectAll = 0;
+  }
+  updateSelectAllButton();
+}
+
+/*!
+  Select the all cells of the table.
+*/
+void QtxTable::selectAll()
+{
+  if ( selectionMode() != Multi && selectionMode() != MultiRow )
+    return;
+
+  selectCells( 0, 0, numRows() - 1, numCols() - 1 );
+}
+
+/*!
+  Reimplemented for 'SelectAll' button geometry updating.
+*/
+void QtxTable::setTopMargin( int m )
+{
+  QTable::setTopMargin( m );
+  updateSelectAllButton();
+}
+
+/*!
+  Reimplemented for 'SelectAll' button geometry updating.
+*/
+void QtxTable::setLeftMargin( int m )
+{
+  QTable::setLeftMargin( m );
+  updateSelectAllButton();
+}
+
+/*!
+  Reimplemented for 'SelectAll' button updating.
+*/
+void QtxTable::setSelectionMode( SelectionMode mode )
+{
+  QTable::setSelectionMode( mode );
+  updateSelectAllButton();
 }
 
 /*!
@@ -128,14 +643,10 @@ bool QtxTable::eventFilter( QObject* o, QEvent* e )
   if ( e->type() == QEvent::MouseButtonDblClick )
   {
     QMouseEvent* me = (QMouseEvent*)e;
-    if ( o == horizontalHeader() )
-    {
-      beginHeaderEdit( Horizontal, me->pos() );
-      return true;
-    }
-    else if ( o == verticalHeader() )
+    QHeader* hdr = ::qt_cast<QHeader*>( o );
+    if ( hdr )
     {
-      beginHeaderEdit( Vertical, me->pos() );
+      beginHeaderEdit( hdr, me->pos() );
       return true;
     }
   }
@@ -149,7 +660,7 @@ bool QtxTable::eventFilter( QObject* o, QEvent* e )
       return true;
     }
 
-    if ( ke->key() == Key_Return || ke->key() == Key_Enter )
+    if ( ke->state() == NoButton && ( ke->key() == Key_Return || ke->key() == Key_Enter ) )
     {
       endHeaderEdit( true );
       return true;
@@ -178,7 +689,21 @@ bool QtxTable::eventFilter( QObject* o, QEvent* e )
 void QtxTable::setNumRows( int rows )
 {
   endHeaderEdit();
+  int old = numRows();
+
   QTable::setNumRows( rows );
+
+  for ( uint i = 0; i < myVerHeaders.count(); i++ )
+  {
+    Header* hdr = (Header*)myVerHeaders.at( i );
+    for ( int d = hdr->count() - 1; d >= (int)numRows(); d-- )
+      hdr->removeSection( d );
+    for ( int c = hdr->count(); c < (int)numRows(); c++ )
+      hdr->addLabel( QString::null );
+  }
+
+  for ( int j = rows + 1; j <= old; j++ )
+      myCellProps.remove( j );
 }
 
 /*!
@@ -188,7 +713,25 @@ void QtxTable::setNumRows( int rows )
 void QtxTable::setNumCols( int cols )
 {
   endHeaderEdit();
+  int old = numCols();
+
   QTable::setNumCols( cols );
+
+  for ( uint i = 0; i < myHorHeaders.count(); i++ )
+  {
+    Header* hdr = (Header*)myHorHeaders.at( i );
+    for ( int d = hdr->count() - 1; d >= (int)numCols(); d-- )
+      hdr->removeSection( d );
+    for ( int c = hdr->count(); c < (int)numCols(); c++ )
+      hdr->addLabel( QString::null );
+  }
+
+  for ( CellMap::Iterator it = myCellProps.begin(); it != myCellProps.end(); ++it )
+  {
+    PropsMap& map = it.data();
+    for ( int i = cols + 1; i <= old; i++ )
+      map.remove( i );
+  }
 }
 
 /*!
@@ -198,7 +741,23 @@ void QtxTable::setNumCols( int cols )
 void QtxTable::insertRows( int row, int count )
 {
   endHeaderEdit();
+
   QTable::insertRows( row, count );
+
+  for ( uint i = 0; i < myVerHeaders.count(); i++ )
+  {
+    Header* hdr = (Header*)myVerHeaders.at( i );
+    for ( int j = numRows() - count - 1; j >= row; --j )
+           hdr->swapSections( j, j + count );
+  }
+
+  CellMap tmp = myCellProps;
+  myCellProps.clear();
+  for ( CellMap::Iterator it = tmp.begin(); it != tmp.end(); ++it )
+  {
+    int r = it.key() < row ? it.key() : it.key() + count;
+    myCellProps.insert( r, it.data() );
+  }
 }
 
 /*!
@@ -208,7 +767,26 @@ void QtxTable::insertRows( int row, int count )
 void QtxTable::insertColumns( int col, int count )
 {
   endHeaderEdit();
+
   QTable::insertColumns( col, count );
+
+  for ( uint i = 0; i < myHorHeaders.count(); i++ )
+  {
+    Header* hdr = (Header*)myHorHeaders.at( i );
+    for ( int j = numCols() - count - 1; j >= col; --j )
+           hdr->swapSections( j, j + count );
+  }
+
+  for ( CellMap::Iterator itr = myCellProps.begin(); itr != myCellProps.end(); ++itr )
+  {
+    PropsMap tmp = itr.data();
+    itr.data().clear();
+    for ( PropsMap::Iterator it = tmp.begin(); it != tmp.end(); ++it )
+    {
+      int c = it.key() < col ? it.key() : it.key() + count;
+      itr.data().insert( c, it.data() );
+    }
+  }
 }
 
 /*!
@@ -218,7 +796,25 @@ void QtxTable::insertColumns( int col, int count )
 void QtxTable::removeRow( int row )
 {
   endHeaderEdit();
+
   QTable::removeRow( row );
+
+  for ( uint i = 0; i < myVerHeaders.count(); i++ )
+  {
+    Header* hdr = (Header*)myVerHeaders.at( i );
+    hdr->removeSection( row );
+  }
+
+  CellMap tmp = myCellProps;
+  myCellProps.clear();
+  for ( CellMap::Iterator it = tmp.begin(); it != tmp.end(); ++it )
+  {
+    if ( it.key() == row )
+      continue;
+
+    int r = it.key() < row ? it.key() : it.key() - 1;
+    myCellProps.insert( r, it.data() );
+  }
 }
 
 /*!
@@ -228,7 +824,33 @@ void QtxTable::removeRow( int row )
 void QtxTable::removeRows( const QMemArray<int>& rows )
 {
   endHeaderEdit();
+
+  int decr = 0;
+  QMap<int, int> indexes;
+  for ( int r = 0; r < numRows(); r++ )
+  {
+    if ( rows.contains( r ) )
+      decr++;
+    else
+      indexes.insert( r, r - decr );
+  }
+
   QTable::removeRows( rows );
+
+  for ( uint i = 0; i < myVerHeaders.count(); i++ )
+  {
+    Header* hdr = (Header*)myVerHeaders.at( i );
+    for ( int d = rows.count() - 1; d >= 0; d-- )
+      hdr->removeSection( rows[d] );
+  }
+
+  CellMap tmp = myCellProps;
+  myCellProps.clear();
+  for ( CellMap::Iterator it = tmp.begin(); it != tmp.end(); ++it )
+  {
+    if ( indexes.contains( it.key() ) )
+      myCellProps.insert( indexes[it.key()], it.data() );
+  }
 }
 
 /*!
@@ -238,7 +860,28 @@ void QtxTable::removeRows( const QMemArray<int>& rows )
 void QtxTable::removeColumn( int col )
 {
   endHeaderEdit();
+
   QTable::removeColumn( col );
+
+  for ( uint i = 0; i < myHorHeaders.count(); i++ )
+  {
+    Header* hdr = (Header*)myHorHeaders.at( i );
+    hdr->removeSection( col );
+  }
+
+  for ( CellMap::Iterator itr = myCellProps.begin(); itr != myCellProps.end(); ++itr )
+  {
+    PropsMap tmp = itr.data();
+    itr.data().clear();
+    for ( PropsMap::Iterator it = tmp.begin(); it != tmp.end(); ++it )
+    {
+      if ( it.key() == col )
+        continue;
+
+      int c = it.key() < col ? it.key() : it.key() - 1;
+      itr.data().insert( c, it.data() );
+    }
+  }
 }
 
 /*!
@@ -248,7 +891,137 @@ void QtxTable::removeColumn( int col )
 void QtxTable::removeColumns( const QMemArray<int>& cols )
 {
   endHeaderEdit();
+
+  int decr = 0;
+  QMap<int, int> indexes;
+  for ( int c = 0; c < numCols(); c++ )
+  {
+    if ( cols.contains( c ) )
+      decr++;
+    else
+      indexes.insert( c, c - decr );
+  }
+
   QTable::removeColumns( cols );
+
+  for ( uint i = 0; i < myHorHeaders.count(); i++ )
+  {
+    Header* hdr = (Header*)myHorHeaders.at( i );
+    for ( int d = cols.count() - 1; d >= 0; d-- )
+      hdr->removeSection( cols[d] );
+  }
+
+  for ( CellMap::Iterator itr = myCellProps.begin(); itr != myCellProps.end(); ++itr )
+  {
+    PropsMap tmp = itr.data();
+    itr.data().clear();
+    for ( PropsMap::Iterator it = tmp.begin(); it != tmp.end(); ++it )
+    {
+      if ( indexes.contains( it.key() ) )
+        itr.data().insert( indexes[it.key()], it.data() );
+    }
+  }
+}
+
+QHeader* QtxTable::header( const Orientation o, const int idx ) const
+{
+  HeaderVector* vec = headerVector( o );
+
+  if ( idx < 0 || idx >= (int)vec->count() )
+    return 0;
+
+  return vec->at( idx );
+}
+
+int QtxTable::numHeaders( const Orientation o ) const
+{
+  return headerVector( o )->count();
+}
+
+void QtxTable::setNumHeaders( const Orientation o, const int n )
+{
+  headerVector( o )->resize( QMAX( n, 0 ) );
+
+  updateHeaders( o );
+  updateHeaderSizes( o );
+  updateHeaderSpace( o );
+
+  updateGeometries();
+}
+
+int QtxTable::verticalSpan( const Orientation o, const int idx, const int section ) const
+{
+  Header* hdr = (Header*)header( o, idx );
+  if ( !hdr )
+    return -1;
+
+  return hdr->verticalSpan( section );
+}
+
+int QtxTable::horizontalSpan( const Orientation o, const int idx, const int section ) const
+{
+  Header* hdr = (Header*)header( o, idx );
+  if ( !hdr )
+    return -1;
+
+  return hdr->horizontalSpan( section );
+}
+
+void QtxTable::setVerticalSpan( const Orientation o, const int idx, const int section, const int span )
+{
+  Header* hdr = (Header*)header( o, idx );
+  if ( hdr )
+    hdr->setVerticalSpan( section, span );
+}
+
+void QtxTable::setHorizontalSpan( const Orientation o, const int idx, const int section, const int span )
+{
+  Header* hdr = (Header*)header( o, idx );
+  if ( hdr )
+    hdr->setHorizontalSpan( section, span );
+}
+
+QColor QtxTable::cellForegroundColor( const int row, const int col ) const
+{
+  QColor res;
+  QVariant val = cellProperty( row, col, FgColor );
+  if ( val.canCast( QVariant::Color ) )
+    res = val.toColor();
+  return res;
+}
+
+QColor QtxTable::cellBackgroundColor( const int row, const int col ) const
+{
+  QColor res;
+  QVariant val = cellProperty( row, col, BgColor );
+  if ( val.canCast( QVariant::Color ) )
+    res = val.toColor();
+  return res;
+}
+
+void QtxTable::setCellForegroundColor( const int row, const int col, const QColor& c )
+{
+  setCellProperty( row, col, FgColor, c );
+}
+
+void QtxTable::setCellBackgroundColor( const int row, const int col, const QColor& c )
+{
+  setCellProperty( row, col, BgColor, c );
+}
+
+void QtxTable::paintCell( QPainter* p, int row, int col, const QRect& cr,
+                          bool selected, const QColorGroup& cg )
+{
+  QColor fg = cellForegroundColor( row, col );
+  QColor bg = cellBackgroundColor( row, col );
+
+  QColorGroup cGroup = cg;
+  if ( fg.isValid() )
+    cGroup.setColor( QColorGroup::Text, fg );
+  if ( bg.isValid() )
+    cGroup.setColor( QColorGroup::Base, bg );
+
+  QTable::paintCell( p, row, col, cr, selected, cGroup );
 }
 
 /*!
@@ -262,9 +1035,20 @@ void QtxTable::onScrollBarMoved( int )
 /*!
   SLOT: called on header size changing
 */
-void QtxTable::onHeaderSizeChange( int, int, int )
+void QtxTable::onHeaderSizeChange( int section, int oldSize, int newSize )
 {
-  if ( sender() == myEditedHeader )
+  const QHeader* header = ::qt_cast<const QHeader*>( sender() );
+  if ( !header )
+    return;
+
+  HeaderVector* vec = headerVector( header->orientation() );
+  for ( int i = 0; i < (int)vec->size(); i++ )
+  {
+    QHeader* hdr = vec->at( i );
+    hdr->resizeSection( section, newSize );
+  }
+
+  if ( header == myEditedHeader )
     updateHeaderEditor();
 }
 
@@ -286,6 +1070,54 @@ void QtxTable::resizeEvent( QResizeEvent* e )
   QTable::resizeEvent( e );
 
   updateHeaderEditor();
+
+  updateGeometries();
+}
+
+/*!
+  Returns the specified property of the cell.
+  \param row - row number of cell
+  \param col - column number of cell
+  \param name - property name
+*/
+QVariant QtxTable::cellProperty( const int row, const int col, const int name ) const
+{
+  QVariant res;
+
+  if ( myCellProps.contains( row ) )
+  {
+    const PropsMap& map = myCellProps[row];
+    if ( map.contains( col ) )
+    {
+      const Properties& props = map[col];
+      if ( props.contains( name ) )
+        res = props[name];
+    }
+  }
+  return res;
+}
+
+/*!
+  Sets the specified property value of the cell.
+  \param row - row number of cell
+  \param col - column number of cell
+  \param name - property name
+  \param val - setted property value
+*/
+void QtxTable::setCellProperty( const int row, const int col, const int name, const QVariant& val )
+{
+  if ( row < 0 || row >= numRows() || col < 0 || col >= numCols() )
+    return;
+
+  if ( !myCellProps.contains( row ) )
+    myCellProps.insert( row, PropsMap() );
+
+  PropsMap& map = myCellProps[row];
+  if ( !map.contains( col ) )
+    map.insert( col, Properties() );
+
+  Properties& props = map[col];
+  props.insert( name, val );
 }
 
 /*!
@@ -293,20 +1125,30 @@ void QtxTable::resizeEvent( QResizeEvent* e )
   \param o - header orientation
   \param sec - column/row
 */
-bool QtxTable::beginHeaderEdit( Orientation o, const int section )
+bool QtxTable::beginHeaderEdit( Orientation o, const int section, const int idx )
 {
-  if ( !headerEditable( o ) || !header( o ) || !header( o )->isVisibleTo( this ) )
+  QHeader* hdr = 0;
+  if ( idx < 0 )
+    hdr = header( o );
+  if ( !hdr->isVisibleTo( this ) )
+    hdr = header( o, idx );
+
+  return beginHeaderEdit( hdr, section );
+}
+
+bool QtxTable::beginHeaderEdit( QHeader* hdr, const int s )
+{
+  if ( !hdr || !headerEditable( hdr->orientation() ) || !hdr->isVisibleTo( this ) )
     return false;
 
   endHeaderEdit();
 
-  QHeader* hdr = header( o );
-
-  QRect r = headerSectionRect( hdr, section );
+  int section = s;
+  QRect r = headerSectionRect( hdr, s, &section );
   if ( !r.isValid() )
     return false;
 
-  if ( o == Horizontal )
+  if ( hdr->orientation() == Horizontal )
     r.setLeft( QMAX( r.left(), leftMargin() ) );
   else
     r.setTop( QMAX( r.top(), topMargin() ) );
@@ -382,12 +1224,31 @@ bool QtxTable::isHeaderEditing() const
 */
 QWidget* QtxTable::createHeaderEditor( QHeader* hdr, const int sec, const bool init )
 {
-  QLineEdit* ed = new QLineEdit( 0 );
+  QString lab = hdr ? hdr->label( sec ) : QString::null;
 
-  if ( init && hdr )
-    ed->setText( hdr->label( sec ) );
+  QWidget* wid = 0;
+  if ( !QStyleSheet::mightBeRichText( lab ) && !lab.contains( "\n" ) )
+  {
+    QLineEdit* le = new QLineEdit( 0 );
+    if ( init )
+      le->setText( lab );
+    wid = le;
+  }
+  else
+  {
+    QTextEdit* te = new QTextEdit( 0 );
+    QStyleSheet* sheet = new QStyleSheet( te );
+    QStyleSheetItem* i = sheet->item( "p" );
+    if ( i )
+      i->setMargin( QStyleSheetItem::MarginAll, 0 );
+    te->setStyleSheet( sheet );
+
+    if ( init )
+      te->setText( lab );
+    wid = te;
+  }
 
-  return ed;
+  return wid;
 }
 
 /*!
@@ -401,8 +1262,15 @@ void QtxTable::setHeaderContentFromEditor( QHeader* hdr, const int sec, QWidget*
   if ( !hdr || !editor )
     return;
 
-  if ( editor->inherits( "QLineEdit" ) )
-    hdr->setLabel( sec, ((QLineEdit*)editor)->text() );
+  QLineEdit* le = ::qt_cast<QLineEdit*>( editor );
+  if ( le )
+    hdr->setLabel( sec, le->text() );
+  else
+  {
+    QTextEdit* te = ::qt_cast<QTextEdit*>( editor );
+    if ( te )
+      hdr->setLabel( sec, te->text() );
+  }
 }
 
 /*!
@@ -419,16 +1287,15 @@ QHeader* QtxTable::header( Orientation o ) const
   \param o - header orientation
   \param p - point
 */
-void QtxTable::beginHeaderEdit( Orientation o, const QPoint& p )
+void QtxTable::beginHeaderEdit( QHeader* hdr, const QPoint& p )
 {
-  QHeader* hdr = header( o );
   if ( !hdr )
     return;
 
-  int pos = o == Horizontal ? p.x() : p.y();
+  int pos = hdr->orientation() == Horizontal ? p.x() : p.y();
   int sec = hdr->sectionAt( hdr->offset() + pos );
 
-  beginHeaderEdit( o, sec );
+  beginHeaderEdit( hdr, sec );
 }
 
 /*!
@@ -436,7 +1303,7 @@ void QtxTable::beginHeaderEdit( Orientation o, const QPoint& p )
   \param hdr - header
   \param sec - column/row
 */
-QRect QtxTable::headerSectionRect( QHeader* hdr, const int sec ) const
+QRect QtxTable::headerSectionRect( QHeader* hdr, const int sec, int* main ) const
 {
   QRect r( -1, -1, -1, -1 );
 
@@ -444,6 +1311,9 @@ QRect QtxTable::headerSectionRect( QHeader* hdr, const int sec ) const
     return r;
 
   r = hdr->sectionRect( sec );
+  if ( hdr != verticalHeader() && hdr != horizontalHeader() )
+    r = ((Header*)hdr)->indexRect( hdr->mapToIndex( sec ), main );
+
   if ( r.isValid() )
     r = QRect( mapFromGlobal( hdr->mapToGlobal( r.topLeft() ) ), r.size() );
 
@@ -462,7 +1332,7 @@ void QtxTable::updateHeaderEditor()
   if ( !r.isValid() )
     return;
 
-  if ( myEditedHeader == horizontalHeader() )
+  if ( myEditedHeader->orientation() == Horizontal )
   {
     r.setLeft( QMAX( r.left(), leftMargin() ) );
     r.setRight( QMIN( r.right(), width() - rightMargin() - 2 ) );
@@ -508,9 +1378,149 @@ void QtxTable::removeSelected( const bool row )
     idsArr[ i ] = *it;
 
   if ( row )
-    removeRows ( idsArr );
+    removeRows( idsArr );
   else
-    removeColumns ( idsArr );
+    removeColumns( idsArr );
+}
+
+QtxTable::HeaderVector* QtxTable::headerVector( const Orientation o ) const
+{
+  return o == Horizontal ? (HeaderVector*)&myHorHeaders : (HeaderVector*)&myVerHeaders;
+}
+
+QtxStyleWrap* QtxTable::styleWrapper()
+{
+  if ( !myStyleWrapper )
+  {
+    myStyleWrapper = new QtxStyleWrap( &style() );
+    new StyleItem( myStyleWrapper );
+  }
+  return myStyleWrapper;
+}
+
+void QtxTable::updateHeaders( const Orientation o )
+{
+  HeaderVector& vec = o == Vertical ? myVerHeaders : myHorHeaders;
+  QScrollBar* sb = o == Vertical ? verticalScrollBar() : horizontalScrollBar();
+  QHeader* main = o == Vertical ? verticalHeader() : horizontalHeader();
+
+  main->setShown( !vec.size() );
+
+  for ( uint i = 0; i < vec.size(); i++ )
+  {
+    if ( vec.at( i ) )
+      continue;
+
+    QHeader* hdr = new Header( o == Horizontal ? numCols() : numRows(), this );
+    vec.insert( i, hdr );
+    hdr->setStyle( styleWrapper() );
+    hdr->setMovingEnabled( false );
+    hdr->setOrientation( o );
+    hdr->installEventFilter( this );
+    hdr->show();
+
+    connect( sb, SIGNAL( valueChanged( int ) ), hdr, SLOT( setOffset( int ) ) );
+  }
+
+  if ( o == Horizontal )
+  {
+    for ( uint j = 0; j < vec.size(); j++ )
+    {
+      QHeader* hdr = vec.at( j );
+      bool upd = hdr->isUpdatesEnabled();
+      hdr->setUpdatesEnabled( false );
+      for ( int s = 0; s < (int)hdr->count(); s++ )
+        hdr->setLabel( s, QString( "" ) );
+      hdr->setUpdatesEnabled( upd );
+    }
+  }
+
+  // slot onScrollBarMoved should be last connection.
+  // QHeader::setOffset() should be invoked before it for every header.
+  // Otherwise header editor geometry will not properly updated.
+  disconnect( verticalScrollBar(), SIGNAL( valueChanged( int ) ), this, SLOT( onScrollBarMoved( int ) ) );
+  disconnect( horizontalScrollBar(), SIGNAL( valueChanged( int ) ), this, SLOT( onScrollBarMoved( int ) ) );
+  connect( verticalScrollBar(), SIGNAL( valueChanged( int ) ), this, SLOT( onScrollBarMoved( int ) ) );
+  connect( horizontalScrollBar(), SIGNAL( valueChanged( int ) ), this, SLOT( onScrollBarMoved( int ) ) );
+}
+
+void QtxTable::updateHeaderSpace( const Orientation o )
+{
+  HeaderVector& vec = o == Vertical ? myVerHeaders : myHorHeaders;
+
+  int size = 0;
+  for ( uint i = 0; i < vec.size(); i++ )
+  {
+    QHeader* hdr = vec.at( i );
+    int sz = o == Vertical ? hdr->width() : hdr->height();
+    if ( o == Vertical )
+      hdr->move( size, 0 );
+    else
+      hdr->move( 0, size );
+    size += sz;
+  }
+
+  if ( vec.size() == 0 )
+    size = o == Vertical ? verticalHeader()->width() : horizontalHeader()->height();
+
+  if ( o == Vertical )
+    setLeftMargin( size );
+  else
+    setTopMargin( size );
+}
+
+void QtxTable::updateHeaderSizes( const Orientation o )
+{
+  HeaderVector& vec = o == Vertical ? myVerHeaders : myHorHeaders;
+
+  for ( uint j = 0; j < vec.count(); j++ )
+  {
+    QHeader* hdr = vec.at( j );
+    for ( int s = 0; s < (int)hdr->count(); s++ )
+      hdr->resizeSection( s, o == Vertical ? rowHeight( s ) : columnWidth( s ) );
+    if ( o == Vertical )
+      hdr->resize( hdr->sizeHint().width(), hdr->height() );
+    else
+      hdr->resize( hdr->width(), hdr->sizeHint().height() );
+  }
+}
+
+void QtxTable::updateGeometries()
+{
+  QSize sz = horizontalHeader()->size();
+  int size = frameWidth();
+  for ( int h = 0; h < (int)myHorHeaders.size(); h++ )
+  {
+    QHeader* hdr = myHorHeaders.at( h );
+    hdr->setGeometry( frameWidth() + leftMargin(), size, sz.width(), hdr->height() );
+    size += hdr->height();
+  }
+
+  sz = verticalHeader()->size();
+  size = frameWidth();
+  for ( int v = 0; v < (int)myVerHeaders.size(); v++ )
+  {
+    QHeader* hdr = myVerHeaders.at( v );
+    hdr->setGeometry( size, frameWidth() + topMargin(), hdr->width(), sz.height() );
+    size += hdr->width();
+  }
+}
+
+void QtxTable::updateHeaderGeometries( const Orientation o )
+{
+  updateHeaderSizes( o );
+  updateHeaderSpace( o );
+  updateGeometries();
+}
+
+void QtxTable::updateSelectAllButton()
+{
+  if ( !mySelectAll )
+    return;
+
+  mySelectAll->setShown( selectionMode() == Multi || selectionMode() == MultiRow );
+  if ( mySelectAll->isVisibleTo( this  ) )
+    mySelectAll->setGeometry( frameWidth(), frameWidth(), leftMargin(), topMargin() );
 }
 
 #endif
index dd38208c75bb0e349e5c4a053e0eb19b6f79fd25..ea786562b43f69d2e6a5b23a095c7f2d7251f9e1 100644 (file)
 
 #include "Qtx.h"
 
+#include <qmap.h>
 #include <qtable.h>
+#include <qvariant.h>
+#include <qptrvector.h>
 
 #ifndef QT_NO_TABLE
 
 class QHeader;
+class QToolButton;
+class QtxStyleWrap;
+
+#ifdef WIN32
+#pragma warning( disable : 4251 )
+#endif
 
 class QTX_EXPORT QtxTable : public QTable
 {
   Q_OBJECT
 
-  class HeaderEditor;
+  Q_PROPERTY( bool selectAllEnabled READ isSelectAllEnabled WRITE setSelectAllEnabled )
+
+  class Header;
+  class StyleItem;
+
+protected:
+  enum { FgColor, BgColor, User };
 
 public:
   QtxTable( QWidget* = 0, const char* = 0 );
@@ -46,6 +61,8 @@ public:
   bool             editHeader( Orientation, const int );
   void             endEditHeader( const bool = true );
 
+  virtual void     setSelectionMode( SelectionMode );
+
   void             removeSelected( const bool row = true );
 
   virtual bool     eventFilter( QObject*, QEvent* );
@@ -53,11 +70,33 @@ public:
   virtual void     setNumRows( int );
   virtual void     setNumCols( int );
 
+  bool             isSelectAllEnabled() const;
+  virtual void     setSelectAllEnabled( const bool );
+
+  QHeader*         header( const Orientation, const int ) const;
+  int              numHeaders( const Orientation ) const;
+  void             setNumHeaders( const Orientation, const int );
+
+  int              verticalSpan( const Orientation, const int, const int ) const;
+  int              horizontalSpan( const Orientation, const int, const int ) const;
+  void             setVerticalSpan( const Orientation, const int, const int, const int );
+  void             setHorizontalSpan( const Orientation, const int, const int, const int );
+
+  QColor           cellForegroundColor( const int, const int ) const;
+  QColor           cellBackgroundColor( const int, const int ) const;
+  void             setCellForegroundColor( const int, const int, const QColor& );
+  void             setCellBackgroundColor( const int, const int, const QColor& );
+
+  virtual void     paintCell( QPainter*, int, int, const QRect&, bool, const QColorGroup& );
+
 signals:
   void             headerEdited( QHeader*, int );
   void             headerEdited( Orientation, int );
 
 public slots:
+  virtual void     selectAll();
+  virtual void     setTopMargin( int );
+  virtual void     setLeftMargin( int );
   virtual void     setHeaderEditable( Orientation, bool );
 
   virtual void     insertRows( int, int = 1 );
@@ -75,26 +114,60 @@ protected:
   virtual void     hideEvent( QHideEvent* );
   virtual void     resizeEvent( QResizeEvent* );
 
-  virtual bool     beginHeaderEdit( Orientation, const int );
+  virtual bool     beginHeaderEdit( Orientation, const int, const int = -1 );
   virtual void     endHeaderEdit( const bool = true );
   bool             isHeaderEditing() const;
   virtual QWidget* createHeaderEditor( QHeader*, const int, const bool = true );
   virtual void     setHeaderContentFromEditor( QHeader*, const int, QWidget* );
 
   QHeader*         header( Orientation o ) const;
+  virtual QRect    headerSectionRect( QHeader*, const int, int* = 0 ) const;
+
+  QVariant         cellProperty( const int, const int, const int ) const;
+  void             setCellProperty( const int, const int, const int, const QVariant& );
+
+private:
+  typedef QMap<int, QVariant>   Properties;
+  typedef QMap<int, Properties> PropsMap;
+  typedef QMap<int, PropsMap>   CellMap;
+  typedef QPtrVector<QHeader>   HeaderVector;
 
 private:
   void             updateHeaderEditor();
-  void             beginHeaderEdit( Orientation, const QPoint& );
-  QRect            headerSectionRect( QHeader*, const int ) const;
+  bool             beginHeaderEdit( QHeader*, const int );
+  void             beginHeaderEdit( QHeader*, const QPoint& );
+
+  QtxStyleWrap*    styleWrapper();
+  HeaderVector*    headerVector( const Orientation ) const;
+
+  void             updateGeometries();
+  void             updateSelectAllButton();
+
+  void             updateHeaders( const Orientation );
+  void             updateHeaderSizes( const Orientation );
+  void             updateHeaderSpace( const Orientation );
+  void             updateHeaderGeometries( const Orientation );
 
 private:
+  CellMap          myCellProps;
+  HeaderVector     myVerHeaders;
+  HeaderVector     myHorHeaders;
+  QtxStyleWrap*    myStyleWrapper;
+
   QWidget*         myHeaderEditor;
   QHeader*         myEditedHeader;
   int              myEditedSection;
   QMap<int, bool>  myHeaderEditable;
+
+  QToolButton*     mySelectAll;
+
+  friend class QtxTable::Header;
 };
 
+#ifdef WIN32
+#pragma warning( default: 4251 )
+#endif
+
 #endif
 
 #endif