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