libyui-mga-qt  1.0.2
YMGA_QCBTable.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: YMGA_QCBTable.cc
20 
21  Author: Angelo Naselli <anaselli@linux.it>
22 
23 /-*/
24 
25 #include <QHeaderView>
26 #include <QVBoxLayout>
27 #include <QString>
28 #define YUILogComponent "mga-qt-ui"
29 #include <yui/YUILog.h>
30 
31 #include <yui/qt/utf8.h>
32 
33 #include <yui/qt/YQUI.h>
34 #include <yui/YEvent.h>
35 #include <yui/qt/YQSignalBlocker.h>
36 #include <yui/YUIException.h>
37 
38 #include "YMGA_QCBTable.h"
39 #include <yui/qt/YQApplication.h>
40 
41 
43 {
44  ///< offset to first YCell
45  /// usually 1 if checkbox Enabled and mode is YCBTableCheckBoxOnFirstColumn
46  /// 0 otherwise
47  unsigned int firstColumnOffset;
48 };
49 
50 
51 YMGA_QCBTable::YMGA_QCBTable( YWidget * parent, YTableHeader * tableHeader, YCBTableMode tableMode )
52  : QFrame( (QWidget *) parent->widgetRep() )
53  , YMGA_CBTable( parent, tableHeader, tableMode ), _qt_listView(0), d(new Private)
54 {
55  YUI_CHECK_NEW ( d );
56 
57  setWidgetRep ( this );
58  QVBoxLayout* layout = new QVBoxLayout ( this );
59  layout->setSpacing ( 0 );
60  setLayout ( layout );
61 
62  layout->setMargin ( YQWidgetMargin );
63 
64  _qt_listView = new QY2ListView ( this );
65  YUI_CHECK_NEW ( _qt_listView );
66  layout->addWidget ( _qt_listView );
67  _qt_listView->setAllColumnsShowFocus ( true );
68  _qt_listView->header()->setStretchLastSection ( false );
69 
70  setKeepSorting ( keepSorting() );
71 
72  d->firstColumnOffset = 0;
73 
74  yuiMilestone() << " Slection mode " << tableMode << std::endl;
75 
76  if ( tableMode == YCBTableCheckBoxOnFirstColumn )
77  {
78  d->firstColumnOffset = 1;
79  }
80 
81  _qt_listView->setContextMenuPolicy ( Qt::CustomContextMenu );
82 
83  //
84  // Add columns
85  //
86 
87  QStringList headers;
88  _qt_listView->setColumnCount ( columns() );
89 
90  // YCBTable needs header also for the checkable column
91  for ( int i=0; i < columns(); i++ )
92  {
93  headers << fromUTF8 ( header ( i ) );
94  }
95 
96  _qt_listView->setHeaderLabels ( headers );
97  _qt_listView->header()->setSectionResizeMode ( QHeaderView::Interactive );
98  _qt_listView->sortItems ( 0, Qt::AscendingOrder );
99 
100  //
101  // Connect signals and slots
102  //
103 
104  connect ( _qt_listView, SIGNAL ( itemDoubleClicked ( QTreeWidgetItem *, int ) ),
105  this, SLOT ( slotActivated ( QTreeWidgetItem *, int ) ) );
106 
107  connect ( _qt_listView, SIGNAL ( itemClicked ( QTreeWidgetItem *, int ) ),
108  this, SLOT ( slotcolumnClicked ( QTreeWidgetItem *, int ) ) );
109 
110  connect ( _qt_listView, SIGNAL ( currentItemChanged ( QTreeWidgetItem *, QTreeWidgetItem * ) ),
111  this, SLOT ( slotSelected ( QTreeWidgetItem * ) ) );
112 
113  connect ( _qt_listView, SIGNAL ( customContextMenuRequested ( const QPoint & ) ),
114  this, SLOT ( slotContextMenu ( const QPoint & ) ) );
115 
116 }
117 
118 
120 {
121  delete d;
122 }
123 
125 {
126  int column = (d->firstColumnOffset == 1) ? 0 : columns() -1;
127 
128  return column;
129 }
130 
131 
132 
133 void
134 YMGA_QCBTable::setKeepSorting( bool keepSorting )
135 {
136  YMGA_CBTable::setKeepSorting( keepSorting );
137  _qt_listView->setSortByInsertionSequence( keepSorting );
138  _qt_listView->setSortingEnabled( ! keepSorting );
139 }
140 
141 
142 void
143 YMGA_QCBTable::addItem( YItem * yitem )
144 {
145  addItem ( yitem,
146  false, // batchMode
147  true ); // resizeColumnsToContent
148 }
149 
150 
151 void
152 YMGA_QCBTable::addItem( YItem * yitem, bool batchMode, bool resizeColumnsToContent )
153 {
154  YCBTableItem * item = dynamic_cast<YCBTableItem *> ( yitem );
155  YUI_CHECK_PTR ( item );
156 
157  YMGA_CBTable::addItem ( item );
158 
159  YMGA_QCBTableListViewItem * clone = new YMGA_QCBTableListViewItem ( this, _qt_listView, item );
160  YUI_CHECK_NEW ( clone );
161 
162  if ( ! batchMode && item->selected() )
163  {
164  // YTable enforces single selection, if appropriate
165 
166  YQSignalBlocker sigBlocker ( _qt_listView );
167  YMGA_QCBTable::selectItem ( YSelectionWidget::selectedItem(), true );
168  }
169 
170 
171  //
172  // Set column alignment
173  //
174 
175  for ( int col=0; col < columns(); col++ )
176  {
177  switch ( alignment ( col ) )
178  {
179  case YAlignBegin:
180  clone->setTextAlignment ( col, Qt::AlignLeft | Qt::AlignVCenter );
181  break;
182  case YAlignCenter:
183  clone->setTextAlignment ( col, Qt::AlignCenter | Qt::AlignVCenter );
184  break;
185  case YAlignEnd:
186  clone->setTextAlignment ( col, Qt::AlignRight | Qt::AlignVCenter );
187  break;
188 
189  case YAlignUnchanged:
190  break;
191  }
192  }
193 
194  if ( ! batchMode )
195  _qt_listView->sortItems ( 0, Qt::AscendingOrder );
196 
197  if ( resizeColumnsToContent )
198  {
199  for ( int i=0; i < columns(); i++ )
200  _qt_listView->resizeColumnToContents ( i );
201  /* NOTE: resizeColumnToContents(...) is performance-critical ! */
202  }
203 }
204 
205 
206 void
207 YMGA_QCBTable::addItems( const YItemCollection & itemCollection )
208 {
209  YQSignalBlocker sigBlocker ( _qt_listView );
210 
211  for ( YItemConstIterator it = itemCollection.begin();
212  it != itemCollection.end();
213  ++it )
214  {
215  addItem ( *it,
216  true, // batchMode
217  false ); // resizeColumnsToContent
218  /* NOTE: resizeToContents=true would cause a massive performance drop !
219  => resize columns to content only one time at the end of this
220  function */
221  }
222 
223  YItem * sel = YSelectionWidget::selectedItem();
224 
225  if ( sel )
226  YMGA_QCBTable::selectItem ( sel, true );
227 
228  for ( int i=0; i < columns(); i++ )
229  _qt_listView->resizeColumnToContents ( i );
230 }
231 
232 
233 void YMGA_QCBTable::selectItem ( YItem * yitem, bool selected )
234 {
235  YQSignalBlocker sigBlocker ( _qt_listView );
236 
237  YCBTableItem * item = dynamic_cast<YCBTableItem *> ( yitem );
238  YUI_CHECK_PTR ( item );
239 
240  YMGA_QCBTableListViewItem * clone = ( YMGA_QCBTableListViewItem * ) item->data();
241  YUI_CHECK_PTR ( clone );
242 
243  if ( ! selected && clone == _qt_listView->currentItem() )
244  {
246  }
247  else
248  {
249  if ( ! hasMultiSelection() )
250  _qt_listView->setCurrentItem ( clone ); // This deselects all other items!
251 
252  clone->setSelected ( true );
253  YMGA_CBTable::selectItem ( item, selected );
254  }
255 }
256 
257 void YMGA_QCBTable::checkItem ( YItem* yitem, bool checked )
258 {
259  YQSignalBlocker sigBlocker ( _qt_listView );
260 
261  YCBTableItem * item = dynamic_cast<YCBTableItem *> ( yitem );
262  YUI_CHECK_PTR ( item );
263 
264  YMGA_QCBTableListViewItem * clone = ( YMGA_QCBTableListViewItem * ) item->data();
265  YUI_CHECK_PTR ( clone );
266 
267  item->check(checked);
268  clone->setCheckState ( checkboxItemColumn(), checked ? Qt::CheckState::Checked : Qt::CheckState::Unchecked );
269 }
270 
271 
272 void
274 {
275  YQSignalBlocker sigBlocker( _qt_listView );
276 
277  YMGA_CBTable::deselectAllItems();
278  _qt_listView->clearSelection();
279 }
280 
281 
282 void
284 {
285  _qt_listView->clear();
286  YMGA_CBTable::deleteAllItems();
287 }
288 
289 
290 void
291 YMGA_QCBTable::cellChanged( const YTableCell * cell )
292 {
293  YCBTableItem * item = dynamic_cast<YCBTableItem*>(cell->parent());
294  YUI_CHECK_PTR( item );
295 
296  YMGA_QCBTableListViewItem * clone = (YMGA_QCBTableListViewItem *) item->data();
297  YUI_CHECK_PTR( clone );
298 
299  clone->updateCell( cell );
300 }
301 
302 
303 void YMGA_QCBTable::selectOrigItem( QTreeWidgetItem * listViewItem )
304 {
305  if ( listViewItem )
306  {
307  YMGA_QCBTableListViewItem * tableListViewItem = dynamic_cast<YMGA_QCBTableListViewItem *> ( listViewItem );
308  YUI_CHECK_PTR ( tableListViewItem );
309 
310  YMGA_CBTable::selectItem ( tableListViewItem->origItem(), true );
311  if ( ! hasMultiSelection() )
312  _qt_listView->setCurrentItem( listViewItem );
313  }
314 }
315 
316 
317 void YMGA_QCBTable::slotSelected ( QTreeWidgetItem * listViewItem )
318 {
319  if ( listViewItem )
320  selectOrigItem ( listViewItem );
321  else
322  {
323  // Qt might select nothing if a user clicks outside the items in the widget
324 
325  if ( hasItems() && YSelectionWidget::hasSelectedItem() )
326  YMGA_QCBTable::selectItem ( YSelectionWidget::selectedItem(), true );
327  }
328 
329  if ( immediateMode() )
330  {
331  if ( ! YQUI::ui()->eventPendingFor ( this ) )
332  {
333  // Avoid overwriting a (more important) Activated event with a SelectionChanged event
334 
335  yuiDebug() << "Sending SelectionChanged event" << std::endl;
336  YQUI::ui()->sendEvent ( new YWidgetEvent ( this, YEvent::SelectionChanged ) );
337  }
338  }
339 }
340 
341 void YMGA_QCBTable::slotActivated( QTreeWidgetItem * listViewItem, int column )
342 {
343  selectOrigItem( listViewItem );
344  if ( notify() )
345  {
346  yuiDebug() << "Sending Activated event" << std::endl;
347  YQUI::ui()->sendEvent( new YWidgetEvent( this, YEvent::Activated ) );
348  }
349 }
350 
351 
352 void
353 YMGA_QCBTable::slotcolumnClicked(QTreeWidgetItem* item,
354  int col)
355 {
356  selectOrigItem( item );
357 
358  if ( col == checkboxItemColumn() )
359  {
360  YMGA_QCBTableListViewItem * it = dynamic_cast<YMGA_QCBTableListViewItem*> ( item );
361  Qt::CheckState checked = item->checkState ( col );
362  YCBTableItem *pYCBTableItem = it->origItem();
363 
364  yuiDebug() << "Column is checked: " << (checked == Qt::CheckState::Checked?"yes":"no" ) << std::endl;
365 
366  // it seems items contains old value when signal is emitted
367  pYCBTableItem->check ( checked == Qt::CheckState::Checked );
368 
369  if ( notify() )
370  {
371  YMGA_CBTable::setChangedItem ( pYCBTableItem );
372  YQUI::ui()->sendEvent ( new YWidgetEvent ( this, YEvent::ValueChanged ) );
373  }
374  }
375 }
376 
377 
378 void
380 {
381  _qt_listView->setEnabled( enabled );
382  //FIXME _qt_listView->triggerUpdate();
383  YWidget::setEnabled( enabled );
384 }
385 
386 
387 
388 int
390 {
391  // Arbitrary value.
392  // Use a MinSize widget to set a size that is useful for the application.
393 
394  return 30;
395 }
396 
397 
398 int
400 {
401  // Arbitrary value.
402  // Use a MinSize widget to set a size that is useful for the application.
403 
404  return 100;
405 }
406 
407 
408 void
409 YMGA_QCBTable::setSize( int newWidth, int newHeight )
410 {
411  resize( newWidth, newHeight );
412 }
413 
414 
415 bool
417 {
418  _qt_listView->setFocus();
419 
420  return true;
421 }
422 
423 
424 void
425 YMGA_QCBTable::slotContextMenu ( const QPoint & pos )
426 {
427  if ( ! _qt_listView || ! _qt_listView->viewport() )
428  return;
429 
430  YQUI::yqApp()->setContextMenuPos( _qt_listView->viewport()->mapToGlobal( pos ) );
431  if ( notifyContextMenu() )
432  YQUI::ui()->sendEvent( new YWidgetEvent( this, YEvent::ContextMenuActivated ) );
433 }
434 
435 
437  QY2ListView * parent,
438  YCBTableItem * origItem )
439  : QY2ListViewItem( parent )
440  , _table( table )
441  , _origItem( origItem )
442 {
443  YUI_CHECK_PTR( _table );
444  YUI_CHECK_PTR( _origItem );
445 
446  _origItem->setData( this );
447 
448  yuiDebug() << "Checkable column is " << table->checkboxItemColumn() << std::endl;
449 
450  int table_columns = _table->columns()-2;
451  setCheckState(table->checkboxItemColumn(), _origItem->checked() ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
452 
453  for ( YTableCellIterator it = _origItem->cellsBegin();
454  it != _origItem->cellsEnd();
455  ++it )
456  {
457  YTableCell * cell = *it;
458  // if someone decided to have more cells for this item
459  if (cell->column() > table_columns)
460  {
461  yuiWarning() << "Item contains too many columns, current is " << cell->column()
462  << " but only " << _table->columns() << " columns are configured" << std::endl;
463  }
464  else
465  updateCell( *it );
466  }
467 }
468 
469 
470 void
471 YMGA_QCBTableListViewItem::updateCell( const YTableCell * cell )
472 {
473  if ( ! cell )
474  return;
475 
476  int column = cell->column();
477  YCBTableMode mode = table()->tableMode();
478  if (mode == YCBTableMode::YCBTableCheckBoxOnFirstColumn)
479  column += 1;
480 
481  //
482  // Set label text
483  //
484 
485  setText( column, fromUTF8( cell->label() ) );
486 
487  //
488  // Set icon (if specified)
489  //
490  if ( cell->hasIconName() )
491  {
492  // _table is checked against 0 in the constructor
493 
494  string iconName = _table->iconFullPath( cell->iconName() );
495  QPixmap icon = QPixmap( iconName.c_str() );
496 
497  if ( icon.isNull() )
498  yuiWarning() << "Can't load icon " << iconName << std::endl;
499  else
500  setData( column, Qt::DecorationRole, icon );
501  }
502  else // No pixmap name
503  {
504  if ( ! data( column, Qt::DecorationRole ).isNull() ) // Was there a pixmap before?
505  {
506  setData( column, Qt::DecorationRole, QPixmap() ); // Set empty pixmap
507  }
508  }
509 }
510 
511 
512 #include "YMGA_QCBTable.moc"
unsigned int firstColumnOffset
< offset to first YCell usually 1 if checkbox Enabled and mode is YCBTableCheckBoxOnFirstColumn 0 oth...
virtual void setEnabled(bool enabled)
Set enabled/disabled state.
void slotContextMenu(const QPoint &pos)
Propagate a context menu selection.
virtual void addItem(YItem *item)
Add an item.
void slotSelected(QTreeWidgetItem *)
Notification that an item is selected (single click or keyboard).
virtual void deselectAllItems()
Deselect all items.
virtual ~YMGA_QCBTable()
Destructor.
YMGA_QCBTable * table() const
Return the parent table widget.
virtual int preferredWidth()
Preferred width of the widget.
virtual void cellChanged(const YTableCell *cell)
Notification that a cell (its text and/or its icon) was changed from the outside.
virtual void selectItem(YItem *item, bool selected=true)
Select or deselect an item.
virtual void setKeepSorting(bool keepSorting)
Switch between sorting by item insertion order (keepSorting: true) or allowing the user to sort by an...
virtual int preferredHeight()
Preferred height of the widget.
virtual void setSize(int newWidth, int newHeight)
Set the new size of the widget.
int checkboxItemColumn()
returns which column is managed by checkboxes, if any -1 otherwise
YCBTableItem * origItem() const
Return the corresponding YCBTableItem.
void checkItem(YItem *item, bool checked=true)
check/uncheck Item from application.
virtual bool setKeyboardFocus()
Accept the keyboard focus.
virtual void addItems(const YItemCollection &itemCollection)
Add multiple items.
void updateCell(const YTableCell *cell)
Update this item's display with the content of 'cell'.
YMGA_QCBTable(YWidget *parent, YTableHeader *header, YCBTableMode checkboxMode)
Constructor.
void slotActivated(QTreeWidgetItem *listViewItem, int column)
Notification that an item is activated (double click or keyboard).
void selectOrigItem(QTreeWidgetItem *listViewItem)
Select the original item (the YCBTableItem) that corresponds to the specified listViewItem.
YMGA_QCBTableListViewItem(YMGA_QCBTable *table, QY2ListView *parent, YCBTableItem *origItem)
Constructor.
virtual void deleteAllItems()
Delete all items.
Visual representation of a YCBTableItem.