libyui-qt  2.42.4
 All Classes Functions Variables
QY2ListView.cc
1 /*
2  Copyright (C) 2000-2012 Novell, Inc
3  This library is free software; you can redistribute it and/or modify
4  it under the terms of the GNU Lesser General Public License as
5  published by the Free Software Foundation; either version 2.1 of the
6  License, or (at your option) version 3.0 of the License. This library
7  is distributed in the hope that it will be useful, but WITHOUT ANY
8  WARRANTY; without even the implied warranty of MERCHANTABILITY or
9  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
10  License for more details. You should have received a copy of the GNU
11  Lesser General Public License along with this library; if not, write
12  to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
13  Floor, Boston, MA 02110-1301 USA
14 */
15 
16 
17 /*-/
18 
19  File: QY2ListView.cc
20 
21  Author: Stefan Hundhammer <sh@suse.de>
22 
23  This is a pure Qt widget - it can be used independently of YaST2.
24 
25 /-*/
26 
27 
28 #include <QPixmap>
29 #include <QHeaderView>
30 #include <QMouseEvent>
31 #include "QY2ListView.h"
32 
33 #define YUILogComponent "qt-pkg"
34 #include <yui/YUILog.h>
35 
36 QY2ListView::QY2ListView( QWidget * parent )
37  : QTreeWidget( parent )
38  , _mousePressedItem(0)
39  , _mousePressedCol( -1 )
40  , _mousePressedButton( Qt::NoButton )
41  , _sortByInsertionSequence( false )
42  , _nextSerial(0)
43  , _mouseButton1PressedInHeader( false )
44  , _finalSizeChangeExpected( false )
45 {
46  //FIXME QTreeWidget::setShowToolTips( false );
47  setRootIsDecorated(false);
48 
49 #if FIXME_TOOLTIP
50  _toolTip = new QY2ListViewToolTip( this );
51 #endif
52 
53  if ( header() )
54  {
55  header()->installEventFilter( this );
56  header()->setStretchLastSection( false );
57  }
58 
59  connect( header(), SIGNAL( sectionResized ( int, int, int ) ),
60  this, SLOT ( columnWidthChanged ( int, int, int ) ) );
61 
62  connect( this, SIGNAL( itemExpanded ( QTreeWidgetItem *) ),
63  this, SLOT ( treeExpanded ( QTreeWidgetItem *) ) );
64 
65  connect( this, SIGNAL( itemCollapsed ( QTreeWidgetItem *) ),
66  this, SLOT ( treeCollapsed ( QTreeWidgetItem *) ) );
67 
68 }
69 
70 
72 {
73 #if FIXME_TOOLTIP
74  if ( _toolTip )
75  delete _toolTip;
76 #endif
77 }
78 
79 
80 void
82 {
83  QTreeWidgetItemIterator it( this );
84 
85  while ( *it )
86  {
87  QY2ListViewItem * item = dynamic_cast<QY2ListViewItem *> (*it);
88 
89  if ( item && (item->flags() & Qt::ItemIsSelectable) )
90  {
91  item->setSelected(true); // emits signal, too
92  return;
93  }
94 
95  ++it;
96  }
97 }
98 
99 
100 void
102 {
103  QTreeWidget::clear();
105 }
106 
107 
108 void
110 {
111  QTreeWidgetItemIterator it( this );
112 
113  while ( *it )
114  {
115  QY2ListViewItem * item = dynamic_cast<QY2ListViewItem *> (*it);
116 
117  if ( item )
118  item->updateStatus();
119 
120  ++it;
121  }
122 }
123 
124 
125 void
127 {
128  QTreeWidgetItemIterator it( this );
129 
130  while ( *it )
131  {
132  QY2ListViewItem * item = dynamic_cast<QY2ListViewItem *> (*it);
133 
134  if ( item )
135  item->updateData();
136 
137  ++it;
138  }
139 }
140 
141 
142 QString
143 QY2ListView::toolTip( QTreeWidgetItem * listViewItem, int column )
144 {
145  if ( ! listViewItem )
146  return QString::null;
147 
148  QString text;
149 
150  // text.sprintf( "Column %d:\n%s", column, (const char *) listViewItem->text( column ) );
151 
152  // Try known item classes
153 
154  QY2ListViewItem * item = dynamic_cast<QY2ListViewItem *> (listViewItem);
155 
156  if ( item )
157  return item->toolTip( column );
158 
159  QY2CheckListItem * checkListItem = dynamic_cast<QY2CheckListItem *> (listViewItem);
160 
161  if ( checkListItem )
162  return checkListItem->toolTip( column );
163 
164  return QString::null;
165 }
166 
167 
168 void
170 {
171  _savedColumnWidth.clear();
172  _savedColumnWidth.reserve( columnCount() );
173 
174  for ( int i = 0; i < columnCount(); i++ )
175  {
176  int size = header()->sectionSize(i);
177  // yuiMilestone() << "Saving size " << size << " for section " << i << std::endl;
178  _savedColumnWidth.push_back( size );
179  }
180 }
181 
182 
183 void
185 {
186  if ( _savedColumnWidth.size() != (unsigned) columnCount() ) // never manually resized
187  {
188 #if 0
189  for ( int i = 0; i < columnCount(); i++ ) // use optimized column width
190  resizeColumnToContents(i);
191 #endif
192  }
193  else // stored settings after manual resizing
194  {
195  for ( int i = 0; i < columnCount(); i++ )
196  {
197  header()->resizeSection( i, _savedColumnWidth[ i ] ); // restore saved column width
198 
199 #if 0
200  yuiDebug() << "Restoring size " << _savedColumnWidth[i]
201  << " for section " << i
202  << " now " << header()->sectionSize(i)
203  << std::endl;
204 #endif
205  }
206  }
207 }
208 
209 
210 void
211 QY2ListView::mousePressEvent( QMouseEvent * ev )
212 {
213  //y2internal("POS is %d %d", ev->pos().x(), ev->pos().y() );
214  QTreeWidgetItem * item = itemAt( ev->pos() );
215 
216 
217  if ( item && ( item->flags() & Qt::ItemIsEnabled ) )
218  {
219  _mousePressedItem = item;
220  _mousePressedCol = header()->logicalIndexAt( ev->pos().x() );
221  _mousePressedButton = ev->button();
222  }
223  else // invalidate last click data
224  {
225  _mousePressedItem = 0;
226  _mousePressedCol = -1;
227  _mousePressedButton = -1;
228  }
229 
230  // Call base class method
231  QTreeWidget::mousePressEvent( ev );
232 }
233 
234 
235 void
237 {
238  //y2internal("REPOS is %d %d", ev->pos().x(), ev->pos().y() );
239  QTreeWidgetItem * item = itemAt( ev->pos() );
240 
241  if ( item && ( item->flags() & Qt::ItemIsEnabled ) && item == _mousePressedItem )
242  {
243  int col = header()->logicalIndexAt( ev->pos().x() );
244  //y2internal("COL %d", col);
245  if ( item == _mousePressedItem &&
246  col == _mousePressedCol &&
247  ev->button() == _mousePressedButton )
248  {
249  emit( columnClicked( ev->button(), item, col, ev->globalPos() ) );
250  }
251 
252  }
253 
254  // invalidate last click data
255 
256  _mousePressedItem = 0;
257  _mousePressedCol = -1;
258  _mousePressedButton = Qt::NoButton;
259 
260  // Call base class method
261  QTreeWidget::mouseReleaseEvent( ev );
262 }
263 
264 
265 void
267 {
268  QTreeWidgetItem * item = itemAt( mapToGlobal( ev->pos() ) );
269 
270  if ( item && ( item->flags() & Qt::ItemIsEnabled ) )
271  {
272  int col = header()->logicalIndexAt( ev->pos().x() );
273  emit( columnDoubleClicked( ev->button(), (QY2ListViewItem *) item, col, ev->globalPos() ) );
274  }
275 
276  // invalidate last click data
277 
278  _mousePressedItem = 0;
279  _mousePressedCol = -1;
280  _mousePressedButton = Qt::NoButton;
281 
282  // Call base class method
283  QTreeWidget::mouseDoubleClickEvent( ev );
284 }
285 
286 
287 void
289 {
291 
292 #if 0
293  // Workaround for Qt bug:
294  //
295  // QHeader sends a sizeChange() signal for every size change, not only (as
296  // documented) when the user resizes a header column manually. But we only
297  // want to record the column widths if the user explicitly did that, so
298  // ignore those signals if the mouse isn't pressed. There is also one final
299  // sizeChange() signal immediately after the user releases the mouse button.
300 
301  if ( _mouseButton1PressedInHeader || _finalSizeChangeExpected )
302  {
303 
304  // Consume that one sizeChange() signal that is sent immediately after
305  // the mouse button is released, but make sure to reset that flag only
306  // when appropriate.
307 
308  if ( ! _mouseButton1PressedInHeader )
309  _finalSizeChangeExpected = false;
310  }
311 #endif
312 }
313 
314 
315 bool
316 QY2ListView::eventFilter( QObject * obj, QEvent * event )
317 {
318  if ( event && obj && obj == header() )
319  {
320  if ( event->type() == QEvent::MouseButtonPress )
321  {
322  QMouseEvent * mouseEvent = (QMouseEvent *) event;
323 
324  if ( mouseEvent->button() == 1 )
325  {
326  _mouseButton1PressedInHeader = true;
327  _finalSizeChangeExpected = false;
328  }
329  }
330  else if ( event->type() == QEvent::MouseButtonRelease )
331  {
332  QMouseEvent * mouseEvent = (QMouseEvent *) event;
333 
334  if ( mouseEvent->button() == 1 )
335  {
336  _finalSizeChangeExpected = true;
337  _mouseButton1PressedInHeader = false;
338  }
339  }
340  }
341 
342  return QTreeWidget::eventFilter( obj, event );
343 }
344 
345 
346 QSize
348 {
349  return QSize( 0, 0 );
350 }
351 
352 
353 void
354 QY2ListView::setSortByInsertionSequence( bool sortByInsertionSequence )
355 {
356  _sortByInsertionSequence = sortByInsertionSequence;
357  //FIXME sort();
358  header()->setClickable( ! _sortByInsertionSequence );
359 
360 }
361 
362 
363 
364 
365 
366 
368  const QString & text )
369  : QTreeWidgetItem( parentListView, QStringList(text), 1)
370 {
371  _serial = parentListView->nextSerial();
372 }
373 
374 
375 QY2ListViewItem::QY2ListViewItem( QTreeWidgetItem * parentItem,
376  const QString & text )
377  : QTreeWidgetItem( parentItem, QStringList(text), 1 )
378 {
379  _serial = 0;
380 
381  QY2ListView * parentListView = dynamic_cast<QY2ListView *> ( treeWidget() );
382 
383  if ( parentListView )
384  _serial = parentListView->nextSerial();
385 }
386 
387 
389 {
390  // NOP
391 }
392 
393 
394 bool
395 QY2ListViewItem::operator< ( const QTreeWidgetItem & otherListViewItem ) const
396 {
397  bool sortByInsertionSequence = false;
398  QY2ListView * parentListView = dynamic_cast<QY2ListView *> (treeWidget());
399 
400  if ( parentListView )
401  sortByInsertionSequence = parentListView->sortByInsertionSequence();
402 
403  if ( sortByInsertionSequence )
404  {
405  const QY2ListViewItem * other = dynamic_cast<const QY2ListViewItem *> (&otherListViewItem);
406 
407  if ( other )
408  {
409  return ( this->serial() < other->serial() );
410  }
411 
412  // Still here? Try the other version: QY2CheckListItem.
413 
414  const QY2CheckListItem * otherCheckListItem = dynamic_cast<const QY2CheckListItem *> (&otherListViewItem);
415 
416  if ( otherCheckListItem )
417  {
418  return ( this->serial() < otherCheckListItem->serial() );
419  }
420 
421  }
422 
423  // numeric sorting if columns are numbers
424  int column = treeWidget()->sortColumn();
425  QString text1=text(column).trimmed();
426  QString text2=otherListViewItem.text(column).trimmed();
427 
428  text1=text1.left(text1.indexOf(QChar(' ')));
429  text2=text2.left(text2.indexOf(QChar(' ')));
430 
431  bool ok1, ok2; // conversion to int successful
432  bool retval = text1.toInt(&ok1) < text2.toInt(&ok2);
433 
434  if (ok1 && ok2 )
435  return retval; // int < int
436  else if (ok1 && !ok2)
437  return true; // int < std::string
438  else if (!ok1 && ok2)
439  return false; // std::string > int
440 
441  // and finally non-numeric sorting is done by the base class
442  return QTreeWidgetItem::operator<(otherListViewItem);
443 }
444 
445 
447  const QString & text )
448  : QY2ListViewItem( parentListView, text)
449 {
450  setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
451  setCheckState(0, Qt::Unchecked);
452  _serial = parentListView->nextSerial();
453 }
454 
455 
456 QY2CheckListItem::QY2CheckListItem( QTreeWidgetItem * parentItem,
457  const QString & text )
458  : QY2ListViewItem( parentItem, text)
459 {
460  _serial = 0;
461  QY2ListView * parentListView = dynamic_cast<QY2ListView *> ( treeWidget() );
462 
463  setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
464  setCheckState(0, Qt::Unchecked);
465 
466  if ( parentListView )
467  _serial = parentListView->nextSerial();
468 }
469 
471 {
472  // NOP
473 }
474 
475 
476 
477 #if FIXME_ITEM_COLORS
478 void
479 QY2CheckListItem::paintCell( QPainter * painter,
480  const QColorGroup & colorGroup,
481  int column,
482  int width,
483  int alignment )
484 {
485  QColorGroup cg = colorGroup;
486 
487  if ( _textColor.isValid() ) cg.setColor( QColorGroup::Text, _textColor );
488  if ( _backgroundColor.isValid() ) cg.setColor( QColorGroup::Base, _backgroundColor );
489 
490  QTreeWidgetItem::paintCell( painter, cg, column, width, alignment );
491 }
492 #endif
493 
494 
495 #if FIXME_TOOLTIP
496 void
497 QY2ListViewToolTip::maybeTip( const QPoint & pos )
498 {
499  Q3Header * header = _listView->header();
500  QTreeWidgetItem * item = _listView->itemAt( pos );
501 
502  if ( ! item )
503  return;
504 
505  int x = _listView->viewportToContents( pos ).x();
506  int column = header->sectionAt(x);
507  int indent = 0;
508 
509  if ( column == 0 )
510  {
511  indent = item->depth() + ( _listView->rootIsDecorated() ? 1 : 0 );
512  indent *= _listView->treeStepSize();
513 
514  if ( pos.x() < indent )
515  column = -1;
516  }
517 
518  QString text = _listView->toolTip( item, column );
519 
520  if ( ! text.isEmpty() )
521  {
522  QRect rect( _listView->itemRect( item ) );
523 
524  if ( column < 0 )
525  {
526  rect.setX(0);
527  rect.setWidth( indent );
528  }
529  else
530  {
531  QPoint topLeft( header->sectionPos( column ), 0 );
532  topLeft = _listView->contentsToViewport( topLeft );
533  rect.setX( topLeft.x() );
534  rect.setWidth( header->sectionSize( column ) );
535  }
536 
537  tip( rect, text );
538  }
539 }
540 
541 #endif
542 
543 
544 void QY2ListView::treeExpanded( QTreeWidgetItem * listViewItem )
545 {
546  if ( columnCount() == 1 && header() && header()->isHidden() )
547  resizeColumnToContents( 0 );
548 }
549 
550 
551 void QY2ListView::treeCollapsed( QTreeWidgetItem * listViewItem )
552 {
553  if ( columnCount() == 1 && header() && header()->isHidden())
554  resizeColumnToContents( 0 );
555 }
556 
557 
558 
559 
560 #include "QY2ListView.moc"