libyui-qt
2.43.5
|
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"