picking up branches/tmp/sh/qt4-port/, merging it with trunk
[duncan/yast2-qt4.git] / src / YQMultiSelectionBox.cc
1 /*---------------------------------------------------------------------\
2 |                                                                      |
3 |                      __   __    ____ _____ ____                      |
4 |                      \ \ / /_ _/ ___|_   _|___ \                     |
5 |                       \ V / _` \___ \ | |   __) |                    |
6 |                        | | (_| |___) || |  / __/                     |
7 |                        |_|\__,_|____/ |_| |_____|                    |
8 |                                                                      |
9 |                               core system                            |
10 |                                                        (C) SuSE GmbH |
11 \----------------------------------------------------------------------/
12
13   File:       YQMultiSelectionBox.cc
14
15   Author:     Stefan Hundhammer <sh@suse.de>
16
17 /-*/
18
19
20 #include <limits.h>
21 #include <qstring.h>
22 #include <qlabel.h>
23 #include <QVBoxLayout>
24 #include <q3header.h>
25 #define y2log_component "qt-ui"
26 #include <ycp/y2log.h>
27
28 using std::max;
29
30 #include "utf8.h"
31 #include "YQUI.h"
32 #include "YEvent.h"
33 #include "YQMultiSelectionBox.h"
34 #include "YQSignalBlocker.h"
35 #include "YQWidgetCaption.h"
36
37 #define DEFAULT_VISIBLE_LINES           5
38 #define SHRINKABLE_VISIBLE_LINES        2
39
40
41 YQMultiSelectionBox::YQMultiSelectionBox( YWidget *             parent,
42                                           const string &        label )
43     : QFrame( (QWidget *) parent->widgetRep() )
44     , YMultiSelectionBox( parent, label )
45 {
46     QVBoxLayout* layout = new QVBoxLayout( this );
47     setLayout( layout );
48
49     setWidgetRep( this );
50
51     layout->setSpacing( YQWidgetSpacing );
52     layout->setMargin( YQWidgetMargin );
53
54     _caption = new YQWidgetCaption( this, label );
55     YUI_CHECK_NEW( _caption );
56     layout->addWidget( _caption );
57
58     _qt_listView = new Q3ListView( this );
59     YUI_CHECK_NEW( _qt_listView );
60     layout->addWidget( _qt_listView );
61
62     _qt_listView->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) );
63     _qt_listView->addColumn( "" );      // QListView doesn't have one single column by default!
64     _qt_listView->setSorting( 0, false );
65     _qt_listView->header()->setStretchEnabled( true );
66     _qt_listView->header()->hide();
67     _caption->setBuddy( _qt_listView );
68
69     // Very small default size if specified
70
71     connect( _qt_listView,      SIGNAL( selectionChanged()      ),
72              this,              SLOT  ( slotSelected()          ) );
73
74     connect( this,              SIGNAL( valueChanged()          ),
75              this,              SLOT  ( slotValueChanged()      ) );
76 }
77
78
79 YQMultiSelectionBox::~YQMultiSelectionBox()
80 {
81     // NOP
82 }
83
84
85 void
86 YQMultiSelectionBox::setLabel( const string & label )
87 {
88     _caption->setText( label );
89     YMultiSelectionBox::setLabel( label );
90 }
91
92
93 void
94 YQMultiSelectionBox::addItem( YItem * yItem )
95 {
96     YQSignalBlocker sigBlocker( _qt_listView );
97     YMultiSelectionBox::addItem( yItem ); // will also check for NULL
98
99     YQMultiSelectionBoxItem * msbItem =
100         new YQMultiSelectionBoxItem( this, _qt_listView, yItem );
101
102     YUI_CHECK_NEW( msbItem );
103
104     // Take care of the item's check box
105
106     if ( yItem->selected() )
107          msbItem->setOn( true );
108
109
110     // Take care of the QListView's keyboard focus
111
112     if ( ! _qt_listView->selectedItem() )
113         _qt_listView->setSelected( msbItem, true );
114 }
115
116
117 void YQMultiSelectionBox::selectItem( YItem * yItem, bool selected )
118 {
119     YMultiSelectionBox::selectItem( yItem, selected );
120     YQMultiSelectionBoxItem * msbItem = findItem( yItem );
121
122     if ( msbItem )
123         msbItem->setOn( selected );
124 }
125
126
127 void
128 YQMultiSelectionBox::deselectAllItems()
129 {
130     YQSignalBlocker sigBlocker( _qt_listView );
131     YMultiSelectionBox::deselectAllItems();
132
133     Q3ListViewItemIterator it( _qt_listView );
134
135     while ( *it )
136     {
137         YQMultiSelectionBoxItem * item = dynamic_cast<YQMultiSelectionBoxItem *> (*it);
138
139         if ( item )
140             item->setOn( false );
141
142         ++it;
143     }
144 }
145
146
147 void
148 YQMultiSelectionBox::deleteAllItems()
149 {
150     YQSignalBlocker sigBlocker( _qt_listView );
151
152     YMultiSelectionBox::deleteAllItems();
153     _qt_listView->clear();
154 }
155
156
157 YItem *
158 YQMultiSelectionBox::currentItem()
159 {
160     // QListView::currentItem() is very similar, but not exactly the same as
161     // QListView::selectedItem(), and it is NOT to be confused with an item's
162     // "selected" state in a YQMultiSelectionBox (the item's check box):
163     //
164     // QListView::currentItem() is the item that currently has the keyboard
165     // focus. By default, it is displayed with a faint dotted outline.
166     //
167     // QListView::selectedItem() is the item that is selected in the QListView
168     // widget. It is displayed a very visible with inverted colors (typically
169     // blue backround). If there is a selected item, it is also the current
170     // item. if there is no selected item, there might still be a current item,
171     // though.
172     //
173     // The Y(Q)MultiSelectionBox item's "selected" state is completely
174     // independent of all this: It only depends on the item's check
175     // box. QListView::selectedItem() and QListView::currentItem() are just
176     // mechanisms for keyboard navigation to show the user which item's check
177     // box will be toggled when he hits the space bar.
178     //
179     // For the purpose of this function, QListView::currentItem() is the
180     // minimum requirement.
181
182     Q3ListViewItem * currentQItem = _qt_listView->currentItem();
183
184     if ( currentQItem )
185     {
186         YQMultiSelectionBoxItem * item = dynamic_cast<YQMultiSelectionBoxItem *> (currentQItem);
187
188         if ( item )
189             return item->yItem();
190     }
191
192     return 0;
193 }
194
195
196 void
197 YQMultiSelectionBox::setCurrentItem( YItem * yItem )
198 {
199     // See also explanations about QListView::currentItem() vs.
200     // QListView::selectedItem() above
201     //
202     // This function uses QListView::selectedItem() for better visibility.
203     // This implicitly also changes QListView::currentItem().
204
205     YQSignalBlocker sigBlocker( _qt_listView );
206
207     if ( ! yItem )
208     {
209         _qt_listView->clearSelection();
210     }
211     else
212     {
213         YQMultiSelectionBoxItem * msbItem = findItem( yItem );
214
215         if ( msbItem )
216             _qt_listView->setSelected( msbItem, true );
217
218         // This does NOT change the item's check box!
219         // (see explanations in YQMultiSelectionBox::currentItem() avove)
220     }
221 }
222
223
224 void
225 YQMultiSelectionBox::setEnabled( bool enabled )
226 {
227     _caption->setEnabled( enabled );
228     _qt_listView->setEnabled( enabled );
229     _qt_listView->triggerUpdate();
230     YWidget::setEnabled( enabled );
231 }
232
233
234 int YQMultiSelectionBox::preferredWidth()
235 {
236     int hintWidth = _caption->isShown() ?
237         _caption->sizeHint().width() + frameWidth() : 0;
238
239     return max( 80, hintWidth );
240 }
241
242
243 int YQMultiSelectionBox::preferredHeight()
244 {
245     int hintHeight       = _caption->isShown() ? _caption->sizeHint().height() : 0;
246     int visibleLines     = shrinkable() ? SHRINKABLE_VISIBLE_LINES : DEFAULT_VISIBLE_LINES;
247     hintHeight          += visibleLines * _qt_listView->fontMetrics().lineSpacing();
248     hintHeight          += _qt_listView->frameWidth() * 2;
249
250     return max( 80, hintHeight );
251 }
252
253
254 void
255 YQMultiSelectionBox::setSize( int newWidth, int newHeight )
256 {
257     resize( newWidth, newHeight );
258 }
259
260
261 bool
262 YQMultiSelectionBox::setKeyboardFocus()
263 {
264     _qt_listView->setFocus();
265
266     return true;
267 }
268
269
270 void
271 YQMultiSelectionBox::slotSelected()
272 {
273     if ( notify() )
274     {
275         if ( ! YQUI::ui()->eventPendingFor( this ) )
276         {
277             // Avoid overwriting a (more important) ValueChanged event with a SelectionChanged event
278
279             YQUI::ui()->sendEvent( new YWidgetEvent( this, YEvent::SelectionChanged ) );
280         }
281     }
282 }
283
284
285 void
286 YQMultiSelectionBox::slotValueChanged()
287 {
288     if ( notify() )
289         YQUI::ui()->sendEvent( new YWidgetEvent( this, YEvent::ValueChanged ) );
290 }
291
292
293 void
294 YQMultiSelectionBox::sendValueChanged()
295 {
296     emit valueChanged();
297 }
298
299
300 YQMultiSelectionBoxItem *
301 YQMultiSelectionBox::findItem( YItem * wantedItem )
302 {
303     // FIXME: Don't search through all items, use the YItem::data() pointer instead
304
305     Q3ListViewItemIterator it( _qt_listView );
306
307     while ( *it )
308     {
309         YQMultiSelectionBoxItem * item = dynamic_cast<YQMultiSelectionBoxItem *> (*it);
310
311         if ( item && item->yItem() == wantedItem )
312             return item;
313
314         ++it;
315     }
316
317     return 0;
318 }
319
320
321
322
323
324 int YQMultiSelectionBoxItem::_item_count = 0;
325
326
327
328 YQMultiSelectionBoxItem::YQMultiSelectionBoxItem( YQMultiSelectionBox * parent,
329                                                   Q3ListView *          listView,
330                                                   YItem *               yItem )
331     : Q3CheckListItem( listView, fromUTF8( yItem->label() ), Q3CheckListItem::CheckBox )
332     , _yItem( yItem )
333     , _multiSelectionBox( parent )
334 {
335     YUI_CHECK_PTR( yItem );
336
337     _serial = _item_count++;
338 }
339
340
341 void
342 YQMultiSelectionBoxItem::stateChange( bool newState )
343 {
344     _yItem->setSelected( newState );
345     _multiSelectionBox->sendValueChanged();
346     Q3CheckListItem::stateChange( newState );
347 }
348
349
350 QString
351 YQMultiSelectionBoxItem::key( int, bool ) const
352 {
353     /*
354      * Return a sort key that depends on creation (i.e. insertion) order.
355      */
356
357     static QString sortKey;
358     sortKey.sprintf( "%010d", INT_MAX - _serial );
359
360     return sortKey;
361 }
362
363
364 #include "YQMultiSelectionBox.moc"