libyui-qt  2.43.5
/usr/src/RPM/BUILD/libyui-qt-2.43.5/src/QY2ListView.cc
00001 /*
00002   Copyright (C) 2000-2012 Novell, Inc
00003   This library is free software; you can redistribute it and/or modify
00004   it under the terms of the GNU Lesser General Public License as
00005   published by the Free Software Foundation; either version 2.1 of the
00006   License, or (at your option) version 3.0 of the License. This library
00007   is distributed in the hope that it will be useful, but WITHOUT ANY
00008   WARRANTY; without even the implied warranty of MERCHANTABILITY or
00009   FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
00010   License for more details. You should have received a copy of the GNU
00011   Lesser General Public License along with this library; if not, write
00012   to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
00013   Floor, Boston, MA 02110-1301 USA
00014 */
00015 
00016 
00017 /*-/
00018 
00019   File:       QY2ListView.cc
00020 
00021   Author:     Stefan Hundhammer <sh@suse.de>
00022 
00023   This is a pure Qt widget - it can be used independently of YaST2.
00024 
00025 /-*/
00026 
00027 
00028 #include <QPixmap>
00029 #include <QHeaderView>
00030 #include <QMouseEvent>
00031 #include "QY2ListView.h"
00032 
00033 #define YUILogComponent "qt-pkg"
00034 #include <yui/YUILog.h>
00035 
00036 QY2ListView::QY2ListView( QWidget * parent )
00037     : QTreeWidget( parent )
00038     , _mousePressedItem(0)
00039     , _mousePressedCol( -1 )
00040     , _mousePressedButton( Qt::NoButton )
00041     , _sortByInsertionSequence( false )
00042     , _nextSerial(0)
00043     , _mouseButton1PressedInHeader( false )
00044     , _finalSizeChangeExpected( false )
00045 {
00046     //FIXME QTreeWidget::setShowToolTips( false );
00047     setRootIsDecorated(false);
00048 
00049 #if FIXME_TOOLTIP
00050     _toolTip = new QY2ListViewToolTip( this );
00051 #endif
00052 
00053     if ( header() )
00054     {
00055         header()->installEventFilter( this );
00056         header()->setStretchLastSection( false );
00057     }
00058 
00059     connect( header(),  SIGNAL( sectionResized     ( int, int, int ) ),
00060              this,      SLOT  ( columnWidthChanged ( int, int, int ) ) );
00061 
00062     connect( this,      SIGNAL( itemExpanded ( QTreeWidgetItem *) ),
00063              this,      SLOT  ( treeExpanded ( QTreeWidgetItem *)  ) );
00064 
00065     connect( this,      SIGNAL( itemCollapsed ( QTreeWidgetItem *) ),
00066              this,      SLOT  ( treeCollapsed ( QTreeWidgetItem *)  ) );
00067 
00068 }
00069 
00070 
00071 QY2ListView::~QY2ListView()
00072 {
00073 #if FIXME_TOOLTIP
00074     if ( _toolTip )
00075         delete _toolTip;
00076 #endif
00077 }
00078 
00079 
00080 void
00081 QY2ListView::selectSomething()
00082 {
00083     QTreeWidgetItemIterator it( this );
00084 
00085     while ( *it )
00086     {
00087         QY2ListViewItem * item = dynamic_cast<QY2ListViewItem *> (*it);
00088 
00089         if ( item && (item->flags() & Qt::ItemIsSelectable) )
00090         {
00091             item->setSelected(true); // emits signal, too
00092             return;
00093         }
00094 
00095         ++it;
00096     }
00097 }
00098 
00099 
00100 void
00101 QY2ListView::clear()
00102 {
00103     QTreeWidget::clear();
00104     restoreColumnWidths();
00105 }
00106 
00107 
00108 void
00109 QY2ListView::updateItemStates()
00110 {
00111     QTreeWidgetItemIterator it( this );
00112 
00113     while ( *it )
00114     {
00115         QY2ListViewItem * item = dynamic_cast<QY2ListViewItem *> (*it);
00116 
00117         if ( item )
00118             item->updateStatus();
00119 
00120         ++it;
00121     }
00122 }
00123 
00124 
00125 void
00126 QY2ListView::updateItemData()
00127 {
00128     QTreeWidgetItemIterator it( this );
00129 
00130     while ( *it )
00131     {
00132         QY2ListViewItem * item = dynamic_cast<QY2ListViewItem *> (*it);
00133 
00134         if ( item )
00135             item->updateData();
00136 
00137         ++it;
00138     }
00139 }
00140 
00141 
00142 QString
00143 QY2ListView::toolTip( QTreeWidgetItem * listViewItem, int column )
00144 {
00145     if ( ! listViewItem )
00146         return QString::null;
00147 
00148     QString text;
00149 
00150     // text.sprintf( "Column %d:\n%s", column, (const char *) listViewItem->text( column ) );
00151 
00152     // Try known item classes
00153 
00154     QY2ListViewItem * item = dynamic_cast<QY2ListViewItem *> (listViewItem);
00155 
00156     if ( item )
00157         return item->toolTip( column );
00158 
00159     QY2CheckListItem * checkListItem = dynamic_cast<QY2CheckListItem *> (listViewItem);
00160 
00161     if ( checkListItem )
00162         return checkListItem->toolTip( column );
00163 
00164     return QString::null;
00165 }
00166 
00167 
00168 void
00169 QY2ListView::saveColumnWidths()
00170 {
00171     _savedColumnWidth.clear();
00172     _savedColumnWidth.reserve( columnCount() );
00173 
00174     for ( int i = 0; i < columnCount(); i++ )
00175     {
00176         int size = header()->sectionSize(i);
00177         // yuiMilestone() << "Saving size " << size << " for section " << i << std::endl;
00178         _savedColumnWidth.push_back( size );
00179     }
00180 }
00181 
00182 
00183 void
00184 QY2ListView::restoreColumnWidths()
00185 {
00186     if ( _savedColumnWidth.size() != (unsigned) columnCount() )         // never manually resized
00187     {
00188 #if 0
00189         for ( int i = 0; i < columnCount(); i++ )                       // use optimized column width
00190             resizeColumnToContents(i);
00191 #endif
00192     }
00193     else                                                // stored settings after manual resizing
00194     {
00195         for ( int i = 0; i < columnCount(); i++ )
00196         {
00197             header()->resizeSection( i, _savedColumnWidth[ i ] ); // restore saved column width
00198 
00199 #if 0
00200             yuiDebug() << "Restoring size " << _savedColumnWidth[i]
00201                        << " for section " << i
00202                        << " now " << header()->sectionSize(i)
00203                        << std::endl;
00204 #endif
00205         }
00206     }
00207 }
00208 
00209 
00210 void
00211 QY2ListView::mousePressEvent( QMouseEvent * ev )
00212 {
00213     //y2internal("POS is %d %d", ev->pos().x(), ev->pos().y() );
00214     QTreeWidgetItem * item = itemAt( ev->pos() );
00215 
00216 
00217     if ( item && ( item->flags() & Qt::ItemIsEnabled ) )
00218     {
00219         _mousePressedItem       = item;
00220                 _mousePressedCol        = header()->logicalIndexAt( ev->pos().x() );
00221         _mousePressedButton     = ev->button();
00222     }
00223     else        // invalidate last click data
00224     {
00225         _mousePressedItem       = 0;
00226         _mousePressedCol        = -1;
00227         _mousePressedButton     = -1;
00228     }
00229 
00230     // Call base class method
00231     QTreeWidget::mousePressEvent( ev );
00232 }
00233 
00234 
00235 void
00236 QY2ListView::mouseReleaseEvent( QMouseEvent * ev )
00237 {
00238     //y2internal("REPOS is %d %d", ev->pos().x(), ev->pos().y() );
00239     QTreeWidgetItem * item = itemAt( ev->pos() );
00240 
00241     if ( item && ( item->flags() & Qt::ItemIsEnabled ) && item == _mousePressedItem )
00242     {
00243         int col = header()->logicalIndexAt( ev->pos().x() );
00244         //y2internal("COL %d", col);
00245         if ( item == _mousePressedItem  &&
00246              col  == _mousePressedCol   &&
00247              ev->button() == _mousePressedButton )
00248         {
00249             emit( columnClicked( ev->button(), item, col, ev->globalPos() ) );
00250         }
00251 
00252     }
00253 
00254     // invalidate last click data
00255 
00256     _mousePressedItem   = 0;
00257     _mousePressedCol    = -1;
00258     _mousePressedButton = Qt::NoButton;
00259 
00260     // Call base class method
00261     QTreeWidget::mouseReleaseEvent( ev );
00262 }
00263 
00264 
00265 void
00266 QY2ListView::mouseDoubleClickEvent( QMouseEvent * ev )
00267 {
00268     QTreeWidgetItem * item = itemAt( mapToGlobal( ev->pos() ) );
00269 
00270     if ( item && ( item->flags() & Qt::ItemIsEnabled ) )
00271     {
00272         int col = header()->logicalIndexAt( ev->pos().x() );
00273         emit( columnDoubleClicked( ev->button(), (QY2ListViewItem *) item, col, ev->globalPos() ) );
00274      }
00275 
00276      // invalidate last click data
00277 
00278      _mousePressedItem  = 0;
00279      _mousePressedCol   = -1;
00280      _mousePressedButton        = Qt::NoButton;
00281 
00282      // Call base class method
00283      QTreeWidget::mouseDoubleClickEvent( ev );
00284 }
00285 
00286 
00287 void
00288 QY2ListView::columnWidthChanged( int, int, int )
00289 {
00290     saveColumnWidths();
00291 
00292 #if 0
00293     // Workaround for Qt bug:
00294     //
00295     // QHeader sends a sizeChange() signal for every size change, not only (as
00296     // documented) when the user resizes a header column manually. But we only
00297     // want to record the column widths if the user explicitly did that, so
00298     // ignore those signals if the mouse isn't pressed. There is also one final
00299     // sizeChange() signal immediately after the user releases the mouse button.
00300 
00301     if ( _mouseButton1PressedInHeader || _finalSizeChangeExpected )
00302     {
00303 
00304         // Consume that one sizeChange() signal that is sent immediately after
00305         // the mouse button is released, but make sure to reset that flag only
00306         // when appropriate.
00307 
00308         if ( ! _mouseButton1PressedInHeader )
00309             _finalSizeChangeExpected = false;
00310     }
00311 #endif
00312 }
00313 
00314 
00315 bool
00316 QY2ListView::eventFilter( QObject * obj, QEvent * event )
00317 {
00318     if ( event && obj && obj == header() )
00319     {
00320         if ( event->type() == QEvent::MouseButtonPress )
00321         {
00322             QMouseEvent * mouseEvent = (QMouseEvent *) event;
00323 
00324             if ( mouseEvent->button() == 1 )
00325             {
00326                 _mouseButton1PressedInHeader = true;
00327                 _finalSizeChangeExpected     = false;
00328             }
00329         }
00330         else if ( event->type() == QEvent::MouseButtonRelease )
00331         {
00332             QMouseEvent * mouseEvent = (QMouseEvent *) event;
00333 
00334             if ( mouseEvent->button() == 1 )
00335             {
00336                 _finalSizeChangeExpected     = true;
00337                 _mouseButton1PressedInHeader = false;
00338             }
00339         }
00340     }
00341 
00342     return QTreeWidget::eventFilter( obj, event );
00343 }
00344 
00345 
00346 QSize
00347 QY2ListView::minimumSizeHint() const
00348 {
00349     return QSize( 0, 0 );
00350 }
00351 
00352 
00353 void
00354 QY2ListView::setSortByInsertionSequence( bool sortByInsertionSequence )
00355 {
00356     _sortByInsertionSequence = sortByInsertionSequence;
00357     //FIXME sort();
00358     header()->setClickable( ! _sortByInsertionSequence );
00359 
00360 }
00361 
00362 
00363 
00364 
00365 
00366 
00367 QY2ListViewItem::QY2ListViewItem( QY2ListView *         parentListView,
00368                                   const QString &       text )
00369     : QTreeWidgetItem( parentListView, QStringList(text), 1)
00370 {
00371     _serial = parentListView->nextSerial();
00372 }
00373 
00374 
00375 QY2ListViewItem::QY2ListViewItem( QTreeWidgetItem *     parentItem,
00376                                   const QString &       text )
00377     : QTreeWidgetItem( parentItem, QStringList(text), 1 )
00378 {
00379     _serial = 0;
00380 
00381     QY2ListView * parentListView = dynamic_cast<QY2ListView *> ( treeWidget() );
00382 
00383     if ( parentListView )
00384         _serial = parentListView->nextSerial();
00385 }
00386 
00387 
00388 QY2ListViewItem::~QY2ListViewItem()
00389 {
00390     // NOP
00391 }
00392 
00393 
00394 bool
00395 QY2ListViewItem::operator< ( const QTreeWidgetItem & otherListViewItem ) const
00396 {
00397     bool sortByInsertionSequence = false;
00398     QY2ListView * parentListView = dynamic_cast<QY2ListView *> (treeWidget());
00399 
00400     if ( parentListView )
00401         sortByInsertionSequence = parentListView->sortByInsertionSequence();
00402 
00403     if ( sortByInsertionSequence )
00404     {
00405         const QY2ListViewItem * other = dynamic_cast<const QY2ListViewItem *> (&otherListViewItem);
00406 
00407         if ( other )
00408         {
00409             return ( this->serial() < other->serial() );
00410         }
00411 
00412         // Still here? Try the other version: QY2CheckListItem.
00413 
00414         const QY2CheckListItem * otherCheckListItem = dynamic_cast<const QY2CheckListItem *> (&otherListViewItem);
00415 
00416         if ( otherCheckListItem )
00417         {
00418             return ( this->serial() < otherCheckListItem->serial() );
00419         }
00420 
00421     }
00422 
00423     // numeric sorting if columns are numbers
00424     int column = treeWidget()->sortColumn();
00425     QString text1=text(column).trimmed();
00426     QString text2=otherListViewItem.text(column).trimmed();
00427 
00428     text1=text1.left(text1.indexOf(QChar(' ')));
00429     text2=text2.left(text2.indexOf(QChar(' ')));
00430 
00431     bool ok1, ok2; // conversion to int successful
00432     bool retval = text1.toInt(&ok1) < text2.toInt(&ok2);
00433 
00434     if (ok1 && ok2 )
00435         return retval;     // int < int
00436     else if (ok1 && !ok2)
00437         return true;       // int < std::string
00438     else if (!ok1 && ok2)
00439         return false;      // std::string > int
00440 
00441     // and finally non-numeric sorting is done by the base class
00442     return QTreeWidgetItem::operator<(otherListViewItem);
00443 }
00444 
00445 
00446 QY2CheckListItem::QY2CheckListItem( QY2ListView *               parentListView,
00447                                     const QString &             text )
00448     : QY2ListViewItem( parentListView, text)
00449 {
00450     setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
00451     setCheckState(0, Qt::Unchecked);
00452     _serial = parentListView->nextSerial();
00453 }
00454 
00455 
00456 QY2CheckListItem::QY2CheckListItem( QTreeWidgetItem *           parentItem,
00457                                     const QString &             text )
00458     : QY2ListViewItem( parentItem, text)
00459 {
00460     _serial = 0;
00461     QY2ListView * parentListView = dynamic_cast<QY2ListView *> ( treeWidget() );
00462 
00463     setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
00464     setCheckState(0, Qt::Unchecked);
00465 
00466     if ( parentListView )
00467         _serial = parentListView->nextSerial();
00468 }
00469 
00470 QY2CheckListItem::~QY2CheckListItem()
00471 {
00472     // NOP
00473 }
00474 
00475 
00476 
00477 #if FIXME_ITEM_COLORS
00478 void
00479 QY2CheckListItem::paintCell( QPainter *                 painter,
00480                              const QColorGroup &        colorGroup,
00481                              int                        column,
00482                              int                        width,
00483                              int                        alignment )
00484 {
00485     QColorGroup cg = colorGroup;
00486 
00487     if ( _textColor.isValid() )         cg.setColor( QColorGroup::Text, _textColor );
00488     if ( _backgroundColor.isValid() )   cg.setColor( QColorGroup::Base, _backgroundColor );
00489 
00490     QTreeWidgetItem::paintCell( painter, cg, column, width, alignment );
00491 }
00492 #endif
00493 
00494 
00495 #if FIXME_TOOLTIP
00496 void
00497 QY2ListViewToolTip::maybeTip( const QPoint & pos )
00498 {
00499     Q3Header *       header        = _listView->header();
00500     QTreeWidgetItem * item          = _listView->itemAt( pos );
00501 
00502     if ( ! item )
00503         return;
00504 
00505     int x      = _listView->viewportToContents( pos ).x();
00506     int column = header->sectionAt(x);
00507     int indent = 0;
00508 
00509     if ( column == 0 )
00510     {
00511         indent  =  item->depth() + ( _listView->rootIsDecorated() ? 1 : 0 );
00512         indent *=  _listView->treeStepSize();
00513 
00514         if ( pos.x() < indent )
00515             column = -1;
00516     }
00517 
00518     QString text = _listView->toolTip( item, column );
00519 
00520     if ( ! text.isEmpty() )
00521     {
00522         QRect rect( _listView->itemRect( item ) );
00523 
00524         if ( column < 0 )
00525         {
00526             rect.setX(0);
00527             rect.setWidth( indent );
00528         }
00529         else
00530         {
00531             QPoint topLeft( header->sectionPos( column ), 0 );
00532             topLeft = _listView->contentsToViewport( topLeft );
00533             rect.setX( topLeft.x() );
00534             rect.setWidth( header->sectionSize( column ) );
00535         }
00536 
00537         tip( rect, text );
00538     }
00539 }
00540 
00541 #endif
00542 
00543 
00544 void QY2ListView::treeExpanded( QTreeWidgetItem * listViewItem )
00545 {
00546     if ( columnCount() == 1 && header() && header()->isHidden() )
00547         resizeColumnToContents( 0 );
00548 }
00549 
00550 
00551 void QY2ListView::treeCollapsed( QTreeWidgetItem * listViewItem )
00552 {
00553     if ( columnCount() == 1  && header() && header()->isHidden())
00554         resizeColumnToContents( 0 );
00555 }
00556 
00557 
00558 
00559 
00560 #include "QY2ListView.moc"
 All Classes Functions Variables