libyui-qt  2.49.2
YQMultiSelectionBox.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: YQMultiSelectionBox.cc
20 
21  Author: Stefan Hundhammer <sh@suse.de>
22 
23 /-*/
24 
25 #include <limits.h>
26 #include <QString>
27 #include <QLabel>
28 #include <QVBoxLayout>
29 #include <QHeaderView>
30 #include <QDebug>
31 #define YUILogComponent "qt-ui"
32 #include <yui/YUILog.h>
33 
34 using std::max;
35 
36 #include "utf8.h"
37 #include "YQUI.h"
38 #include <yui/YEvent.h>
39 #include "YQMultiSelectionBox.h"
40 #include "YQSignalBlocker.h"
41 #include "YQWidgetCaption.h"
42 
43 #define DEFAULT_VISIBLE_LINES 5
44 #define SHRINKABLE_VISIBLE_LINES 2
45 
46 
48  const std::string & label )
49  : QFrame( (QWidget *) parent->widgetRep() )
50  , YMultiSelectionBox( parent, label )
51 {
52  QVBoxLayout* layout = new QVBoxLayout( this );
53  setLayout( layout );
54 
55  setWidgetRep( this );
56 
57  layout->setSpacing( YQWidgetSpacing );
58  layout->setMargin( YQWidgetMargin );
59 
60  _caption = new YQWidgetCaption( this, label );
61  YUI_CHECK_NEW( _caption );
62  layout->addWidget( _caption );
63 
64  _qt_listView = new QTreeWidget( this );
65  YUI_CHECK_NEW( _qt_listView );
66  layout->addWidget( _qt_listView );
67 
68  _qt_listView->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) );
69  _qt_listView->setHeaderLabel(""); // QListView doesn't have one single column by default!
70  _qt_listView->setSortingEnabled( false );
71 
72  _qt_listView->header()->hide();
73  _qt_listView->setRootIsDecorated ( false );
74  _caption->setBuddy( _qt_listView );
75 
76  // Very small default size if specified
77 
78  connect( _qt_listView, &pclass(_qt_listView)::itemSelectionChanged,
79  this, &pclass(this)::slotSelected );
80 
81  connect( this, &pclass(this)::valueChanged,
82  this, &pclass(this)::slotValueChanged );
83 
84  connect( _qt_listView, &pclass(_qt_listView)::itemChanged,
85  this, &pclass(this)::slotItemChanged );
86 }
87 
88 
90 {
91  // NOP
92 }
93 
94 
95 void
96 YQMultiSelectionBox::setLabel( const std::string & label )
97 {
98  _caption->setText( label );
99  YMultiSelectionBox::setLabel( label );
100 }
101 
102 
103 void
105 {
106  YQSignalBlocker sigBlocker( _qt_listView );
107  YMultiSelectionBox::addItem( yItem ); // will also check for NULL
108 
109  YQMultiSelectionBoxItem * msbItem = new YQMultiSelectionBoxItem( this, _qt_listView, yItem );
110 
111  YUI_CHECK_NEW( msbItem );
112 
113  // Take care of the item's check box
114 
115  msbItem->setCheckState(0, yItem->selected() ? Qt::Checked : Qt::Unchecked );
116 
117  // Take care of the QListView's keyboard focus
118 
119  if ( ! _qt_listView->currentItem() )
120  _qt_listView->setCurrentItem( msbItem );
121 }
122 
123 
124 void YQMultiSelectionBox::selectItem( YItem * yItem, bool selected )
125 {
126  YMultiSelectionBox::selectItem( yItem, selected );
127  YQMultiSelectionBoxItem * msbItem = findItem( yItem );
128 
129  if ( msbItem )
130  msbItem->setCheckState( 0, selected ? Qt::Checked : Qt::Unchecked );
131 }
132 
133 
134 void
136 {
137  YQSignalBlocker sigBlocker( _qt_listView );
138  YMultiSelectionBox::deselectAllItems();
139 
140  QTreeWidgetItemIterator it( _qt_listView );
141 
142  while ( *it )
143  {
144  YQMultiSelectionBoxItem * item = dynamic_cast<YQMultiSelectionBoxItem *> (*it);
145 
146  if ( item )
147  item->setCheckState(0, Qt::Unchecked);
148 
149  ++it;
150  }
151 }
152 
153 
154 void
156 {
157  YQSignalBlocker sigBlocker( _qt_listView );
158 
159  YMultiSelectionBox::deleteAllItems();
160  _qt_listView->clear();
161 }
162 
163 
164 YItem *
166 {
167  // QListView::currentItem() is very similar, but not exactly the same as
168  // QListView::selectedItem(), and it is NOT to be confused with an item's
169  // "selected" state in a YQMultiSelectionBox (the item's check box):
170  //
171  // QListView::currentItem() is the item that currently has the keyboard
172  // focus. By default, it is displayed with a faint dotted outline.
173  //
174  // QListView::selectedItem() is the item that is selected in the QListView
175  // widget. It is displayed in a very visible way with inverted colors
176  // (typically blue backround). If there is a selected item, it is also the
177  // current item. if there is no selected item, there might still be a
178  // current item, though.
179  //
180  // The Y(Q)MultiSelectionBox item's "selected" state is completely
181  // independent of all this: It only depends on the item's check
182  // box. QListView::selectedItem() and QListView::currentItem() are just
183  // mechanisms for keyboard navigation to show the user which item's check
184  // box will be toggled when he hits the space bar.
185  //
186  // For the purpose of this function, QListView::currentItem() is the
187  // minimum requirement.
188 
189  QTreeWidgetItem * currentQItem = _qt_listView->currentItem();
190 
191  if ( currentQItem )
192  {
193  YQMultiSelectionBoxItem * item = dynamic_cast<YQMultiSelectionBoxItem *> (currentQItem);
194 
195  if ( item )
196  return item->yItem();
197  }
198 
199  return 0;
200 }
201 
202 
203 void
205 {
206  // See also explanations about QListView::currentItem() vs.
207  // QListView::selectedItem() above
208  //
209  // This function uses QListView::selectedItem() for better visibility.
210  // This implicitly also changes QListView::currentItem().
211 
212  YQSignalBlocker sigBlocker( _qt_listView );
213 
214  if ( ! yItem )
215  {
216  _qt_listView->clearSelection();
217  }
218  else
219  {
220  YQMultiSelectionBoxItem * msbItem = findItem( yItem );
221 
222  if ( msbItem )
223  _qt_listView->setCurrentItem( msbItem );
224 
225  // This does NOT change the item's check box!
226  // (see explanations in YQMultiSelectionBox::currentItem() avove)
227  }
228 }
229 
230 
231 void
233 {
234  _caption->setEnabled( enabled );
235  _qt_listView->setEnabled( enabled );
236  //_qt_listView->triggerUpdate();
237  YWidget::setEnabled( enabled );
238 }
239 
240 
242 {
243  int hintWidth = (!_caption->isHidden()) ?
244  _caption->sizeHint().width() + frameWidth() : 0;
245 
246  return max( 80, hintWidth );
247 }
248 
249 
251 {
252  int hintHeight = (!_caption->isHidden()) ? _caption->sizeHint().height() : 0;
253  int visibleLines = shrinkable() ? SHRINKABLE_VISIBLE_LINES : DEFAULT_VISIBLE_LINES;
254  hintHeight += visibleLines * _qt_listView->fontMetrics().lineSpacing();
255  hintHeight += _qt_listView->frameWidth() * 2;
256 
257  return max( 80, hintHeight );
258 }
259 
260 
261 void
262 YQMultiSelectionBox::setSize( int newWidth, int newHeight )
263 {
264  resize( newWidth, newHeight );
265 }
266 
267 
268 bool
270 {
271  _qt_listView->setFocus();
272 
273  return true;
274 }
275 
276 
277 void
279 {
280  if ( notify() )
281  {
282  if ( ! YQUI::ui()->eventPendingFor( this ) )
283  {
284  // Avoid overwriting a (more important) ValueChanged event with a SelectionChanged event
285 
286  YQUI::ui()->sendEvent( new YWidgetEvent( this, YEvent::SelectionChanged ) );
287  }
288  }
289 }
290 
291 
292 void
294 {
295  if ( notify() )
296  YQUI::ui()->sendEvent( new YWidgetEvent( this, YEvent::ValueChanged ) );
297 }
298 
299 
300 void
301 YQMultiSelectionBox::slotItemChanged ( QTreeWidgetItem * _item, int )
302 {
303  YQMultiSelectionBoxItem * item = dynamic_cast<YQMultiSelectionBoxItem *> (_item);
304  bool selected = item->checkState( 0 );
305  item->yItem()->setSelected( selected );
306  emit valueChanged();
307 }
308 
310 YQMultiSelectionBox::findItem( YItem * wantedItem )
311 {
312  // FIXME: Don't search through all items, use the YItem::data() pointer instead
313  QTreeWidgetItemIterator it( _qt_listView );
314 
315  while ( *it )
316  {
317  YQMultiSelectionBoxItem * item = dynamic_cast<YQMultiSelectionBoxItem *> (*it);
318 
319  if ( item && item->yItem() == wantedItem )
320  return item;
321 
322  ++it;
323  }
324 
325  return 0;
326 }
327 
328 
330 
331 
332 
334  QTreeWidget * listView,
335  YItem * yItem )
336  : QTreeWidgetItem( listView )
337  , _yItem( yItem )
338  , _multiSelectionBox( parent )
339 {
340  YUI_CHECK_PTR( yItem );
341  setFlags( Qt::ItemIsUserCheckable | Qt::ItemIsEnabled );
342  setText(0, fromUTF8( yItem->label() ));
343  setCheckState( 0, Qt::Unchecked );
344  _serial = _item_count++;
345 
346  if ( yItem->hasIconName() )
347  {
348  // _table is checked against 0 in the constructor
349 
350  string iconName = parent->iconFullPath( yItem->iconName() );
351  QPixmap icon = QPixmap( iconName.c_str() );
352 
353  if ( icon.isNull() )
354  yuiWarning() << "Can't load icon " << iconName << std::endl;
355  else
356  setIcon( 0 /* column */, icon );
357  }
358  /*
359  else // No pixmap name
360  {
361  if ( ! data( column, Qt::DecorationRole ).isNull() ) // Was there a pixmap before?
362  {
363  setData( column, Qt::DecorationRole, QPixmap() ); // Set empty pixmap
364  }
365  }
366  */
367 }
368 
369 #include "YQMultiSelectionBox.moc"
void slotValueChanged()
Send ValueChanged event if opt(notify) is set.
Helper class to block Qt signals for QWidgets or QObjects as long as this object exists.
virtual int preferredWidth()
Preferred width of the widget.
static int _item_count
The next serial number to use.
virtual void setText(const std::string &newText)
Change the text and handle visibility: If the new text is empty, hide this widget.
virtual int preferredHeight()
Preferred height of the widget.
YQMultiSelectionBox(YWidget *parent, const std::string &label)
Constructor.
virtual void deleteAllItems()
Delete all items.
YQMultiSelectionBoxItem(YQMultiSelectionBox *parent, QTreeWidget *listView, YItem *yItem)
Constructor.
virtual YItem * currentItem()
Return the the item that currently has the keyboard focus or 0 if no item currently has the keyboard ...
virtual void setSize(int newWidth, int newHeight)
Set the new size of the widget.
void valueChanged()
Emitted upon when an item changes its state.
YItem * yItem() const
Return the corresponding YItem.
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:468
virtual void setLabel(const std::string &label)
Change the label text.
virtual void deselectAllItems()
Deselect all items.
virtual void setEnabled(bool enabled)
Set enabled/disabled state.
YQMultiSelectionBoxItem * findItem(YItem *item)
Find the counterpart of &#39;item&#39;.
virtual void setCurrentItem(YItem *item)
Set the keyboard focus to the specified item.
Helper class for captions (labels) above a widget: Takes care of hiding itself when its text is empty...
virtual bool setKeyboardFocus()
Accept the keyboard focus.
virtual void selectItem(YItem *item, bool selected=true)
Select or deselect an item.
void slotSelected()
Send SelectionChanged event if opt(notify) is set.
~YQMultiSelectionBox()
Destructor.
static YQUI * ui()
Access the global Qt-UI.
Definition: YQUI.h:80
virtual void addItem(YItem *item)
Add an item.