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