]> icculus.org git repositories - duncan/yast2-qt4.git/blob - src/QY2ListView.cc
merge latest qt3 commits
[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     header()->setClickable( ! _sortByInsertionSequence );
330 }
331
332
333
334
335
336
337 QY2ListViewItem::QY2ListViewItem( QY2ListView *         parentListView,
338                                   const QString &       text )
339     : QTreeWidgetItem( parentListView, QStringList(text), 1)
340 {
341     _serial = parentListView->nextSerial();
342 }
343
344
345 QY2ListViewItem::QY2ListViewItem( QTreeWidgetItem *     parentItem,
346                                   const QString &       text )
347     : QTreeWidgetItem( parentItem, QStringList(text), 1 )
348 {
349     _serial = 0;
350
351     QY2ListView * parentListView = dynamic_cast<QY2ListView *> ( treeWidget() );
352
353     if ( parentListView )
354         _serial = parentListView->nextSerial();
355 }
356
357
358 QY2ListViewItem::~QY2ListViewItem()
359 {
360     // NOP
361 }
362
363
364 /**
365  * Comparison function used for sorting the list.
366  * Returns:
367  * -1 if this <  other
368  *  0 if this == other
369  * +1 if this >  other
370  **/
371 int
372 QY2ListViewItem::compare( QTreeWidgetItem *     otherListViewItem,
373                           int                   col,
374                           bool                  ascending ) const
375 {
376     bool sortByInsertionSequence = false;
377     QY2ListView * parentListView = dynamic_cast<QY2ListView *> (treeWidget());
378
379     if ( parentListView )
380         sortByInsertionSequence = parentListView->sortByInsertionSequence();
381
382     if ( sortByInsertionSequence )
383     {
384         QY2ListViewItem * other = dynamic_cast<QY2ListViewItem *> (otherListViewItem);
385
386         if ( other )
387         {
388             if ( this->serial() < other->serial() ) return -1;
389             if ( this->serial() > other->serial() ) return  1;
390             return 0;
391         }
392
393         // Still here? Try the other version: QY2CheckListItem.
394
395         QY2CheckListItem * otherCheckListItem = dynamic_cast<QY2CheckListItem *> (otherListViewItem);
396
397         if ( otherCheckListItem )
398         {
399             if ( this->serial() < otherCheckListItem->serial() ) return -1;
400             if ( this->serial() > otherCheckListItem->serial() ) return  1;
401             return 0;
402         }
403
404     }
405
406     //return QTreeWidgetItem::compare( otherListViewItem, col, ascending );
407     return 0;
408 }
409
410
411 // void
412 // QY2ListViewItem::paintCell( QPainter *               painter,
413 //                          const QColorGroup & colorGroup,
414 //                          int                 column,
415 //                          int                 width,
416 //                          int                 alignment )
417 // {
418 //     QColorGroup cg = colorGroup;
419 //
420 //     if ( _textColor.isValid() )              cg.setColor( QColorGroup::Text, _textColor );
421 //     if ( _backgroundColor.isValid() )        cg.setColor( QColorGroup::Base, _backgroundColor );
422 //
423 //     QTreeWidgetItem::paintCell( painter, cg, column, width, alignment );
424 // }
425
426
427
428
429
430
431 QY2CheckListItem::QY2CheckListItem( QY2ListView *               parentListView,
432                                     const QString &             text )
433     : QTreeWidgetItem( parentListView, QStringList(text))
434 {
435     setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
436     setCheckState(0, Qt::Unchecked);
437     _serial = parentListView->nextSerial();
438 }
439
440
441 QY2CheckListItem::QY2CheckListItem( QTreeWidgetItem *           parentItem,
442                                     const QString &             text )
443     : QTreeWidgetItem( parentItem, QStringList(text))
444 {
445     _serial = 0;
446     QY2ListView * parentListView = dynamic_cast<QY2ListView *> ( treeWidget() );
447
448     if ( parentListView )
449         _serial = parentListView->nextSerial();
450 }
451
452 QY2CheckListItem::~QY2CheckListItem()
453 {
454     // NOP
455 }
456
457
458 /**
459  * Comparison function used for sorting the list.
460  * Returns:
461  * -1 if this <  other
462  *  0 if this == other
463  * +1 if this >  other
464  **/
465 int
466 QY2CheckListItem::compare( QTreeWidgetItem *    otherListViewItem,
467                            int                  col,
468                            bool                 ascending ) const
469 {
470     bool sortByInsertionSequence = false;
471     QY2ListView * parentListView = dynamic_cast<QY2ListView *> (treeWidget());
472
473     if ( parentListView )
474         sortByInsertionSequence = parentListView->sortByInsertionSequence();
475
476     if ( sortByInsertionSequence )
477     {
478         QY2CheckListItem * other = dynamic_cast<QY2CheckListItem *> (otherListViewItem);
479
480         if ( other )
481         {
482             if ( this->serial() < other->serial() ) return -1;
483             if ( this->serial() > other->serial() ) return  1;
484             return 0;
485         }
486
487
488         // Still here? Try the other version: QY2ListViewItem.
489
490         QY2ListViewItem * otherCheckListItem = dynamic_cast<QY2ListViewItem *> (otherListViewItem);
491
492         if ( otherCheckListItem )
493         {
494             if ( this->serial() < otherCheckListItem->serial() ) return -1;
495             if ( this->serial() > otherCheckListItem->serial() ) return  1;
496             return 0;
497         }
498
499     }
500
501     //FIXME return QTreeWidgetItem::compare( otherListViewItem, col, ascending );
502     return 0;
503 }
504
505 /*
506 void
507 QY2CheckListItem::paintCell( QPainter *                 painter,
508                              const QColorGroup &        colorGroup,
509                              int                        column,
510                              int                        width,
511                              int                        alignment )
512 {
513     QColorGroup cg = colorGroup;
514
515     if ( _textColor.isValid() )         cg.setColor( QColorGroup::Text, _textColor );
516     if ( _backgroundColor.isValid() )   cg.setColor( QColorGroup::Base, _backgroundColor );
517
518     QTreeWidgetItem::paintCell( painter, cg, column, width, alignment );
519 }
520 */
521
522 #if FIXME_TOOLTIP
523 void
524 QY2ListViewToolTip::maybeTip( const QPoint & pos )
525 {
526     Q3Header *       header        = _listView->header();
527     QTreeWidgetItem * 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 #endif
569
570
571 #include "QY2ListView.moc"