libyui-qt  2.52.2
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 }
Helper class to block Qt signals for QWidgets or QObjects as long as this object exists.
virtual void activate()
Activate the item selected in the tree.
Definition: YQTree.cc:438
static YQApplication * yqApp()
Return the global YApplication object as YQApplication.
Definition: YQUI.cc:268
void slotItemChanged(QTreeWidgetItem *item)
Propagate a tree item change.
Definition: YQTree.cc:298
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:369
virtual void setOpen(bool open)
Open this item.
Definition: YQTree.cc:513
virtual void rebuildTree()
Rebuild the displayed tree from the internally stored YTreeItems.
Definition: YQTree.cc:125
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
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 &#39;item&#39; 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 void setLabel(const std::string &label)
Change the label text.
Definition: YQTree.cc:118
void slotItemCollapsed(QTreeWidgetItem *item)
Propagate an "item collapsed" event to the underlying YTreeItem.
Definition: YQTree.cc:229
virtual void deselectAllItems()
Deselect all items.
Definition: YQTree.cc:240
QIcon loadIcon(const string &iconName) const
Load an icon.
Definition: YQUI.cc:708
virtual ~YQTree()
Destructor.
Definition: YQTree.cc:112
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:480
virtual void setSize(int newWidth, int newHeight)
Set the new size of the widget.
Definition: YQTree.cc:387
virtual void selectItem(YItem *item, bool selected=true)
Select or deselect an item.
Definition: YQTree.cc:162
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
QString key(int column, bool ascending) const
Sort key of this item.
Definition: YQTree.cc:521
void busyCursor()
Show mouse cursor indicating busy state.
Definition: YQUI.cc:562
void slotSelectionChanged()
Propagate a tree item selection.
Definition: YQTree.cc:344
virtual void deleteAllItems()
Delete all items.
Definition: YQTree.cc:266
virtual void setEnabled(bool enabled)
Set enabled/disbled state.
Definition: YQTree.cc:393
Helper class for captions (labels) above a widget: Takes care of hiding itself when its text is empty...
void slotActivated(QTreeWidgetItem *item)
Propagate a double click or pressing the space key on a tree item.
Definition: YQTree.cc:360
void normalCursor()
Show normal mouse cursor not indicating busy status.
Definition: YQUI.cc:568
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
static YQUI * ui()
Access the global Qt-UI.
Definition: YQUI.h:83
virtual int preferredHeight()
Preferred height of the widget.
Definition: YQTree.cc:376
virtual bool setKeyboardFocus()
Accept the keyboard focus.
Definition: YQTree.cc:401
void slotContextMenu(const QPoint &pos)
Propagate a context menu selection.
Definition: YQTree.cc:409