libyui-qt  2.46.13
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 <QHeaderView>
26 #include <QLabel>
27 #include <QTreeWidget>
28 #include <QVBoxLayout>
29 #include <QString>
30 #include <QPixmap>
31 #define YUILogComponent "qt-ui"
32 #include <yui/YUILog.h>
33 
34 using std::min;
35 using std::max;
36 
37 #include "YQUI.h"
38 #include <yui/YEvent.h>
39 #include "utf8.h"
40 #include "YQTree.h"
41 #include <yui/YTreeItem.h>
42 #include "YQSignalBlocker.h"
43 #include "YQWidgetCaption.h"
44 #include "YQApplication.h"
45 
46 
47 #define VERBOSE_TREE_ITEMS 0
48 
49 
50 YQTree::YQTree( YWidget * parent, const std::string & label, bool multiSelectionMode, bool recursiveSelectionMode )
51  : QFrame( (QWidget *) parent->widgetRep() )
52  , YTree( parent, label, multiSelectionMode, recursiveSelectionMode )
53 {
54  QVBoxLayout* layout = new QVBoxLayout( this );
55  setLayout( layout );
56 
57  setWidgetRep( this );
58 
59  layout->setSpacing( YQWidgetSpacing );
60  layout->setMargin ( YQWidgetMargin );
61 
62  _nextSerialNo = 0;
63 
64  _caption = new YQWidgetCaption( this, label );
65  YUI_CHECK_NEW( _caption );
66  layout->addWidget( _caption );
67 
68  _qt_treeWidget = new QTreeWidget( this );
69  YUI_CHECK_NEW( _qt_treeWidget );
70  layout->addWidget( _qt_treeWidget );
71 
72  // _qt_treeWidget->setHeaderLabel("");
73  // _qt_treeWidget->addColumn( "" );
74  _qt_treeWidget->header()->hide();
75  // _qt_treeWidget->setHeader(0L);
76  _qt_treeWidget->setRootIsDecorated ( true );
77 
78  _qt_treeWidget->setContextMenuPolicy( Qt::CustomContextMenu );
79 
80  _caption->setBuddy ( _qt_treeWidget );
81 
82  connect( _qt_treeWidget, &pclass(_qt_treeWidget)::itemSelectionChanged,
83  this, &pclass(this)::slotSelectionChanged );
84 
85  connect( _qt_treeWidget, &pclass(_qt_treeWidget)::itemClicked,
86  this, &pclass(this)::slotItemClicked );
87 
88 // connect( _qt_treeWidget, &pclass(_qt_treeWidget)::itemChanged,
89 // this, &pclass(this)::slotItemChanged );
90 
91  connect( _qt_treeWidget, &pclass(_qt_treeWidget)::itemChanged,
92  this, &pclass(this)::slotItemChanged );
93 
94  connect( _qt_treeWidget, &pclass(_qt_treeWidget)::itemDoubleClicked,
95  this, &pclass(this)::slotActivated );
96 
97  connect( _qt_treeWidget, &pclass(_qt_treeWidget)::itemExpanded,
98  this, &pclass(this)::slotItemExpanded );
99 
100  connect( _qt_treeWidget, &pclass(_qt_treeWidget)::itemCollapsed,
101  this, &pclass(this)::slotItemCollapsed );
102 
103  connect( _qt_treeWidget, &pclass(_qt_treeWidget)::customContextMenuRequested,
104  this, &pclass(this)::slotContextMenu );
105 
106 }
107 
108 
110 {
111  // NOP
112 }
113 
114 
115 void YQTree::setLabel( const std::string & label )
116 {
117  _caption->setText( label );
118  YTree::setLabel( label );
119 }
120 
121 
123 {
124  YQSignalBlocker sigBlocker( _qt_treeWidget );
125  _qt_treeWidget->clear();
126 
127  buildDisplayTree( 0, itemsBegin(), itemsEnd() );
128  _qt_treeWidget->resizeColumnToContents( 0 );
129 }
130 
131 
132 void YQTree::buildDisplayTree( YQTreeItem * parentItem, YItemIterator begin, YItemIterator end )
133 {
134  for ( YItemIterator it = begin; it < end; ++it )
135  {
136  YTreeItem * orig = dynamic_cast<YTreeItem *> (*it);
137  YUI_CHECK_PTR( orig );
138 
139  YQTreeItem * clone;
140 
141  if ( parentItem )
142  clone = new YQTreeItem( this, parentItem, orig, _nextSerialNo++ );
143  else
144  clone = new YQTreeItem( this, _qt_treeWidget, orig, _nextSerialNo++ );
145 
146  YUI_CHECK_NEW( clone );
147 
148  if (orig->selected())
149  {
150  selectItem(clone);
151  }
152 
153  if ( orig->hasChildren() )
154  buildDisplayTree( clone, orig->childrenBegin(), orig->childrenEnd() );
155  }
156 }
157 
158 
159 void YQTree::selectItem( YItem * yItem, bool selected )
160 {
161  YQSignalBlocker sigBlocker( _qt_treeWidget );
162 
163  // yuiDebug() << "Selecting item \"" << yItem->label() << "\" " << std::boolalpha << selected << std::endl;
164  YTreeItem * treeItem = dynamic_cast<YTreeItem *> (yItem);
165  YUI_CHECK_PTR( treeItem );
166 
167  YQTreeItem * yqTreeItem = (YQTreeItem *) treeItem->data();
168  YUI_CHECK_PTR( yqTreeItem );
169 
170 
171  if ( selected )
172  {
173  selectItem( yqTreeItem );
174  }
175  else if ( yqTreeItem == _qt_treeWidget->currentItem() )
176  {
178  }
179 }
180 
181 
183 {
184  if ( item )
185  {
186  YQSignalBlocker sigBlocker( _qt_treeWidget );
187 
188  _qt_treeWidget->setCurrentItem( item );
189  item->setSelected( true );
190 
191  if ( hasMultiSelection() )
192  item->setCheckState( 0, Qt::Checked );
193 
194  if ( item->parent() )
195  openBranch( (YQTreeItem *) item->parent() );
196 
197  YTree::selectItem( item->origItem(), true );
198 
199  // yuiDebug() << "selected item: \"" << item->origItem()->label() << "\"" << std::endl;
200 
201  }
202 }
203 
204 
206 {
207  while ( item )
208  {
209  item->setOpen( true ); // Takes care of origItem()->setOpen()
210  item = (YQTreeItem *) item->parent();
211  }
212 }
213 
214 void YQTree::slotItemExpanded( QTreeWidgetItem * qItem )
215 {
216  YQTreeItem * item = dynamic_cast<YQTreeItem *> (qItem);
217 
218  if ( item )
219  item->setOpen( true );
220 
221  _qt_treeWidget->resizeColumnToContents( 0 );
222 }
223 
224 
225 void YQTree::slotItemCollapsed( QTreeWidgetItem * qItem )
226 {
227  YQTreeItem * item = dynamic_cast<YQTreeItem *> (qItem);
228 
229  if ( item )
230  item->setOpen( false );
231 
232  _qt_treeWidget->resizeColumnToContents( 0 );
233 }
234 
235 
237 {
238  YQSignalBlocker sigBlocker( _qt_treeWidget );
239 
240  YTree::deselectAllItems();
241  _qt_treeWidget->clearSelection();
242 
243  if ( hasMultiSelection() )
244  {
245  QTreeWidgetItemIterator it( _qt_treeWidget);
246  while (*it)
247  {
248  YQTreeItem * treeItem = dynamic_cast<YQTreeItem *> (*it);
249 
250  if ( treeItem )
251  {
252  treeItem->setCheckState( 0, Qt::Unchecked );
253  treeItem->origItem()->setSelected( false );
254  }
255  ++it;
256  }
257  }
258 
259 }
260 
261 
263 {
264  YQSignalBlocker sigBlocker( _qt_treeWidget );
265 
266  _qt_treeWidget->clear();
267  YTree::deleteAllItems();
268 }
269 
270 
271 void YQTree::selectItem(QTreeWidgetItem * item, bool selected, bool recursive)
272 {
273 
274  YQTreeItem * treeItem = dynamic_cast<YQTreeItem *> (item);
275 
276  if ( ! treeItem )
277  return;
278 
279  YSelectionWidget::selectItem( treeItem->origItem(), selected );
280 
281  if ( recursive )
282  {
283  for (int i=0; i < item->childCount(); ++i)
284  {
285  QTreeWidgetItem* child = item->child(i);
286  child->setCheckState(0, ( selected )? Qt::Checked : Qt::Unchecked );
287  YQTree::selectItem( child, selected, recursive );
288  }
289  }
290 
291 }
292 
293 
294 void YQTree::slotItemChanged( QTreeWidgetItem * item )
295 {
296 
297  YQSignalBlocker sigBlocker( _qt_treeWidget );
298 
299  if ( hasMultiSelection() )
300  {
301  if ( recursiveSelection() )
302  YQUI::ui()->busyCursor();
303 
304  if ( item->checkState(0) == Qt::Checked )
305  YQTree::selectItem( item, true, recursiveSelection() );
306  else
307  YQTree::selectItem( item, false, recursiveSelection() );
308 
309 
310  if ( recursiveSelection() )
311  YQUI::ui()->normalCursor();
312 
313  }
314  else
315  {
316  QList<QTreeWidgetItem *> items = _qt_treeWidget->selectedItems ();
317 
318  if ( ! items.empty() )
319  {
320  QTreeWidgetItem *qItem = items.first();
321  selectItem( dynamic_cast<YQTreeItem *> (qItem) );
322  }
323  }
324 
325 
326 
327  if ( notify() && ! YQUI::ui()->eventPendingFor( this ) )
328  YQUI::ui()->sendEvent( new YWidgetEvent( this, YEvent::ValueChanged ) );
329 
330 
331 }
332 
333 
334 void YQTree::slotItemClicked( QTreeWidgetItem * item, int column )
335 {
336  _qt_treeWidget->setCurrentItem( item );
337 
338  if ( notify() && ! YQUI::ui()->eventPendingFor( this ) )
339  YQUI::ui()->sendEvent( new YWidgetEvent( this, YEvent::SelectionChanged ) );
340 }
341 
342 
343 
344 
346 {
347  QList<QTreeWidgetItem *> items = _qt_treeWidget->selectedItems ();
348 
349  if ( ! hasMultiSelection() && ! items.empty() )
350  {
351  QTreeWidgetItem *qItem = items.first();
352  selectItem( dynamic_cast<YQTreeItem *> (qItem) );
353  }
354 
355 
356  if ( notify() && ! YQUI::ui()->eventPendingFor( this ) )
357  YQUI::ui()->sendEvent( new YWidgetEvent( this, YEvent::SelectionChanged ) );
358 }
359 
360 
361 void YQTree::slotActivated( QTreeWidgetItem * qItem )
362 {
363  selectItem( dynamic_cast<YQTreeItem *> (qItem) );
364 
365  if ( notify() )
366  YQUI::ui()->sendEvent( new YWidgetEvent( this, YEvent::Activated ) );
367 }
368 
369 
371 {
372  int hintWidth = !_caption->isHidden() ? _caption->sizeHint().width() : 0;
373  return max( 80, hintWidth );
374 }
375 
376 
378 {
379  int hintHeight = !_caption->isHidden() ? _caption->sizeHint().height() : 0;
380 
381  // 80 is an arbitrary value. Use a MinSize or MinHeight widget to set a
382  // size that is useful for the application.
383 
384  return 80 + hintHeight;
385 }
386 
387 
388 void YQTree::setSize( int newWidth, int newHeight )
389 {
390  resize( newWidth, newHeight );
391 }
392 
393 
394 void YQTree::setEnabled( bool enabled )
395 {
396  _caption->setEnabled( enabled );
397  _qt_treeWidget->setEnabled( enabled );
398  YWidget::setEnabled( enabled );
399 }
400 
401 
403 {
404  _qt_treeWidget->setFocus();
405 
406  return true;
407 }
408 
409 
410 void YQTree::slotContextMenu ( const QPoint & pos )
411 {
412  if ( ! _qt_treeWidget || ! _qt_treeWidget->viewport() )
413  return;
414 
415  YQUI::yqApp()->setContextMenuPos( _qt_treeWidget->viewport()->mapToGlobal( pos ) );
416  if ( notifyContextMenu() )
417  YQUI::ui()->sendEvent( new YWidgetEvent( this, YEvent::ContextMenuActivated ) );
418 }
419 
420 
421 YTreeItem *
423 {
424 
425  QTreeWidgetItem * currentQItem = _qt_treeWidget->currentItem();
426 
427  if ( currentQItem )
428  {
429  YQTreeItem * item = dynamic_cast<YQTreeItem *> (currentQItem);
430 
431  if ( item )
432  return item->origItem();
433  }
434 
435  return 0;
436 }
437 
438 
439 
440 /*============================================================================*/
441 
442 
443 
445  QTreeWidget * listView,
446  YTreeItem * orig,
447  int serial )
448  : QTreeWidgetItem( listView )
449 {
450  init( tree, orig, serial );
451 
452 #if VERBOSE_TREE_ITEMS
453  yuiDebug() << "Creating toplevel tree item \"" << orig->label() << "\"" << std::endl;
454 #endif
455 
456 }
457 
458 
460  YQTreeItem * parentItem,
461  YTreeItem * orig,
462  int serial )
463  : QTreeWidgetItem( parentItem )
464 {
465  init( tree, orig, serial );
466 #if VERBOSE_TREE_ITEMS
467  yuiDebug() << "Creating tree item \"" << orig->label()
468  << "\" as child of \"" << parentItem->origItem()->label() << "\""
469  << std::endl;
470 
471 #endif
472 
473 
474 
475 }
476 
477 
478 void YQTreeItem::init( YQTree * tree,
479  YTreeItem * orig,
480  int serial )
481 {
482  YUI_CHECK_PTR( tree );
483  YUI_CHECK_PTR( orig );
484 
485  _tree = tree;
486  _serialNo = serial;
487  _origItem = orig;
488 
489  _origItem->setData( this );
490 
491  setText( 0, fromUTF8 ( _origItem->label() ) );
492  setOpen( _origItem->isOpen() );
493 
494  if ( _origItem->hasIconName() )
495  {
496  string iconName = _tree->iconFullPath( _origItem );
497  QPixmap icon( iconName.c_str() );
498 
499  if ( icon.isNull() )
500  yuiWarning() << "Can't load icon " << iconName << std::endl;
501  else
502  setData( 0, Qt::DecorationRole, icon );
503  }
504 
505  if ( tree->hasMultiSelection() )
506  setCheckState(0,Qt::Unchecked);
507 }
508 
509 
510 void
512 {
513  QTreeWidgetItem::setExpanded( open );
514  _origItem->setOpen( open );
515 }
516 
517 
518 
519 QString
520 YQTreeItem::key( int column, bool ascending ) const
521 {
522  /*
523  * Sorting key for QListView internal sorting:
524  *
525  * Always sort tree items by insertion order. The tree widget cannot
526  * maintain a meaningful sorting order of its own: All it could do is sort
527  * by names (ASCII sort). Better let the application handle this.
528  */
529 
530  QString strKey;
531  strKey.sprintf( "%08d", _serialNo );
532 
533  return strKey;
534 }
535 
536 
537 #include "YQTree.moc"
Helper class to block Qt signals for QWidgets or QObjects as long as this object exists.
static YQApplication * yqApp()
Return the global YApplication object as YQApplication.
Definition: YQUI.cc:284
void slotItemChanged(QTreeWidgetItem *item)
Propagate a tree item change.
Definition: YQTree.cc:294
virtual void setText(const std::string &newText)
Change the text and handle visibility: If the new text is empty, hide this widget.
virtual int preferredWidth()
Preferred width of the widget.
Definition: YQTree.cc:370
virtual void setOpen(bool open)
Open this item.
Definition: YQTree.cc:511
virtual void rebuildTree()
Rebuild the displayed tree from the internally stored YTreeItems.
Definition: YQTree.cc:122
virtual YTreeItem * currentItem()
Return the the item that currently has the keyboard focus or 0 if no item currently has the keyboard ...
Definition: YQTree.cc:422
YQTree(YWidget *parent, const std::string &label, bool multiSelection, bool recursiveSelection)
Constructor.
Definition: YQTree.cc:50
Definition: YQTree.h:38
void openBranch(YQTreeItem *item)
Open the branch of 'item' recursively to its toplevel item.
Definition: YQTree.cc:205
void slotItemExpanded(QTreeWidgetItem *item)
Propagate an "item expanded" event to the underlying YTreeItem.
Definition: YQTree.cc:214
virtual void setLabel(const std::string &label)
Change the label text.
Definition: YQTree.cc:115
void slotItemCollapsed(QTreeWidgetItem *item)
Propagate an "item collapsed" event to the underlying YTreeItem.
Definition: YQTree.cc:225
virtual void deselectAllItems()
Deselect all items.
Definition: YQTree.cc:236
virtual ~YQTree()
Destructor.
Definition: YQTree.cc:109
virtual void setContextMenuPos(QPoint contextMenuPos)
Sets the position of the context menu (in gloabl coordinates)
void sendEvent(YEvent *event)
Widget event handlers (slots) call this when an event occured that should be the answer to a UserInpu...
Definition: YQUI.cc:486
virtual void setSize(int newWidth, int newHeight)
Set the new size of the widget.
Definition: YQTree.cc:388
virtual void selectItem(YItem *item, bool selected=true)
Select or deselect an item.
Definition: YQTree.cc:159
YQTreeItem(YQTree *tree, QTreeWidget *parent, YTreeItem *origItem, int serial)
Constructor for a top level item.
Definition: YQTree.cc:444
YTreeItem * origItem()
Returns the original YTreeItem of which this item is a clone.
Definition: YQTree.h:243
void busyCursor()
Show mouse cursor indicating busy state.
Definition: YQUI.cc:568
void slotSelectionChanged()
Propagate a tree item selection.
Definition: YQTree.cc:345
virtual void deleteAllItems()
Delete all items.
Definition: YQTree.cc:262
virtual void setEnabled(bool enabled)
Set enabled/disbled state.
Definition: YQTree.cc:394
Helper class for captions (labels) above a widget: Takes care of hiding itself when its text is empty...
QString key(int column, bool ascending) const
Sort key of this item.
Definition: YQTree.cc:520
void slotActivated(QTreeWidgetItem *item)
Propagate a double click or pressing the space key on a tree item.
Definition: YQTree.cc:361
void normalCursor()
Show normal mouse cursor not indicating busy status.
Definition: YQUI.cc:574
void buildDisplayTree(YQTreeItem *parentItem, YItemIterator begin, YItemIterator end)
Build a tree of items that will be displayed (YQTreeItems) from the original items between iterators ...
Definition: YQTree.cc:132
static YQUI * ui()
Access the global Qt-UI.
Definition: YQUI.h:81
virtual int preferredHeight()
Preferred height of the widget.
Definition: YQTree.cc:377
virtual bool setKeyboardFocus()
Accept the keyboard focus.
Definition: YQTree.cc:402
void slotContextMenu(const QPoint &pos)
Propagate a context menu selection.
Definition: YQTree.cc:410