libyui-qt  2.47.1.1
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 "YQUI.h"
32 #include "QY2ListView.h"
33 
34 #define YUILogComponent "qt-pkg"
35 #include <yui/YUILog.h>
36 
37 QY2ListView::QY2ListView( QWidget * parent )
38  : QTreeWidget( parent )
39  , _mousePressedItem(0)
40  , _mousePressedCol( -1 )
41  , _mousePressedButton( Qt::NoButton )
42  , _sortByInsertionSequence( false )
43  , _nextSerial(0)
44  , _mouseButton1PressedInHeader( false )
45  , _finalSizeChangeExpected( false )
46 {
47  //FIXME QTreeWidget::setShowToolTips( false );
48  setRootIsDecorated(false);
49 
50 #if FIXME_TOOLTIP
51  _toolTip = new QY2ListViewToolTip( this );
52 #endif
53 
54  if ( header() )
55  {
56  header()->installEventFilter( this );
57  header()->setStretchLastSection( false );
58  }
59 
60  connect( header(), &pclass(header())::sectionResized,
61  this, &pclass(this)::columnWidthChanged );
62 
63  connect( this, &pclass(this)::itemExpanded,
64  this, &pclass(this)::treeExpanded );
65 
66  connect( this, &pclass(this)::itemCollapsed,
67  this, &pclass(this)::treeCollapsed );
68 
69 }
70 
71 
73 {
74 #if FIXME_TOOLTIP
75  if ( _toolTip )
76  delete _toolTip;
77 #endif
78 }
79 
80 
81 void
83 {
84  QTreeWidgetItemIterator it( this );
85 
86  while ( *it )
87  {
88  QY2ListViewItem * item = dynamic_cast<QY2ListViewItem *> (*it);
89 
90  if ( item && (item->flags() & Qt::ItemIsSelectable) )
91  {
92  item->setSelected(true); // emits signal, too
93  return;
94  }
95 
96  ++it;
97  }
98 }
99 
100 
101 void
103 {
104  QTreeWidget::clear();
106 }
107 
108 
109 void
111 {
112  QTreeWidgetItemIterator it( this );
113 
114  while ( *it )
115  {
116  QY2ListViewItem * item = dynamic_cast<QY2ListViewItem *> (*it);
117 
118  if ( item )
119  item->updateStatus();
120 
121  ++it;
122  }
123 }
124 
125 
126 void
128 {
129  QTreeWidgetItemIterator it( this );
130 
131  while ( *it )
132  {
133  QY2ListViewItem * item = dynamic_cast<QY2ListViewItem *> (*it);
134 
135  if ( item )
136  item->updateData();
137 
138  ++it;
139  }
140 }
141 
142 
143 QString
144 QY2ListView::toolTip( QTreeWidgetItem * listViewItem, int column )
145 {
146  if ( ! listViewItem )
147  return QString::null;
148 
149  QString text;
150 
151  // text.sprintf( "Column %d:\n%s", column, (const char *) listViewItem->text( column ) );
152 
153  // Try known item classes
154 
155  QY2ListViewItem * item = dynamic_cast<QY2ListViewItem *> (listViewItem);
156 
157  if ( item )
158  return item->toolTip( column );
159 
160  QY2CheckListItem * checkListItem = dynamic_cast<QY2CheckListItem *> (listViewItem);
161 
162  if ( checkListItem )
163  return checkListItem->toolTip( column );
164 
165  return QString::null;
166 }
167 
168 
169 void
171 {
172  _savedColumnWidth.clear();
173  _savedColumnWidth.reserve( columnCount() );
174 
175  for ( int i = 0; i < columnCount(); i++ )
176  {
177  int size = header()->sectionSize(i);
178  // yuiMilestone() << "Saving size " << size << " for section " << i << std::endl;
179  _savedColumnWidth.push_back( size );
180  }
181 }
182 
183 
184 void
186 {
187  if ( _savedColumnWidth.size() != (unsigned) columnCount() ) // never manually resized
188  {
189 #if 0
190  for ( int i = 0; i < columnCount(); i++ ) // use optimized column width
191  resizeColumnToContents(i);
192 #endif
193  }
194  else // stored settings after manual resizing
195  {
196  for ( int i = 0; i < columnCount(); i++ )
197  {
198  header()->resizeSection( i, _savedColumnWidth[ i ] ); // restore saved column width
199 
200 #if 0
201  yuiDebug() << "Restoring size " << _savedColumnWidth[i]
202  << " for section " << i
203  << " now " << header()->sectionSize(i)
204  << std::endl;
205 #endif
206  }
207  }
208 }
209 
210 
211 void
212 QY2ListView::mousePressEvent( QMouseEvent * ev )
213 {
214  //y2internal("POS is %d %d", ev->pos().x(), ev->pos().y() );
215  QTreeWidgetItem * item = itemAt( ev->pos() );
216 
217 
218  if ( item && ( item->flags() & Qt::ItemIsEnabled ) )
219  {
220  _mousePressedItem = item;
221  _mousePressedCol = header()->logicalIndexAt( ev->pos().x() );
222  _mousePressedButton = ev->button();
223  }
224  else // invalidate last click data
225  {
226  _mousePressedItem = 0;
227  _mousePressedCol = -1;
228  _mousePressedButton = Qt::NoButton;
229  }
230 
231  // Call base class method
232  QTreeWidget::mousePressEvent( ev );
233 }
234 
235 
236 void
238 {
239  //y2internal("REPOS is %d %d", ev->pos().x(), ev->pos().y() );
240  QTreeWidgetItem * item = itemAt( ev->pos() );
241 
242  if ( item && ( item->flags() & Qt::ItemIsEnabled ) && item == _mousePressedItem )
243  {
244  int col = header()->logicalIndexAt( ev->pos().x() );
245  //y2internal("COL %d", col);
246  if ( item == _mousePressedItem &&
247  col == _mousePressedCol &&
248  ev->button() == _mousePressedButton )
249  {
250  emit( columnClicked( ev->button(), item, col, ev->globalPos() ) );
251  }
252 
253  }
254 
255  // invalidate last click data
256 
257  _mousePressedItem = 0;
258  _mousePressedCol = -1;
259  _mousePressedButton = Qt::NoButton;
260 
261  // Call base class method
262  QTreeWidget::mouseReleaseEvent( ev );
263 }
264 
265 
266 void
268 {
269  QTreeWidgetItem * item = itemAt( mapToGlobal( ev->pos() ) );
270 
271  if ( item && ( item->flags() & Qt::ItemIsEnabled ) )
272  {
273  int col = header()->logicalIndexAt( ev->pos().x() );
274  emit( columnDoubleClicked( ev->button(), (QY2ListViewItem *) item, col, ev->globalPos() ) );
275  }
276 
277  // invalidate last click data
278 
279  _mousePressedItem = 0;
280  _mousePressedCol = -1;
281  _mousePressedButton = Qt::NoButton;
282 
283  // Call base class method
284  QTreeWidget::mouseDoubleClickEvent( ev );
285 }
286 
287 
288 void
290 {
292 
293 #if 0
294  // Workaround for Qt bug:
295  //
296  // QHeader sends a sizeChange() signal for every size change, not only (as
297  // documented) when the user resizes a header column manually. But we only
298  // want to record the column widths if the user explicitly did that, so
299  // ignore those signals if the mouse isn't pressed. There is also one final
300  // sizeChange() signal immediately after the user releases the mouse button.
301 
302  if ( _mouseButton1PressedInHeader || _finalSizeChangeExpected )
303  {
304 
305  // Consume that one sizeChange() signal that is sent immediately after
306  // the mouse button is released, but make sure to reset that flag only
307  // when appropriate.
308 
309  if ( ! _mouseButton1PressedInHeader )
310  _finalSizeChangeExpected = false;
311  }
312 #endif
313 }
314 
315 
316 bool
317 QY2ListView::eventFilter( QObject * obj, QEvent * event )
318 {
319  if ( event && obj && obj == header() )
320  {
321  if ( event->type() == QEvent::MouseButtonPress )
322  {
323  QMouseEvent * mouseEvent = (QMouseEvent *) event;
324 
325  if ( mouseEvent->button() == 1 )
326  {
327  _mouseButton1PressedInHeader = true;
328  _finalSizeChangeExpected = false;
329  }
330  }
331  else if ( event->type() == QEvent::MouseButtonRelease )
332  {
333  QMouseEvent * mouseEvent = (QMouseEvent *) event;
334 
335  if ( mouseEvent->button() == 1 )
336  {
337  _finalSizeChangeExpected = true;
338  _mouseButton1PressedInHeader = false;
339  }
340  }
341  }
342 
343  return QTreeWidget::eventFilter( obj, event );
344 }
345 
346 
347 QSize
349 {
350  return QSize( 0, 0 );
351 }
352 
353 
354 void
356 {
357  _sortByInsertionSequence = sortByInsertionSequence;
358  //FIXME sort();
359  header()->setSectionsClickable( ! _sortByInsertionSequence );
360 
361 }
362 
363 
364 
365 
366 
367 
369  const QString & text )
370  : QTreeWidgetItem( parentListView, QStringList(text), 1)
371 {
372  _serial = parentListView->nextSerial();
373 }
374 
375 
376 QY2ListViewItem::QY2ListViewItem( QTreeWidgetItem * parentItem,
377  const QString & text )
378  : QTreeWidgetItem( parentItem, QStringList(text), 1 )
379 {
380  _serial = 0;
381 
382  QY2ListView * parentListView = dynamic_cast<QY2ListView *> ( treeWidget() );
383 
384  if ( parentListView )
385  _serial = parentListView->nextSerial();
386 }
387 
388 
390 {
391  // NOP
392 }
393 
394 
395 bool
396 QY2ListViewItem::operator< ( const QTreeWidgetItem & otherListViewItem ) const
397 {
398  bool sortByInsertionSequence = false;
399  QY2ListView * parentListView = dynamic_cast<QY2ListView *> (treeWidget());
400 
401  if ( parentListView )
402  sortByInsertionSequence = parentListView->sortByInsertionSequence();
403 
404  if ( sortByInsertionSequence )
405  {
406  const QY2ListViewItem * other = dynamic_cast<const QY2ListViewItem *> (&otherListViewItem);
407 
408  if ( other )
409  {
410  return ( this->serial() < other->serial() );
411  }
412 
413  // Still here? Try the other version: QY2CheckListItem.
414 
415  const QY2CheckListItem * otherCheckListItem = dynamic_cast<const QY2CheckListItem *> (&otherListViewItem);
416 
417  if ( otherCheckListItem )
418  {
419  return ( this->serial() < otherCheckListItem->serial() );
420  }
421 
422  }
423 
424  // numeric sorting if columns are numbers
425  int column = treeWidget()->sortColumn();
426  QString text1=text(column).trimmed();
427  QString text2=otherListViewItem.text(column).trimmed();
428 
429  text1=text1.left(text1.indexOf(QChar(' ')));
430  text2=text2.left(text2.indexOf(QChar(' ')));
431 
432  bool ok1, ok2; // conversion to int successful
433  bool retval = text1.toInt(&ok1) < text2.toInt(&ok2);
434 
435  if (ok1 && ok2 )
436  return retval; // int < int
437  else if (ok1 && !ok2)
438  return true; // int < std::string
439  else if (!ok1 && ok2)
440  return false; // std::string > int
441 
442  // and finally non-numeric sorting is done by the base class
443  return QTreeWidgetItem::operator<(otherListViewItem);
444 }
445 
446 
448  const QString & text )
449  : QY2ListViewItem( parentListView, text)
450 {
451  setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
452  setCheckState(0, Qt::Unchecked);
453  _serial = parentListView->nextSerial();
454 }
455 
456 
457 QY2CheckListItem::QY2CheckListItem( QTreeWidgetItem * parentItem,
458  const QString & text )
459  : QY2ListViewItem( parentItem, text)
460 {
461  _serial = 0;
462  QY2ListView * parentListView = dynamic_cast<QY2ListView *> ( treeWidget() );
463 
464  setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
465  setCheckState(0, Qt::Unchecked);
466 
467  if ( parentListView )
468  _serial = parentListView->nextSerial();
469 }
470 
472 {
473  // NOP
474 }
475 
476 
477 
478 #if FIXME_TOOLTIP
479 void
480 QY2ListViewToolTip::maybeTip( const QPoint & pos )
481 {
482  Q3Header * header = _listView->header();
483  QTreeWidgetItem * item = _listView->itemAt( pos );
484 
485  if ( ! item )
486  return;
487 
488  int x = _listView->viewportToContents( pos ).x();
489  int column = header->sectionAt(x);
490  int indent = 0;
491 
492  if ( column == 0 )
493  {
494  indent = item->depth() + ( _listView->rootIsDecorated() ? 1 : 0 );
495  indent *= _listView->treeStepSize();
496 
497  if ( pos.x() < indent )
498  column = -1;
499  }
500 
501  QString text = _listView->toolTip( item, column );
502 
503  if ( ! text.isEmpty() )
504  {
505  QRect rect( _listView->itemRect( item ) );
506 
507  if ( column < 0 )
508  {
509  rect.setX(0);
510  rect.setWidth( indent );
511  }
512  else
513  {
514  QPoint topLeft( header->sectionPos( column ), 0 );
515  topLeft = _listView->contentsToViewport( topLeft );
516  rect.setX( topLeft.x() );
517  rect.setWidth( header->sectionSize( column ) );
518  }
519 
520  tip( rect, text );
521  }
522 }
523 
524 #endif
525 
526 
527 void QY2ListView::treeExpanded( QTreeWidgetItem * listViewItem )
528 {
529  if ( columnCount() == 1 && header() && header()->isHidden() )
530  resizeColumnToContents( 0 );
531 }
532 
533 
534 void QY2ListView::treeCollapsed( QTreeWidgetItem * listViewItem )
535 {
536  if ( columnCount() == 1 && header() && header()->isHidden())
537  resizeColumnToContents( 0 );
538 }
539 
540 
541 
542 
543 #include "QY2ListView.moc"
bool sortByInsertionSequence() const
Returns &#39;true&#39; if the sort order should always be the item insertion order, &#39;false&#39; if the user can c...
Definition: QY2ListView.h:144
virtual void setSortByInsertionSequence(bool sortByInsertionSequence)
Enforce sorting by item insertion order (true) or let user change sorting by clicking on a column hea...
Definition: QY2ListView.cc:355
virtual bool operator<(const QTreeWidgetItem &other) const
Comparison function used for sorting the list.
Definition: QY2ListView.cc:396
QY2ListViewItem(QY2ListView *parentListView, const QString &text=QString::null)
Constructor for toplevel items.
Definition: QY2ListView.cc:368
void saveColumnWidths()
Save the current column widths.
Definition: QY2ListView.cc:170
void columnWidthChanged(int col, int oldSize, int newSize)
Internal: Handle manual column resize.
Definition: QY2ListView.cc:289
QY2ListView(QWidget *parent)
Constructor.
Definition: QY2ListView.cc:37
virtual QSize minimumSizeHint() const
Returns the minimum size required for this widget.
Definition: QY2ListView.cc:348
virtual void clear()
Reimplemented from Q3ListView: Adjust header sizes after clearing contents.
Definition: QY2ListView.cc:102
void columnClicked(int button, QTreeWidgetItem *item, int col, const QPoint &pos)
Emitted for mouse clicks on an item.
virtual void mouseDoubleClickEvent(QMouseEvent *)
Handle mouse clicks.
Definition: QY2ListView.cc:267
virtual void updateData()
Update this item&#39;s data completely.
Definition: QY2ListView.h:269
virtual QString toolTip(QTreeWidgetItem *item, int column)
Returns a tool tip text for a specific column of a list item.
Definition: QY2ListView.cc:144
virtual bool eventFilter(QObject *obj, QEvent *event)
Event filter - inherited from QWidget.
Definition: QY2ListView.cc:317
void updateItemStates()
Update the status display of all list entries: Call QY2ListViewItem::updateStatus() for each item...
Definition: QY2ListView.cc:110
virtual ~QY2CheckListItem()
Destructor.
Definition: QY2ListView.cc:471
virtual QString toolTip(int column)
Returns a tool tip text for a specific column of this item.
Definition: QY2ListView.h:373
int serial() const
Return this item&#39;s serial number.
Definition: QY2ListView.h:281
void treeCollapsed(QTreeWidgetItem *listViewItem)
Internal notification that a tree item has been collapsed.
Definition: QY2ListView.cc:534
void columnDoubleClicked(int button, QTreeWidgetItem *item, int col, const QPoint &pos)
Emitted for mouse double clicks on an item.
Enhanced QCheckListItem.
Definition: QY2ListView.h:309
Enhanced QTreeWidget.
Definition: QY2ListView.h:47
virtual QString toolTip(int column)
Returns a tool tip text for a specific column of this item.
Definition: QY2ListView.h:289
QY2CheckListItem(QY2ListView *parentListView, const QString &text)
Constructor for toplevel items.
Definition: QY2ListView.cc:447
void treeExpanded(QTreeWidgetItem *listViewItem)
Internal notification that a tree item has been expanded.
Definition: QY2ListView.cc:527
Enhanced QTreeWidgetItem.
Definition: QY2ListView.h:233
virtual ~QY2ListViewItem()
Destructor.
Definition: QY2ListView.cc:389
virtual ~QY2ListView()
Destructor.
Definition: QY2ListView.cc:72
void updateItemData()
Update the status display of all list entries: Call QY2ListViewItem::updateData() for each item...
Definition: QY2ListView.cc:127
virtual void mouseReleaseEvent(QMouseEvent *)
Handle mouse clicks.
Definition: QY2ListView.cc:237
virtual void selectSomething()
Select a list entry (if there is any).
Definition: QY2ListView.cc:82
int nextSerial()
Returns the next free serial number for items that want to be ordered in insertion sequence...
Definition: QY2ListView.h:156
virtual void mousePressEvent(QMouseEvent *e)
Handle mouse clicks.
Definition: QY2ListView.cc:212
int serial() const
Return this item&#39;s serial number.
Definition: QY2ListView.h:351
void restoreColumnWidths()
Restore the column widths to what was saved previously with saveColumnWidths().
Definition: QY2ListView.cc:185
virtual void updateStatus()
Update this item&#39;s status.
Definition: QY2ListView.h:261