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