libyui-qt  2.53.0
YQTable.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: YQTable.cc
20 
21  Author: Stefan Hundhammer <sh@suse.de>
22 
23 /-*/
24 
25 #include <QHeaderView>
26 #include <QVBoxLayout>
27 #include <QString>
28 #define YUILogComponent "qt-ui"
29 #include <yui/YUILog.h>
30 
31 #include "utf8.h"
32 #include "YQUI.h"
33 #include <yui/YEvent.h>
34 #include "YQSignalBlocker.h"
35 #include <yui/YUIException.h>
36 
37 #include "QY2ListView.h"
38 #include "YQTable.h"
39 #include "YQApplication.h"
40 
41 
42 using std::endl;
43 
44 
45 
46 YQTable::YQTable( YWidget * parent,
47  YTableHeader * tableHeader,
48  bool multiSelectionMode )
49  : QFrame( (QWidget *) parent->widgetRep() )
50  , YTable( parent, tableHeader, multiSelectionMode )
51 {
52  setWidgetRep( this );
53  QVBoxLayout* layout = new QVBoxLayout( this );
54  layout->setSpacing( 0 );
55  setLayout( layout );
56 
57  layout->setMargin( YQWidgetMargin );
58 
59  _qt_listView = new QY2ListView( this );
60  YUI_CHECK_NEW( _qt_listView );
61  layout->addWidget( _qt_listView );
62  _qt_listView->setAllColumnsShowFocus( true );
63  _qt_listView->header()->setStretchLastSection( false );
64 
65  setKeepSorting( keepSorting() );
66 
67  if ( multiSelectionMode )
68  _qt_listView->setSelectionMode( QAbstractItemView::ExtendedSelection );
69 
70  _qt_listView->setContextMenuPolicy( Qt::CustomContextMenu );
71 
72  //
73  // Add columns
74  //
75 
76  QStringList headers;
77  _qt_listView->setColumnCount( columns() );
78 
79  for ( int i=0; i < columns(); i++ )
80  {
81  headers << fromUTF8( header(i) );
82  }
83 
84  _qt_listView->setHeaderLabels( headers );
85  _qt_listView->header()->setSectionResizeMode( QHeaderView::Interactive );
86  _qt_listView->sortItems( 0, Qt::AscendingOrder);
87 
88 
89  //
90  // Connect signals and slots
91  //
92 
93  connect( _qt_listView, &pclass(_qt_listView)::itemDoubleClicked,
94  this, &pclass(this)::slotActivated );
95 
96  connect( _qt_listView, &pclass(_qt_listView)::customContextMenuRequested,
97  this, &pclass(this)::slotContextMenu );
98 
99  if ( multiSelectionMode )
100  {
101  // This is the exceptional case - avoid performance drop in the normal case
102  connect( _qt_listView, &pclass(_qt_listView)::itemSelectionChanged,
103  this, &pclass(this)::slotSelectionChanged );
104  }
105  else
106  {
107  connect( _qt_listView, &pclass(_qt_listView)::currentItemChanged,
108  this, &pclass(this)::slotSelected );
109  }
110 }
111 
112 
114 {
115  // NOP
116 }
117 
118 
119 void
120 YQTable::setKeepSorting( bool keepSorting )
121 {
122  YTable::setKeepSorting( keepSorting );
123  _qt_listView->setSortByInsertionSequence( keepSorting );
124  _qt_listView->setSortingEnabled( ! keepSorting );
125 }
126 
127 
128 void
129 YQTable::addItem( YItem * yitem )
130 {
131  addItem( yitem,
132  false, // batchMode
133  true); // resizeColumnsToContent
134 }
135 
136 
137 void
138 YQTable::addItem( YItem * yitem, bool batchMode, bool resizeColumnsToContent )
139 {
140  YTableItem * item = dynamic_cast<YTableItem *> (yitem);
141  YUI_CHECK_PTR( item );
142 
143  YTable::addItem( item );
144 
145  YQTableListViewItem * clone = new YQTableListViewItem( this, _qt_listView, item );
146  YUI_CHECK_NEW( clone );
147 
148  if ( ! batchMode && item->selected() )
149  {
150  // YTable enforces single selection, if appropriate
151 
152  YQSignalBlocker sigBlocker( _qt_listView );
153  YQTable::selectItem( YSelectionWidget::selectedItem(), true );
154  }
155 
156 
157  //
158  // Set column alignment
159  //
160 
161  for ( int col=0; col < columns(); col++ )
162  {
163  switch ( alignment( col ) )
164  {
165  case YAlignBegin: clone->setTextAlignment( col, Qt::AlignLeft | Qt::AlignVCenter ); break;
166  case YAlignCenter: clone->setTextAlignment( col, Qt::AlignCenter | Qt::AlignVCenter ); break;
167  case YAlignEnd: clone->setTextAlignment( col, Qt::AlignRight | Qt::AlignVCenter ); break;
168 
169  case YAlignUnchanged: break;
170  }
171  }
172 
173  if ( ! batchMode )
174  _qt_listView->sortItems( 0, Qt::AscendingOrder);
175 
176  if ( resizeColumnsToContent )
177  {
178  for ( int i=0; i < columns(); i++ )
179  _qt_listView->resizeColumnToContents( i );
180  /* NOTE: resizeColumnToContents(...) is performance-critical ! */
181  }
182 }
183 
184 
185 void
186 YQTable::addItems( const YItemCollection & itemCollection )
187 {
188  YQSignalBlocker sigBlocker( _qt_listView );
189 
190  for ( YItemConstIterator it = itemCollection.begin();
191  it != itemCollection.end();
192  ++it )
193  {
194  addItem( *it,
195  true, // batchMode
196  false ); // resizeColumnsToContent
197  /* NOTE: resizeToContents=true would cause a massive performance drop !
198  => resize columns to content only one time at the end of this
199  function */
200  }
201 
202  YItem * sel = YSelectionWidget::selectedItem();
203 
204  if ( sel )
205  YQTable::selectItem( sel, true );
206 
207  for ( int i=0; i < columns(); i++ )
208  _qt_listView->resizeColumnToContents( i );
209 }
210 
211 
212 void
213 YQTable::selectItem( YItem * yitem, bool selected )
214 {
215  YQSignalBlocker sigBlocker( _qt_listView );
216 
217  YTableItem * item = dynamic_cast<YTableItem *> (yitem);
218  YUI_CHECK_PTR( item );
219 
220  YQTableListViewItem * clone = (YQTableListViewItem *) item->data();
221  YUI_CHECK_PTR( clone );
222 
223 
224  if ( ! selected && clone == _qt_listView->currentItem() )
225  {
227  }
228  else
229  {
230  if ( ! hasMultiSelection() )
231  _qt_listView->setCurrentItem( clone ); // This deselects all other items!
232 
233  clone->setSelected( true );
234  YTable::selectItem( item, selected );
235  }
236 }
237 
238 
239 void
241 {
242  YQSignalBlocker sigBlocker( _qt_listView );
243 
244  YTable::deselectAllItems();
245  _qt_listView->clearSelection();
246 }
247 
248 
249 void
251 {
252  _qt_listView->clear();
253  YTable::deleteAllItems();
254 }
255 
256 
257 void
258 YQTable::cellChanged( const YTableCell * cell )
259 {
260  YTableItem * item = cell->parent();
261  YUI_CHECK_PTR( item );
262 
263  YQTableListViewItem * clone = (YQTableListViewItem *) item->data();
264  YUI_CHECK_PTR( clone );
265 
266  clone->updateCell( cell );
267 }
268 
269 
270 void
271 YQTable::selectOrigItem( QTreeWidgetItem * listViewItem )
272 {
273  if ( listViewItem )
274  {
275  YQTableListViewItem * tableListViewItem = dynamic_cast<YQTableListViewItem *> (listViewItem);
276  YUI_CHECK_PTR( tableListViewItem );
277 
278  YTable::selectItem( tableListViewItem->origItem(), true );
279  }
280 }
281 
282 
283 void
284 YQTable::slotSelected( QTreeWidgetItem * listViewItem )
285 {
286  if ( listViewItem )
287  selectOrigItem( listViewItem );
288  else
289  {
290  // Qt might select nothing if a user clicks outside the items in the widget
291 
292  if ( hasItems() && YSelectionWidget::hasSelectedItem() )
293  YQTable::selectItem( YSelectionWidget::selectedItem(), true );
294  }
295 
296  if ( immediateMode() )
297  {
298  if ( ! YQUI::ui()->eventPendingFor( this ) )
299  {
300  // Avoid overwriting a (more important) Activated event with a SelectionChanged event
301 
302  yuiDebug() << "Sending SelectionChanged event" << endl;
303  YQUI::ui()->sendEvent( new YWidgetEvent( this, YEvent::SelectionChanged ) );
304  }
305  }
306 }
307 
308 
309 void
311 {
312  YSelectionWidget::deselectAllItems();
313  yuiDebug() << endl;
314 
315  QList<QTreeWidgetItem *> selItems = _qt_listView->selectedItems();
316 
317  for ( QList<QTreeWidgetItem *>::iterator it = selItems.begin();
318  it != selItems.end();
319  ++it )
320  {
321  YQTableListViewItem * tableListViewItem = dynamic_cast<YQTableListViewItem *> (*it);
322 
323  if ( tableListViewItem )
324  {
325  tableListViewItem->origItem()->setSelected( true );
326 
327  yuiDebug() << "Selected item: " << tableListViewItem->origItem()->label() << endl;
328  }
329  }
330 
331  if ( immediateMode() )
332  {
333  if ( ! YQUI::ui()->eventPendingFor( this ) )
334  {
335  // Avoid overwriting a (more important) Activated event with a SelectionChanged event
336 
337  yuiDebug() << "Sending SelectionChanged event" << endl;
338  YQUI::ui()->sendEvent( new YWidgetEvent( this, YEvent::SelectionChanged ) );
339  }
340  }
341 }
342 
343 
344 void
345 YQTable::slotActivated( QTreeWidgetItem * listViewItem )
346 {
347  selectOrigItem( listViewItem );
348 
349  if ( notify() )
350  {
351  yuiDebug() << "Sending Activated event" << endl;
352  YQUI::ui()->sendEvent( new YWidgetEvent( this, YEvent::Activated ) );
353  }
354 }
355 
356 
357 void
358 YQTable::setEnabled( bool enabled )
359 {
360  _qt_listView->setEnabled( enabled );
361  //FIXME _qt_listView->triggerUpdate();
362  YWidget::setEnabled( enabled );
363 }
364 
365 
366 
367 int
369 {
370  // Arbitrary value.
371  // Use a MinSize widget to set a size that is useful for the application.
372 
373  return 30;
374 }
375 
376 
377 int
379 {
380  // Arbitrary value.
381  // Use a MinSize widget to set a size that is useful for the application.
382 
383  return 30;
384 }
385 
386 
387 void
388 YQTable::setSize( int newWidth, int newHeight )
389 {
390  resize( newWidth, newHeight );
391 }
392 
393 
394 bool
396 {
397  _qt_listView->setFocus();
398 
399  return true;
400 }
401 
402 
403 void
404 YQTable::slotContextMenu ( const QPoint & pos )
405 {
406  if ( ! _qt_listView || ! _qt_listView->viewport() )
407  return;
408 
409  YQUI::yqApp()->setContextMenuPos( _qt_listView->viewport()->mapToGlobal( pos ) );
410  if ( notifyContextMenu() )
411  YQUI::ui()->sendEvent( new YWidgetEvent( this, YEvent::ContextMenuActivated ) );
412 }
413 
414 
415 
416 
417 
419  QY2ListView * parent,
420  YTableItem * origItem )
421  : QY2ListViewItem( parent )
422  , _table( table )
423  , _origItem( origItem )
424 {
425  YUI_CHECK_PTR( _table );
426  YUI_CHECK_PTR( _origItem );
427 
428  _origItem->setData( this );
429 
430  for ( YTableCellIterator it = _origItem->cellsBegin();
431  it != _origItem->cellsEnd();
432  ++it )
433  {
434  updateCell( *it );
435  }
436 }
437 
438 
439 void
440 YQTableListViewItem::updateCell( const YTableCell * cell )
441 {
442  if ( ! cell )
443  return;
444 
445  int column = cell->column();
446 
447  //
448  // Set label text
449  //
450 
451  setText( column, fromUTF8( cell->label() ) );
452 
453 
454  //
455  // Set icon (if specified)
456  //
457 
458  if ( cell->hasIconName() )
459  {
460  // _table is checked against 0 in the constructor
461  QIcon icon = YQUI::ui()->loadIcon( cell->iconName() );
462 
463  if ( ! icon.isNull() )
464  setData( column, Qt::DecorationRole, icon );
465  }
466  else // No icon name
467  {
468  if ( ! data( column, Qt::DecorationRole ).isNull() ) // Was there an icon before?
469  {
470  setData( column, Qt::DecorationRole, QIcon() ); // Set empty icon
471  }
472  }
473 }
474 
475 
476 QString
478 {
479  const YTableCell* tableCell = origItem()->cell(column);
480 
481  if (tableCell->hasSortKey())
482  return QString::fromUtf8(tableCell->sortKey().c_str());
483  else
484  return text(column).trimmed();
485 }
Enhanced QTreeWidgetItem.
Definition: QY2ListView.h:234
Enhanced QTreeWidget.
Definition: QY2ListView.h:48
virtual void clear()
Reimplemented from Q3ListView: Adjust header sizes after clearing contents.
Definition: QY2ListView.cc:102
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 void setContextMenuPos(QPoint contextMenuPos)
Sets the position of the context menu (in gloabl coordinates)
Helper class to block Qt signals for QWidgets or QObjects as long as this object exists.
Visual representation of a YTableItem.
Definition: YQTable.h:199
virtual QString smartSortKey(int column) const override
The text of the table cell or the sort-key if available.
Definition: YQTable.cc:477
YQTableListViewItem(YQTable *table, QY2ListView *parent, YTableItem *origItem)
Constructor.
Definition: YQTable.cc:418
void updateCell(const YTableCell *cell)
Update this item's display with the content of 'cell'.
Definition: YQTable.cc:440
YTableItem * origItem() const
Return the corresponding YTableItem.
Definition: YQTable.h:217
virtual void addItems(const YItemCollection &itemCollection)
Add multiple items.
Definition: YQTable.cc:186
virtual void setSize(int newWidth, int newHeight)
Set the new size of the widget.
Definition: YQTable.cc:388
virtual bool setKeyboardFocus()
Accept the keyboard focus.
Definition: YQTable.cc:395
virtual void addItem(YItem *item)
Add an item.
Definition: YQTable.cc:129
virtual void deselectAllItems()
Deselect all items.
Definition: YQTable.cc:240
void slotActivated(QTreeWidgetItem *)
Notification that an item is activated (double click or keyboard).
Definition: YQTable.cc:345
virtual void setKeepSorting(bool keepSorting)
Switch between sorting by item insertion order (keepSorting: true) or allowing the user to sort by an...
Definition: YQTable.cc:120
virtual int preferredWidth()
Preferred width of the widget.
Definition: YQTable.cc:368
void slotContextMenu(const QPoint &pos)
Propagate a context menu selection.
Definition: YQTable.cc:404
virtual void selectItem(YItem *item, bool selected=true)
Select or deselect an item.
Definition: YQTable.cc:213
virtual void deleteAllItems()
Delete all items.
Definition: YQTable.cc:250
virtual void setEnabled(bool enabled)
Set enabled/disabled state.
Definition: YQTable.cc:358
virtual ~YQTable()
Destructor.
Definition: YQTable.cc:113
void slotSelected(QTreeWidgetItem *)
Notification that an item is selected (single click or keyboard).
Definition: YQTable.cc:284
virtual int preferredHeight()
Preferred height of the widget.
Definition: YQTable.cc:378
void slotSelectionChanged()
Notification that the item selection changed (relevant for multiSelection mode).
Definition: YQTable.cc:310
YQTable(YWidget *parent, YTableHeader *header, bool multiSelection)
Constructor.
Definition: YQTable.cc:46
virtual void cellChanged(const YTableCell *cell)
Notification that a cell (its text and/or its icon) was changed from the outside.
Definition: YQTable.cc:258
void selectOrigItem(QTreeWidgetItem *listViewItem)
Select the original item (the YTableItem) that corresponds to the specified listViewItem.
Definition: YQTable.cc:271
static YQUI * ui()
Access the global Qt-UI.
Definition: YQUI.h:83
void sendEvent(YEvent *event)
Widget event handlers (slots) call this when an event occured that should be the answer to a UserInpu...
Definition: YQUI.cc:480
static YQApplication * yqApp()
Return the global YApplication object as YQApplication.
Definition: YQUI.cc:268
QIcon loadIcon(const string &iconName) const
Load an icon.
Definition: YQUI.cc:708