libyui-qt  2.43.5
/usr/src/RPM/BUILD/libyui-qt-2.43.5/src/YQTree.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:       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"
 All Classes Functions Variables