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: YQTree.cc 00020 00021 Author: Stefan Hundhammer <sh@suse.de> 00022 00023 /-*/ 00024 00025 #include <QColorGroup> 00026 #include <QHeaderView> 00027 #include <QLabel> 00028 #include <QTreeWidget> 00029 #include <QVBoxLayout> 00030 #include <QString> 00031 #include <QPixmap> 00032 #define YUILogComponent "qt-ui" 00033 #include <yui/YUILog.h> 00034 00035 using std::min; 00036 using std::max; 00037 00038 #include "YQUI.h" 00039 #include <yui/YEvent.h> 00040 #include "utf8.h" 00041 #include "YQTree.h" 00042 #include <yui/YTreeItem.h> 00043 #include "YQSignalBlocker.h" 00044 #include "YQWidgetCaption.h" 00045 #include "YQApplication.h" 00046 00047 00048 #define VERBOSE_TREE_ITEMS 0 00049 00050 00051 YQTree::YQTree( YWidget * parent, const std::string & label, bool multiSelectionMode, bool recursiveSelectionMode ) 00052 : QFrame( (QWidget *) parent->widgetRep() ) 00053 , YTree( parent, label, multiSelectionMode, recursiveSelectionMode ) 00054 { 00055 QVBoxLayout* layout = new QVBoxLayout( this ); 00056 setLayout( layout ); 00057 00058 setWidgetRep( this ); 00059 00060 layout->setSpacing( YQWidgetSpacing ); 00061 layout->setMargin ( YQWidgetMargin ); 00062 00063 _nextSerialNo = 0; 00064 00065 _caption = new YQWidgetCaption( this, label ); 00066 YUI_CHECK_NEW( _caption ); 00067 layout->addWidget( _caption ); 00068 00069 _qt_treeWidget = new QTreeWidget( this ); 00070 YUI_CHECK_NEW( _qt_treeWidget ); 00071 layout->addWidget( _qt_treeWidget ); 00072 00073 // _qt_treeWidget->setHeaderLabel(""); 00074 // _qt_treeWidget->addColumn( "" ); 00075 _qt_treeWidget->header()->hide(); 00076 // _qt_treeWidget->setHeader(0L); 00077 _qt_treeWidget->setRootIsDecorated ( true ); 00078 00079 _qt_treeWidget->setContextMenuPolicy( Qt::CustomContextMenu ); 00080 00081 _caption->setBuddy ( _qt_treeWidget ); 00082 00083 connect( _qt_treeWidget, SIGNAL( itemSelectionChanged () ), 00084 this, SLOT ( slotSelectionChanged () ) ); 00085 00086 connect( _qt_treeWidget, SIGNAL( itemClicked ( QTreeWidgetItem *, int ) ), 00087 this, SLOT ( slotItemClicked ( QTreeWidgetItem *, int ) ) ); 00088 00089 // connect( _qt_treeWidget, SIGNAL( itemChanged ( QTreeWidgetItem *, int ) ), 00090 // this, SLOT ( slotItemChanged () ) ); 00091 00092 connect( _qt_treeWidget, SIGNAL( itemChanged ( QTreeWidgetItem *, int ) ), 00093 this, SLOT ( slotItemChanged (QTreeWidgetItem *) ) ); 00094 00095 connect( _qt_treeWidget, SIGNAL( itemDoubleClicked( QTreeWidgetItem *, int ) ), 00096 this, SLOT ( slotActivated ( QTreeWidgetItem * ) ) ); 00097 00098 connect( _qt_treeWidget, SIGNAL( itemExpanded ( QTreeWidgetItem * ) ), 00099 this, SLOT ( slotItemExpanded ( QTreeWidgetItem * ) ) ); 00100 00101 connect( _qt_treeWidget, SIGNAL( itemCollapsed ( QTreeWidgetItem * ) ), 00102 this, SLOT ( slotItemCollapsed( QTreeWidgetItem * ) ) ); 00103 00104 connect( _qt_treeWidget, SIGNAL( customContextMenuRequested ( const QPoint & ) ), 00105 this, SLOT ( slotContextMenu ( const QPoint & ) ) ); 00106 00107 } 00108 00109 00110 YQTree::~YQTree() 00111 { 00112 // NOP 00113 } 00114 00115 00116 void YQTree::setLabel( const std::string & label ) 00117 { 00118 _caption->setText( label ); 00119 YTree::setLabel( label ); 00120 } 00121 00122 00123 void YQTree::rebuildTree() 00124 { 00125 YQSignalBlocker sigBlocker( _qt_treeWidget ); 00126 _qt_treeWidget->clear(); 00127 00128 buildDisplayTree( 0, itemsBegin(), itemsEnd() ); 00129 _qt_treeWidget->resizeColumnToContents( 0 ); 00130 } 00131 00132 00133 void YQTree::buildDisplayTree( YQTreeItem * parentItem, YItemIterator begin, YItemIterator end ) 00134 { 00135 for ( YItemIterator it = begin; it < end; ++it ) 00136 { 00137 YTreeItem * orig = dynamic_cast<YTreeItem *> (*it); 00138 YUI_CHECK_PTR( orig ); 00139 00140 YQTreeItem * clone; 00141 00142 if ( parentItem ) 00143 clone = new YQTreeItem( this, parentItem, orig, _nextSerialNo++ ); 00144 else 00145 clone = new YQTreeItem( this, _qt_treeWidget, orig, _nextSerialNo++ ); 00146 00147 YUI_CHECK_NEW( clone ); 00148 00149 if ( orig->hasChildren() ) 00150 buildDisplayTree( clone, orig->childrenBegin(), orig->childrenEnd() ); 00151 } 00152 } 00153 00154 00155 void YQTree::selectItem( YItem * yItem, bool selected ) 00156 { 00157 YQSignalBlocker sigBlocker( _qt_treeWidget ); 00158 00159 // yuiDebug() << "Selecting item \"" << yItem->label() << "\" " << std::boolalpha << selected << std::endl; 00160 YTreeItem * treeItem = dynamic_cast<YTreeItem *> (yItem); 00161 YUI_CHECK_PTR( treeItem ); 00162 00163 YQTreeItem * yqTreeItem = (YQTreeItem *) treeItem->data(); 00164 YUI_CHECK_PTR( yqTreeItem ); 00165 00166 00167 if ( selected ) 00168 { 00169 selectItem( yqTreeItem ); 00170 } 00171 else if ( yqTreeItem == _qt_treeWidget->currentItem() ) 00172 { 00173 deselectAllItems(); 00174 } 00175 } 00176 00177 00178 void YQTree::selectItem( YQTreeItem * item ) 00179 { 00180 if ( item ) 00181 { 00182 YQSignalBlocker sigBlocker( _qt_treeWidget ); 00183 00184 _qt_treeWidget->setCurrentItem( item ); 00185 item->setSelected( true ); 00186 00187 if ( hasMultiSelection() ) 00188 item->setCheckState( 0, Qt::Checked ); 00189 00190 if ( item->parent() ) 00191 openBranch( (YQTreeItem *) item->parent() ); 00192 00193 YTree::selectItem( item->origItem(), true ); 00194 00195 // yuiDebug() << "selected item: \"" << item->origItem()->label() << "\"" << std::endl; 00196 00197 } 00198 } 00199 00200 00201 void YQTree::openBranch( YQTreeItem * item ) 00202 { 00203 while ( item ) 00204 { 00205 item->setOpen( true ); // Takes care of origItem()->setOpen() 00206 item = (YQTreeItem *) item->parent(); 00207 } 00208 } 00209 00210 void YQTree::slotItemExpanded( QTreeWidgetItem * qItem ) 00211 { 00212 YQTreeItem * item = dynamic_cast<YQTreeItem *> (qItem); 00213 00214 if ( item ) 00215 item->setOpen( true ); 00216 00217 _qt_treeWidget->resizeColumnToContents( 0 ); 00218 } 00219 00220 00221 void YQTree::slotItemCollapsed( QTreeWidgetItem * qItem ) 00222 { 00223 YQTreeItem * item = dynamic_cast<YQTreeItem *> (qItem); 00224 00225 if ( item ) 00226 item->setOpen( false ); 00227 00228 _qt_treeWidget->resizeColumnToContents( 0 ); 00229 } 00230 00231 00232 void YQTree::deselectAllItems() 00233 { 00234 YQSignalBlocker sigBlocker( _qt_treeWidget ); 00235 00236 YTree::deselectAllItems(); 00237 _qt_treeWidget->clearSelection(); 00238 00239 if ( hasMultiSelection() ) 00240 { 00241 QTreeWidgetItemIterator it( _qt_treeWidget); 00242 while (*it) 00243 { 00244 YQTreeItem * treeItem = dynamic_cast<YQTreeItem *> (*it); 00245 00246 if ( treeItem ) 00247 { 00248 treeItem->setCheckState( 0, Qt::Unchecked ); 00249 treeItem->origItem()->setSelected( false ); 00250 } 00251 ++it; 00252 } 00253 } 00254 00255 } 00256 00257 00258 void YQTree::deleteAllItems() 00259 { 00260 YQSignalBlocker sigBlocker( _qt_treeWidget ); 00261 00262 _qt_treeWidget->clear(); 00263 YTree::deleteAllItems(); 00264 } 00265 00266 00267 void YQTree::selectItem(QTreeWidgetItem * item, bool selected, bool recursive) 00268 { 00269 00270 YQTreeItem * treeItem = dynamic_cast<YQTreeItem *> (item); 00271 00272 if ( ! treeItem ) 00273 return; 00274 00275 YSelectionWidget::selectItem( treeItem->origItem(), selected ); 00276 00277 if ( recursive ) 00278 { 00279 for (int i=0; i < item->childCount(); ++i) 00280 { 00281 QTreeWidgetItem* child = item->child(i); 00282 child->setCheckState(0, ( selected )? Qt::Checked : Qt::Unchecked ); 00283 YQTree::selectItem( child, selected, recursive ); 00284 } 00285 } 00286 00287 } 00288 00289 00290 void YQTree::slotItemChanged( QTreeWidgetItem * item ) 00291 { 00292 00293 YQSignalBlocker sigBlocker( _qt_treeWidget ); 00294 00295 if ( hasMultiSelection() ) 00296 { 00297 if ( recursiveSelection() ) 00298 YQUI::ui()->busyCursor(); 00299 00300 if ( item->checkState(0) == Qt::Checked ) 00301 YQTree::selectItem( item, true, recursiveSelection() ); 00302 else 00303 YQTree::selectItem( item, false, recursiveSelection() ); 00304 00305 00306 if ( recursiveSelection() ) 00307 YQUI::ui()->normalCursor(); 00308 00309 } 00310 else 00311 { 00312 QList<QTreeWidgetItem *> items = _qt_treeWidget->selectedItems (); 00313 00314 if ( ! items.empty() ) 00315 { 00316 QTreeWidgetItem *qItem = items.first(); 00317 selectItem( dynamic_cast<YQTreeItem *> (qItem) ); 00318 } 00319 } 00320 00321 00322 00323 if ( notify() && ! YQUI::ui()->eventPendingFor( this ) ) 00324 YQUI::ui()->sendEvent( new YWidgetEvent( this, YEvent::ValueChanged ) ); 00325 00326 00327 } 00328 00329 00330 void YQTree::slotItemClicked( QTreeWidgetItem * item, int column ) 00331 { 00332 _qt_treeWidget->setCurrentItem( item ); 00333 00334 if ( notify() && ! YQUI::ui()->eventPendingFor( this ) ) 00335 YQUI::ui()->sendEvent( new YWidgetEvent( this, YEvent::SelectionChanged ) ); 00336 } 00337 00338 00339 00340 00341 void YQTree::slotSelectionChanged( ) 00342 { 00343 QList<QTreeWidgetItem *> items = _qt_treeWidget->selectedItems (); 00344 00345 if ( ! hasMultiSelection() && ! items.empty() ) 00346 { 00347 QTreeWidgetItem *qItem = items.first(); 00348 selectItem( dynamic_cast<YQTreeItem *> (qItem) ); 00349 } 00350 00351 00352 if ( notify() && ! YQUI::ui()->eventPendingFor( this ) ) 00353 YQUI::ui()->sendEvent( new YWidgetEvent( this, YEvent::SelectionChanged ) ); 00354 } 00355 00356 00357 void YQTree::slotActivated( QTreeWidgetItem * qItem ) 00358 { 00359 selectItem( dynamic_cast<YQTreeItem *> (qItem) ); 00360 00361 if ( notify() ) 00362 YQUI::ui()->sendEvent( new YWidgetEvent( this, YEvent::Activated ) ); 00363 } 00364 00365 00366 int YQTree::preferredWidth() 00367 { 00368 int hintWidth = !_caption->isHidden() ? _caption->sizeHint().width() : 0; 00369 return max( 80, hintWidth ); 00370 } 00371 00372 00373 int YQTree::preferredHeight() 00374 { 00375 int hintHeight = !_caption->isHidden() ? _caption->sizeHint().height() : 0; 00376 00377 // 80 is an arbitrary value. Use a MinSize or MinHeight widget to set a 00378 // size that is useful for the application. 00379 00380 return 80 + hintHeight; 00381 } 00382 00383 00384 void YQTree::setSize( int newWidth, int newHeight ) 00385 { 00386 resize( newWidth, newHeight ); 00387 } 00388 00389 00390 void YQTree::setEnabled( bool enabled ) 00391 { 00392 _caption->setEnabled( enabled ); 00393 _qt_treeWidget->setEnabled( enabled ); 00394 YWidget::setEnabled( enabled ); 00395 } 00396 00397 00398 bool YQTree::setKeyboardFocus() 00399 { 00400 _qt_treeWidget->setFocus(); 00401 00402 return true; 00403 } 00404 00405 00406 void YQTree::slotContextMenu ( const QPoint & pos ) 00407 { 00408 if ( ! _qt_treeWidget || ! _qt_treeWidget->viewport() ) 00409 return; 00410 00411 YQUI::yqApp()->setContextMenuPos( _qt_treeWidget->viewport()->mapToGlobal( pos ) ); 00412 if ( notifyContextMenu() ) 00413 YQUI::ui()->sendEvent( new YWidgetEvent( this, YEvent::ContextMenuActivated ) ); 00414 } 00415 00416 00417 YTreeItem * 00418 YQTree::currentItem() 00419 { 00420 00421 QTreeWidgetItem * currentQItem = _qt_treeWidget->currentItem(); 00422 00423 if ( currentQItem ) 00424 { 00425 YQTreeItem * item = dynamic_cast<YQTreeItem *> (currentQItem); 00426 00427 if ( item ) 00428 return item->origItem(); 00429 } 00430 00431 return 0; 00432 } 00433 00434 00435 00436 /*============================================================================*/ 00437 00438 00439 00440 YQTreeItem::YQTreeItem( YQTree * tree, 00441 QTreeWidget * listView, 00442 YTreeItem * orig, 00443 int serial ) 00444 : QTreeWidgetItem( listView ) 00445 { 00446 init( tree, orig, serial ); 00447 00448 #if VERBOSE_TREE_ITEMS 00449 yuiDebug() << "Creating toplevel tree item \"" << orig->label() << "\"" << std::endl; 00450 #endif 00451 00452 } 00453 00454 00455 YQTreeItem::YQTreeItem( YQTree * tree, 00456 YQTreeItem * parentItem, 00457 YTreeItem * orig, 00458 int serial ) 00459 : QTreeWidgetItem( parentItem ) 00460 { 00461 init( tree, orig, serial ); 00462 #if VERBOSE_TREE_ITEMS 00463 yuiDebug() << "Creating tree item \"" << orig->label() 00464 << "\" as child of \"" << parentItem->origItem()->label() << "\"" 00465 << std::endl; 00466 00467 #endif 00468 00469 00470 00471 } 00472 00473 00474 void YQTreeItem::init( YQTree * tree, 00475 YTreeItem * orig, 00476 int serial ) 00477 { 00478 YUI_CHECK_PTR( tree ); 00479 YUI_CHECK_PTR( orig ); 00480 00481 _tree = tree; 00482 _serialNo = serial; 00483 _origItem = orig; 00484 00485 _origItem->setData( this ); 00486 00487 setText( 0, fromUTF8 ( _origItem->label() ) ); 00488 setOpen( _origItem->isOpen() ); 00489 00490 if ( _origItem->hasIconName() ) 00491 { 00492 string iconName = _tree->iconFullPath( _origItem ); 00493 QPixmap icon( iconName.c_str() ); 00494 00495 if ( icon.isNull() ) 00496 yuiWarning() << "Can't load icon " << iconName << std::endl; 00497 else 00498 setData( 0, Qt::DecorationRole, icon ); 00499 } 00500 00501 if ( tree->hasMultiSelection() ) 00502 setCheckState(0,Qt::Unchecked); 00503 } 00504 00505 00506 void 00507 YQTreeItem::setOpen( bool open ) 00508 { 00509 QTreeWidgetItem::setExpanded( open ); 00510 _origItem->setOpen( open ); 00511 } 00512 00513 00514 00515 QString 00516 YQTreeItem::key( int column, bool ascending ) const 00517 { 00518 /* 00519 * Sorting key for QListView internal sorting: 00520 * 00521 * Always sort tree items by insertion order. The tree widget cannot 00522 * maintain a meaningful sorting order of its own: All it could do is sort 00523 * by names (ASCII sort). Better let the application handle this. 00524 */ 00525 00526 QString strKey; 00527 strKey.sprintf( "%08d", _serialNo ); 00528 00529 return strKey; 00530 } 00531 00532 00533 #include "YQTree.moc"