libyui-qt  2.46.1
 All Classes Functions Variables
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"