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