]> icculus.org git repositories - duncan/yast2-qt4.git/blob - src/QY2ListView.cc
clicking packages work! so the package selector is now
[duncan/yast2-qt4.git] / src / QY2ListView.cc
1 /*---------------------------------------------------------------------\
2 |                                                                      |
3 |                      __   __    ____ _____ ____                      |
4 |                      \ \ / /_ _/ ___|_   _|___ \                     |
5 |                       \ V / _` \___ \ | |   __) |                    |
6 |                        | | (_| |___) || |  / __/                     |
7 |                        |_|\__,_|____/ |_| |_____|                    |
8 |                                                                      |
9 |                               core system                            |
10 |                                                        (C) SuSE GmbH |
11 \----------------------------------------------------------------------/
12
13   File:       QY2ListView.cc
14
15   Author:     Stefan Hundhammer <sh@suse.de>
16
17   This is a pure Qt widget - it can be used independently of YaST2.
18
19 /-*/
20
21
22 #include <QPixmap>
23 #include <QHeaderView>
24 #include <QMouseEvent>
25 #include "QY2ListView.h"
26
27 #define y2log_component "qt-pkg"
28 #include <ycp/y2log.h>
29
30 QY2ListView::QY2ListView( QWidget * parent )
31     : QTreeWidget( parent )
32     , _mousePressedItem(0)
33     , _mousePressedCol( -1 )
34     , _mousePressedButton( Qt::NoButton )
35     , _sortByInsertionSequence( false )
36     , _nextSerial(0)
37     , _mouseButton1PressedInHeader( false )
38     , _finalSizeChangeExpected( false )
39 {
40     //FIXME QTreeWidget::setShowToolTips( false );
41     setRootIsDecorated(false);
42
43 #if FIXME_TOOLTIP
44     _toolTip = new QY2ListViewToolTip( this );
45 #endif
46
47      if ( header() )
48        header()->installEventFilter( this );
49
50 #if FIXME
51     connect( this,      SIGNAL( columnResized        ( int, int, int ) ),
52              this,      SLOT  ( columnWidthChanged( int, int, int ) ) );
53 #endif
54 }
55
56
57 QY2ListView::~QY2ListView()
58 {
59 #if FIXME_TOOLTIP
60     if ( _toolTip )
61         delete _toolTip;
62 #endif
63 }
64
65
66 void
67 QY2ListView::selectSomething()
68 {
69     QTreeWidgetItemIterator it( this );
70
71     while ( *it )
72     {
73         QY2ListViewItem * item = dynamic_cast<QY2ListViewItem *> (*it);
74
75         if ( item && (item->flags() & Qt::ItemIsSelectable) )
76         {
77             item->setSelected(true); // emits signal, too
78             return;
79         }
80
81         ++it;
82     }
83 }
84
85
86 void
87 QY2ListView::clear()
88 {
89     QTreeWidget::clear();
90     restoreColumnWidths();
91 }
92
93
94 void
95 QY2ListView::updateItemStates()
96 {
97     QTreeWidgetItemIterator it( this );
98
99     while ( *it )
100     {
101         QY2ListViewItem * item = dynamic_cast<QY2ListViewItem *> (*it);
102
103         if ( item )
104             item->updateStatus();
105
106         ++it;
107     }
108 }
109
110
111 void
112 QY2ListView::updateItemData()
113 {
114     QTreeWidgetItemIterator it( this );
115
116     while ( *it )
117     {
118         QY2ListViewItem * item = dynamic_cast<QY2ListViewItem *> (*it);
119
120         if ( item )
121             item->updateData();
122
123         ++it;
124     }
125 }
126
127
128 QString
129 QY2ListView::toolTip( QTreeWidgetItem * listViewItem, int column )
130 {
131     if ( ! listViewItem )
132         return QString::null;
133
134     QString text;
135
136 #if 0
137     text.sprintf( "Column %d:\n%s", column, (const char *) listViewItem->text( column ) );
138 #endif
139
140     // Try known item classes
141
142     QY2ListViewItem * item = dynamic_cast<QY2ListViewItem *> (listViewItem);
143
144     if ( item )
145         return item->toolTip( column );
146
147     QY2CheckListItem * checkListItem = dynamic_cast<QY2CheckListItem *> (listViewItem);
148
149     if ( checkListItem )
150         return checkListItem->toolTip( column );
151
152     return QString::null;
153 }
154
155
156 void
157 QY2ListView::saveColumnWidths()
158 {
159     _savedColumnWidth.clear();
160     _savedColumnWidth.reserve( columnCount() );
161
162     for ( int i = 0; i < columnCount(); i++ )
163     {
164         _savedColumnWidth.push_back( columnWidth(i) );
165     }
166 }
167
168
169 void
170 QY2ListView::restoreColumnWidths()
171 {
172     if ( _savedColumnWidth.size() != (unsigned) columnCount() )         // never manually resized
173     {
174         for ( int i = 0; i < columnCount(); i++ )               // use optimized column width
175             resizeColumnToContents(i);
176     }
177     else                                                // stored settings after manual resizing
178     {
179         for ( int i = 0; i < columnCount(); i++ )
180         {
181             setColumnWidth( i, _savedColumnWidth[ i ] ); // restore saved column width
182         }
183     }
184 }
185
186
187 void
188 QY2ListView::mousePressEvent( QMouseEvent * ev )
189 {
190     //y2internal("POS is %d %d", ev->pos().x(), ev->pos().y() );
191     QTreeWidgetItem * item = itemAt( ev->pos() );
192
193
194     if ( item && ( item->flags() & Qt::ItemIsEnabled ) )
195     {
196         _mousePressedItem       = item;
197                 _mousePressedCol        = header()->logicalIndexAt( ev->pos().x() );
198         _mousePressedButton     = ev->button();
199     }
200     else        // invalidate last click data
201     {
202         _mousePressedItem       = 0;
203         _mousePressedCol        = -1;
204         _mousePressedButton     = -1;
205     }
206
207     // Call base class method
208     QTreeWidget::mousePressEvent( ev );
209 }
210
211
212 void
213 QY2ListView::mouseReleaseEvent( QMouseEvent * ev )
214 {
215     //y2internal("REPOS is %d %d", ev->pos().x(), ev->pos().y() );
216     QTreeWidgetItem * item = itemAt( ev->pos() );
217
218     if ( item && ( item->flags() & Qt::ItemIsEnabled ) && item == _mousePressedItem )
219     {
220         int col = header()->logicalIndexAt( ev->pos().x() );
221         //y2internal("COL %d", col);
222         if ( item == _mousePressedItem  &&
223              col  == _mousePressedCol   &&
224              ev->button() == _mousePressedButton )
225         {
226             emit( columnClicked( ev->button(), item, col, ev->globalPos() ) );
227         }
228
229     }
230
231     // invalidate last click data
232
233     _mousePressedItem   = 0;
234     _mousePressedCol    = -1;
235     _mousePressedButton = Qt::NoButton;
236
237     // Call base class method
238     QTreeWidget::mouseReleaseEvent( ev );
239 }
240
241
242 void
243 QY2ListView::mouseDoubleClickEvent( QMouseEvent * ev )
244 {
245     QTreeWidgetItem * item = itemAt( mapToGlobal( ev->pos() ) );
246
247     if ( item && ( item->flags() & Qt::ItemIsEnabled ) )
248     {
249         int col = header()->logicalIndexAt( ev->pos().x() );
250         emit( columnDoubleClicked( ev->button(), (QY2ListViewItem *) item, col, ev->globalPos() ) );
251      }
252
253      // invalidate last click data
254
255      _mousePressedItem  = 0;
256      _mousePressedCol   = -1;
257      _mousePressedButton        = Qt::NoButton;
258
259      // Call base class method
260      QTreeWidget::mouseDoubleClickEvent( ev );
261 }
262
263
264 void
265 QY2ListView::columnWidthChanged( int, int, int )
266 {
267     // Workaround for Qt bug:
268     //
269     // QHeader sends a sizeChange() signal for every size change, not only (as
270     // documented) when the user resizes a header column manually. But we only
271     // want to record the column widths if the user explicitly did that, so
272     // ignore those signals if the mouse isn't pressed. There is also one final
273     // sizeChange() signal immediately after the user releases the mouse button.
274
275     if ( _mouseButton1PressedInHeader || _finalSizeChangeExpected )
276     {
277         saveColumnWidths();
278
279         // Consume that one sizeChange() signal that is sent immediately after
280         // the mouse button is released, but make sure to reset that flag only
281         // when appropriate.
282
283         if ( ! _mouseButton1PressedInHeader )
284             _finalSizeChangeExpected = false;
285     }
286 }
287
288
289 bool
290 QY2ListView::eventFilter( QObject * obj, QEvent * event )
291 {
292     if ( event && obj && obj == header() )
293     {
294         if ( event->type() == QEvent::MouseButtonPress )
295         {
296             QMouseEvent * mouseEvent = (QMouseEvent *) event;
297
298             if ( mouseEvent->button() == 1 )
299             {
300                 _mouseButton1PressedInHeader = true;
301                 _finalSizeChangeExpected     = false;
302             }
303         }
304         else if ( event->type() == QEvent::MouseButtonRelease )
305         {
306             QMouseEvent * mouseEvent = (QMouseEvent *) event;
307
308             if ( mouseEvent->button() == 1 )
309             {
310                 _finalSizeChangeExpected     = true;
311                 _mouseButton1PressedInHeader = false;
312             }
313         }
314     }
315
316     return QTreeWidget::eventFilter( obj, event );
317 }
318
319
320 QSize
321 QY2ListView::minimumSizeHint() const
322 {
323     return QSize( 0, 0 );
324 }
325
326
327 void
328 QY2ListView::setSortByInsertionSequence( bool sortByInsertionSequence )
329 {
330     _sortByInsertionSequence = sortByInsertionSequence;
331     //FIXME sort();
332     header()->setClickable( ! _sortByInsertionSequence );
333
334 }
335
336
337
338
339
340
341 QY2ListViewItem::QY2ListViewItem( QY2ListView *         parentListView,
342                                   const QString &       text )
343     : QTreeWidgetItem( parentListView, QStringList(text), 1)
344 {
345     _serial = parentListView->nextSerial();
346 }
347
348
349 QY2ListViewItem::QY2ListViewItem( QTreeWidgetItem *     parentItem,
350                                   const QString &       text )
351     : QTreeWidgetItem( parentItem, QStringList(text), 1 )
352 {
353     _serial = 0;
354
355     QY2ListView * parentListView = dynamic_cast<QY2ListView *> ( treeWidget() );
356
357     if ( parentListView )
358         _serial = parentListView->nextSerial();
359 }
360
361
362 QY2ListViewItem::~QY2ListViewItem()
363 {
364     // NOP
365 }
366
367 bool
368 QY2ListViewItem::operator< ( const QTreeWidgetItem & otherListViewItem ) const
369 {
370   bool sortByInsertionSequence = false;
371     QY2ListView * parentListView = dynamic_cast<QY2ListView *> (treeWidget());
372
373     if ( parentListView )
374         sortByInsertionSequence = parentListView->sortByInsertionSequence();
375
376     if ( sortByInsertionSequence )
377     {
378         const QY2ListViewItem * other = dynamic_cast<const QY2ListViewItem *> (&otherListViewItem);
379
380         if ( other )
381         {
382             return ( this->serial() < other->serial() );
383         }
384
385         // Still here? Try the other version: QY2CheckListItem.
386
387         const QY2CheckListItem * otherCheckListItem = dynamic_cast<const QY2CheckListItem *> (&otherListViewItem);
388
389         if ( otherCheckListItem )
390         {
391             return ( this->serial() < otherCheckListItem->serial() );
392         }
393
394     }
395
396     return QTreeWidgetItem::operator<(otherListViewItem);
397 }
398
399 // void
400 // QY2ListViewItem::paintCell( QPainter *               painter,
401 //                          const QColorGroup & colorGroup,
402 //                          int                 column,
403 //                          int                 width,
404 //                          int                 alignment )
405 // {
406 //     QColorGroup cg = colorGroup;
407 //
408 //     if ( _textColor.isValid() )              cg.setColor( QColorGroup::Text, _textColor );
409 //     if ( _backgroundColor.isValid() )        cg.setColor( QColorGroup::Base, _backgroundColor );
410 //
411 //     QTreeWidgetItem::paintCell( painter, cg, column, width, alignment );
412 // }
413
414
415 QY2CheckListItem::QY2CheckListItem( QY2ListView *               parentListView,
416                                     const QString &             text )
417     : QY2ListViewItem( parentListView, text)
418 {
419     setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
420     setCheckState(0, Qt::Unchecked);
421     _serial = parentListView->nextSerial();
422 }
423
424
425 QY2CheckListItem::QY2CheckListItem( QTreeWidgetItem *           parentItem,
426                                     const QString &             text )
427     : QY2ListViewItem( parentItem, text)
428 {
429     _serial = 0;
430     QY2ListView * parentListView = dynamic_cast<QY2ListView *> ( treeWidget() );
431
432     if ( parentListView )
433         _serial = parentListView->nextSerial();
434 }
435
436 QY2CheckListItem::~QY2CheckListItem()
437 {
438     // NOP
439 }
440
441
442 /*
443 void
444 QY2CheckListItem::paintCell( QPainter *                 painter,
445                              const QColorGroup &        colorGroup,
446                              int                        column,
447                              int                        width,
448                              int                        alignment )
449 {
450     QColorGroup cg = colorGroup;
451
452     if ( _textColor.isValid() )         cg.setColor( QColorGroup::Text, _textColor );
453     if ( _backgroundColor.isValid() )   cg.setColor( QColorGroup::Base, _backgroundColor );
454
455     QTreeWidgetItem::paintCell( painter, cg, column, width, alignment );
456 }
457 */
458
459 #if FIXME_TOOLTIP
460 void
461 QY2ListViewToolTip::maybeTip( const QPoint & pos )
462 {
463     Q3Header *       header        = _listView->header();
464     QTreeWidgetItem * item          = _listView->itemAt( pos );
465
466     if ( ! item )
467         return;
468
469     int x      = _listView->viewportToContents( pos ).x();
470     int column = header->sectionAt(x);
471     int indent = 0;
472
473     if ( column == 0 )
474     {
475         indent  =  item->depth() + ( _listView->rootIsDecorated() ? 1 : 0 );
476         indent *=  _listView->treeStepSize();
477
478         if ( pos.x() < indent )
479             column = -1;
480     }
481
482     QString text = _listView->toolTip( item, column );
483
484     if ( ! text.isEmpty() )
485     {
486         QRect rect( _listView->itemRect( item ) );
487
488         if ( column < 0 )
489         {
490             rect.setX(0);
491             rect.setWidth( indent );
492         }
493         else
494         {
495             QPoint topLeft( header->sectionPos( column ), 0 );
496             topLeft = _listView->contentsToViewport( topLeft );
497             rect.setX( topLeft.x() );
498             rect.setWidth( header->sectionSize( column ) );
499         }
500
501         tip( rect, text );
502     }
503 }
504
505 #endif
506
507
508 #include "QY2ListView.moc"