libyui-qt  2.42.4
 All Classes Functions Variables
YQTree.cc
1 /*
2  Copyright (C) 2000-2012 Novell, Inc
3  This library is free software; you can redistribute it and/or modify
4  it under the terms of the GNU Lesser General Public License as
5  published by the Free Software Foundation; either version 2.1 of the
6  License, or (at your option) version 3.0 of the License. This library
7  is distributed in the hope that it will be useful, but WITHOUT ANY
8  WARRANTY; without even the implied warranty of MERCHANTABILITY or
9  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
10  License for more details. You should have received a copy of the GNU
11  Lesser General Public License along with this library; if not, write
12  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
13  Floor, Boston, MA 02110-1301 USA
14 */
15 
16 
17 /*-/
18 
19  File: YQTree.cc
20 
21  Author: Stefan Hundhammer <sh@suse.de>
22 
23 /-*/
24 
25 #include <QColorGroup>
26 #include <QHeaderView>
27 #include <QLabel>
28 #include <QTreeWidget>
29 #include <QVBoxLayout>
30 #include <QString>
31 #include <QPixmap>
32 #define YUILogComponent "qt-ui"
33 #include <yui/YUILog.h>
34 
35 using std::min;
36 using std::max;
37 
38 #include "YQUI.h"
39 #include <yui/YEvent.h>
40 #include "utf8.h"
41 #include "YQTree.h"
42 #include <yui/YTreeItem.h>
43 #include "YQSignalBlocker.h"
44 #include "YQWidgetCaption.h"
45 #include "YQApplication.h"
46 
47 
48 #define VERBOSE_TREE_ITEMS 0
49 
50 
51 YQTree::YQTree( YWidget * parent, const std::string & label, bool multiSelectionMode, bool recursiveSelectionMode )
52  : QFrame( (QWidget *) parent->widgetRep() )
53  , YTree( parent, label, multiSelectionMode, recursiveSelectionMode )
54 {
55  QVBoxLayout* layout = new QVBoxLayout( this );
56  setLayout( layout );
57 
58  setWidgetRep( this );
59 
60  layout->setSpacing( YQWidgetSpacing );
61  layout->setMargin ( YQWidgetMargin );
62 
63  _nextSerialNo = 0;
64 
65  _caption = new YQWidgetCaption( this, label );
66  YUI_CHECK_NEW( _caption );
67  layout->addWidget( _caption );
68 
69  _qt_treeWidget = new QTreeWidget( this );
70  YUI_CHECK_NEW( _qt_treeWidget );
71  layout->addWidget( _qt_treeWidget );
72 
73  // _qt_treeWidget->setHeaderLabel("");
74  // _qt_treeWidget->addColumn( "" );
75  _qt_treeWidget->header()->hide();
76  // _qt_treeWidget->setHeader(0L);
77  _qt_treeWidget->setRootIsDecorated ( true );
78 
79  _qt_treeWidget->setContextMenuPolicy( Qt::CustomContextMenu );
80 
81  _caption->setBuddy ( _qt_treeWidget );
82 
83  connect( _qt_treeWidget, SIGNAL( itemSelectionChanged () ),
84  this, SLOT ( slotSelectionChanged () ) );
85 
86  connect( _qt_treeWidget, SIGNAL( itemClicked ( QTreeWidgetItem *, int ) ),
87  this, SLOT ( slotItemClicked ( QTreeWidgetItem *, int ) ) );
88 
89 // connect( _qt_treeWidget, SIGNAL( itemChanged ( QTreeWidgetItem *, int ) ),
90 // this, SLOT ( slotItemChanged () ) );
91 
92  connect( _qt_treeWidget, SIGNAL( itemChanged ( QTreeWidgetItem *, int ) ),
93  this, SLOT ( slotItemChanged (QTreeWidgetItem *) ) );
94 
95  connect( _qt_treeWidget, SIGNAL( itemDoubleClicked( QTreeWidgetItem *, int ) ),
96  this, SLOT ( slotActivated ( QTreeWidgetItem * ) ) );
97 
98  connect( _qt_treeWidget, SIGNAL( itemExpanded ( QTreeWidgetItem * ) ),
99  this, SLOT ( slotItemExpanded ( QTreeWidgetItem * ) ) );
100 
101  connect( _qt_treeWidget, SIGNAL( itemCollapsed ( QTreeWidgetItem * ) ),
102  this, SLOT ( slotItemCollapsed( QTreeWidgetItem * ) ) );
103 
104  connect( _qt_treeWidget, SIGNAL( customContextMenuRequested ( const QPoint & ) ),
105  this, SLOT ( slotContextMenu ( const QPoint & ) ) );
106 
107 }
108 
109 
111 {
112  // NOP
113 }
114 
115 
116 void YQTree::setLabel( const std::string & label )
117 {
118  _caption->setText( label );
119  YTree::setLabel( label );
120 }
121 
122 
124 {
125  YQSignalBlocker sigBlocker( _qt_treeWidget );
126  _qt_treeWidget->clear();
127 
128  buildDisplayTree( 0, itemsBegin(), itemsEnd() );
129  _qt_treeWidget->resizeColumnToContents( 0 );
130 }
131 
132 
133 void YQTree::buildDisplayTree( YQTreeItem * parentItem, YItemIterator begin, YItemIterator end )
134 {
135  for ( YItemIterator it = begin; it < end; ++it )
136  {
137  YTreeItem * orig = dynamic_cast<YTreeItem *> (*it);
138  YUI_CHECK_PTR( orig );
139 
140  YQTreeItem * clone;
141 
142  if ( parentItem )
143  clone = new YQTreeItem( this, parentItem, orig, _nextSerialNo++ );
144  else
145  clone = new YQTreeItem( this, _qt_treeWidget, orig, _nextSerialNo++ );
146 
147  YUI_CHECK_NEW( clone );
148 
149  if ( orig->hasChildren() )
150  buildDisplayTree( clone, orig->childrenBegin(), orig->childrenEnd() );
151  }
152 }
153 
154 
155 void YQTree::selectItem( YItem * yItem, bool selected )
156 {
157  YQSignalBlocker sigBlocker( _qt_treeWidget );
158 
159  // yuiDebug() << "Selecting item \"" << yItem->label() << "\" " << std::boolalpha << selected << std::endl;
160  YTreeItem * treeItem = dynamic_cast<YTreeItem *> (yItem);
161  YUI_CHECK_PTR( treeItem );
162 
163  YQTreeItem * yqTreeItem = (YQTreeItem *) treeItem->data();
164  YUI_CHECK_PTR( yqTreeItem );
165 
166 
167  if ( selected )
168  {
169  selectItem( yqTreeItem );
170  }
171  else if ( yqTreeItem == _qt_treeWidget->currentItem() )
172  {
174  }
175 }
176 
177 
179 {
180  if ( item )
181  {
182  YQSignalBlocker sigBlocker( _qt_treeWidget );
183 
184  _qt_treeWidget->setCurrentItem( item );
185  item->setSelected( true );
186 
187  if ( hasMultiSelection() )
188  item->setCheckState( 0, Qt::Checked );
189 
190  if ( item->parent() )
191  openBranch( (YQTreeItem *) item->parent() );
192 
193  YTree::selectItem( item->origItem(), true );
194 
195  // yuiDebug() << "selected item: \"" << item->origItem()->label() << "\"" << std::endl;
196 
197  }
198 }
199 
200 
202 {
203  while ( item )
204  {
205  item->setOpen( true ); // Takes care of origItem()->setOpen()
206  item = (YQTreeItem *) item->parent();
207  }
208 }
209 
210 void YQTree::slotItemExpanded( QTreeWidgetItem * qItem )
211 {
212  YQTreeItem * item = dynamic_cast<YQTreeItem *> (qItem);
213 
214  if ( item )
215  item->setOpen( true );
216 
217  _qt_treeWidget->resizeColumnToContents( 0 );
218 }
219 
220 
221 void YQTree::slotItemCollapsed( QTreeWidgetItem * qItem )
222 {
223  YQTreeItem * item = dynamic_cast<YQTreeItem *> (qItem);
224 
225  if ( item )
226  item->setOpen( false );
227 
228  _qt_treeWidget->resizeColumnToContents( 0 );
229 }
230 
231 
233 {
234  YQSignalBlocker sigBlocker( _qt_treeWidget );
235 
236  YTree::deselectAllItems();
237  _qt_treeWidget->clearSelection();
238 
239  if ( hasMultiSelection() )
240  {
241  QTreeWidgetItemIterator it( _qt_treeWidget);
242  while (*it)
243  {
244  YQTreeItem * treeItem = dynamic_cast<YQTreeItem *> (*it);
245 
246  if ( treeItem )
247  {
248  treeItem->setCheckState( 0, Qt::Unchecked );
249  treeItem->origItem()->setSelected( false );
250  }
251  ++it;
252  }
253  }
254 
255 }
256 
257 
259 {
260  YQSignalBlocker sigBlocker( _qt_treeWidget );
261 
262  _qt_treeWidget->clear();
263  YTree::deleteAllItems();
264 }
265 
266 
267 void YQTree::selectItem(QTreeWidgetItem * item, bool selected, bool recursive)
268 {
269 
270  YQTreeItem * treeItem = dynamic_cast<YQTreeItem *> (item);
271 
272  if ( ! treeItem )
273  return;
274 
275  YSelectionWidget::selectItem( treeItem->origItem(), selected );
276 
277  if ( recursive )
278  {
279  for (int i=0; i < item->childCount(); ++i)
280  {
281  QTreeWidgetItem* child = item->child(i);
282  child->setCheckState(0, ( selected )? Qt::Checked : Qt::Unchecked );
283  YQTree::selectItem( child, selected, recursive );
284  }
285  }
286 
287 }
288 
289 
290 void YQTree::slotItemChanged( QTreeWidgetItem * item )
291 {
292 
293  YQSignalBlocker sigBlocker( _qt_treeWidget );
294 
295  if ( hasMultiSelection() )
296  {
297  if ( recursiveSelection() )
298  YQUI::ui()->busyCursor();
299 
300  if ( item->checkState(0) == Qt::Checked )
301  YQTree::selectItem( item, true, recursiveSelection() );
302  else
303  YQTree::selectItem( item, false, recursiveSelection() );
304 
305 
306  if ( recursiveSelection() )
307  YQUI::ui()->normalCursor();
308 
309  }
310  else
311  {
312  QList<QTreeWidgetItem *> items = _qt_treeWidget->selectedItems ();
313 
314  if ( ! items.empty() )
315  {
316  QTreeWidgetItem *qItem = items.first();
317  selectItem( dynamic_cast<YQTreeItem *> (qItem) );
318  }
319  }
320 
321 
322 
323  if ( notify() && ! YQUI::ui()->eventPendingFor( this ) )
324  YQUI::ui()->sendEvent( new YWidgetEvent( this, YEvent::ValueChanged ) );
325 
326 
327 }
328 
329 
330 void YQTree::slotItemClicked( QTreeWidgetItem * item, int column )
331 {
332  _qt_treeWidget->setCurrentItem( item );
333 
334  if ( notify() && ! YQUI::ui()->eventPendingFor( this ) )
335  YQUI::ui()->sendEvent( new YWidgetEvent( this, YEvent::SelectionChanged ) );
336 }
337 
338 
339 
340 
342 {
343  QList<QTreeWidgetItem *> items = _qt_treeWidget->selectedItems ();
344 
345  if ( ! hasMultiSelection() && ! items.empty() )
346  {
347  QTreeWidgetItem *qItem = items.first();
348  selectItem( dynamic_cast<YQTreeItem *> (qItem) );
349  }
350 
351 
352  if ( notify() && ! YQUI::ui()->eventPendingFor( this ) )
353  YQUI::ui()->sendEvent( new YWidgetEvent( this, YEvent::SelectionChanged ) );
354 }
355 
356 
357 void YQTree::slotActivated( QTreeWidgetItem * qItem )
358 {
359  selectItem( dynamic_cast<YQTreeItem *> (qItem) );
360 
361  if ( notify() )
362  YQUI::ui()->sendEvent( new YWidgetEvent( this, YEvent::Activated ) );
363 }
364 
365 
367 {
368  int hintWidth = !_caption->isHidden() ? _caption->sizeHint().width() : 0;
369  return max( 80, hintWidth );
370 }
371 
372 
374 {
375  int hintHeight = !_caption->isHidden() ? _caption->sizeHint().height() : 0;
376 
377  // 80 is an arbitrary value. Use a MinSize or MinHeight widget to set a
378  // size that is useful for the application.
379 
380  return 80 + hintHeight;
381 }
382 
383 
384 void YQTree::setSize( int newWidth, int newHeight )
385 {
386  resize( newWidth, newHeight );
387 }
388 
389 
390 void YQTree::setEnabled( bool enabled )
391 {
392  _caption->setEnabled( enabled );
393  _qt_treeWidget->setEnabled( enabled );
394  YWidget::setEnabled( enabled );
395 }
396 
397 
399 {
400  _qt_treeWidget->setFocus();
401 
402  return true;
403 }
404 
405 
406 void YQTree::slotContextMenu ( const QPoint & pos )
407 {
408  if ( ! _qt_treeWidget || ! _qt_treeWidget->viewport() )
409  return;
410 
411  YQUI::yqApp()->setContextMenuPos( _qt_treeWidget->viewport()->mapToGlobal( pos ) );
412  if ( notifyContextMenu() )
413  YQUI::ui()->sendEvent( new YWidgetEvent( this, YEvent::ContextMenuActivated ) );
414 }
415 
416 
417 YTreeItem *
419 {
420 
421  QTreeWidgetItem * currentQItem = _qt_treeWidget->currentItem();
422 
423  if ( currentQItem )
424  {
425  YQTreeItem * item = dynamic_cast<YQTreeItem *> (currentQItem);
426 
427  if ( item )
428  return item->origItem();
429  }
430 
431  return 0;
432 }
433 
434 
435 
436 /*============================================================================*/
437 
438 
439 
441  QTreeWidget * listView,
442  YTreeItem * orig,
443  int serial )
444  : QTreeWidgetItem( listView )
445 {
446  init( tree, orig, serial );
447 
448 #if VERBOSE_TREE_ITEMS
449  yuiDebug() << "Creating toplevel tree item \"" << orig->label() << "\"" << std::endl;
450 #endif
451 
452 }
453 
454 
456  YQTreeItem * parentItem,
457  YTreeItem * orig,
458  int serial )
459  : QTreeWidgetItem( parentItem )
460 {
461  init( tree, orig, serial );
462 #if VERBOSE_TREE_ITEMS
463  yuiDebug() << "Creating tree item \"" << orig->label()
464  << "\" as child of \"" << parentItem->origItem()->label() << "\""
465  << std::endl;
466 
467 #endif
468 
469 
470 
471 }
472 
473 
474 void YQTreeItem::init( YQTree * tree,
475  YTreeItem * orig,
476  int serial )
477 {
478  YUI_CHECK_PTR( tree );
479  YUI_CHECK_PTR( orig );
480 
481  _tree = tree;
482  _serialNo = serial;
483  _origItem = orig;
484 
485  _origItem->setData( this );
486 
487  setText( 0, fromUTF8 ( _origItem->label() ) );
488  setOpen( _origItem->isOpen() );
489 
490  if ( _origItem->hasIconName() )
491  {
492  string iconName = _tree->iconFullPath( _origItem );
493  QPixmap icon( iconName.c_str() );
494 
495  if ( icon.isNull() )
496  yuiWarning() << "Can't load icon " << iconName << std::endl;
497  else
498  setData( 0, Qt::DecorationRole, icon );
499  }
500 
501  if ( tree->hasMultiSelection() )
502  setCheckState(0,Qt::Unchecked);
503 }
504 
505 
506 void
508 {
509  QTreeWidgetItem::setExpanded( open );
510  _origItem->setOpen( open );
511 }
512 
513 
514 
515 QString
516 YQTreeItem::key( int column, bool ascending ) const
517 {
518  /*
519  * Sorting key for QListView internal sorting:
520  *
521  * Always sort tree items by insertion order. The tree widget cannot
522  * maintain a meaningful sorting order of its own: All it could do is sort
523  * by names (ASCII sort). Better let the application handle this.
524  */
525 
526  QString strKey;
527  strKey.sprintf( "%08d", _serialNo );
528 
529  return strKey;
530 }
531 
532 
533 #include "YQTree.moc"