Loading [MathJax]/jax/output/NativeMML/config.js
Isis 3 Programmer Reference
TableViewHeader.cpp
1 
7 /* SPDX-License-Identifier: CC0-1.0 */
8 
9 #include "IsisDebug.h"
10 
11 #include "TableViewHeader.h"
12 
13 #include <iostream>
14 
15 #include <QAbstractItemModel>
16 #include <QFontMetrics>
17 #include <QLabel>
18 #include <QLinearGradient>
19 #include <QLocale>
20 #include <QMessageBox>
21 #include <QMouseEvent>
22 #include <QPainter>
23 #include <QPen>
24 #include <QRect>
25 #include <QString>
26 #include <QVBoxLayout>
27 
28 #include "AbstractTableModel.h"
29 #include "AbstractTreeModel.h"
30 #include "TableColumn.h"
31 #include "TableColumnList.h"
32 #include "TableView.h"
33 
34 
35 namespace Isis {
42  nullify();
43 
44  m_horizontalOffset = 0;
45  m_filterProgress = 0;
46  m_filterProgressMin = 0;
47  m_filterProgressMax = 0;
48  m_rebuildProgress = 0;
49  m_rebuildProgressMin = 0;
50  m_rebuildProgressMax = 0;
51  m_sortProgress = 0;
52  m_sortProgressMin = 0;
53  m_sortProgressMax = 0;
54  m_visibleCount = -1;
55  m_totalCount = -1;
56 
57  m_clickedColumnEdge = -1;
58  m_clickedColumn = -1;
59 
60  setMouseTracking(true);
61 
62  setModel(someModel);
63 
64  ARROW_HEIGHT = 3;
65  ARROW_WIDTH = 5;
66  }
67 
68 
73  m_columns = NULL;
74  }
75 
76 
83  m_columns = cols;
84  }
85 
86 
93  return QSize(0, QFontMetrics(font()).height() + 6);
94  /*QFontMetrics(font()).width(text->join("")) + 15,
95  QFontMetrics(font()).height() + 6);*/
96  }
97 
98 
107  return minimumSizeHint();
108  }
109 
110 
117  if (m_model) {
118  disconnect(m_model, SIGNAL(filterProgressChanged(int)),
119  this, SLOT(updateFilterProgress(int)));
120  disconnect(m_model, SIGNAL(rebuildProgressChanged(int)),
121  this, SLOT(updateRebuildProgress(int)));
122  disconnect(m_model, SIGNAL(sortProgressChanged(int)),
123  this, SLOT(updateSortProgress(int)));
124  disconnect(m_model, SIGNAL(filterProgressRangeChanged(int, int)),
125  this, SLOT(updateFilterProgressRange(int, int)));
126  disconnect(m_model, SIGNAL(rebuildProgressRangeChanged(int, int)),
127  this, SLOT(updateRebuildProgressRange(int, int)));
128  disconnect(m_model, SIGNAL(sortProgressRangeChanged(int, int)),
129  this, SLOT(updateSortProgressRange(int, int)));
130  disconnect(m_model, SIGNAL(filterCountsChanged(int, int)),
131  this, SLOT(handleFilterCountsChanged(int, int)));
132  disconnect(this, SIGNAL(requestedGlobalSelection(bool)),
133  m_model, SLOT(setGlobalSelection(bool)));
134  disconnect(m_model, SIGNAL(m_modelModified()),
135  this, SLOT(update()));
136  }
137 
138  m_model = someModel;
139 
140  connect(m_model, SIGNAL(filterProgressChanged(int)),
141  this, SLOT(updateFilterProgress(int)));
142  connect(m_model, SIGNAL(rebuildProgressChanged(int)),
143  this, SLOT(updateRebuildProgress(int)));
144  connect(m_model, SIGNAL(sortProgressChanged(int)),
145  this, SLOT(updateSortProgress(int)));
146  connect(m_model, SIGNAL(filterProgressRangeChanged(int, int)),
147  this, SLOT(updateFilterProgressRange(int, int)));
148  connect(m_model, SIGNAL(rebuildProgressRangeChanged(int, int)),
149  this, SLOT(updateRebuildProgressRange(int, int)));
150  connect(m_model, SIGNAL(sortProgressRangeChanged(int, int)),
151  this, SLOT(updateSortProgressRange(int, int)));
152  connect(m_model, SIGNAL(filterCountsChanged(int, int)),
153  this, SLOT(handleFilterCountsChanged(int, int)));
154  connect(this, SIGNAL(requestedGlobalSelection(bool)),
155  m_model, SLOT(setGlobalSelection(bool)));
156  connect(m_model, SIGNAL(modelModified()), this, SLOT(update()));
157 
158 
159  if (m_columns) {
160  for (int i = 0; i < m_columns->size(); i++) {
161  disconnect((*m_columns)[i], SIGNAL(visibilityChanged()),
162  this, SLOT(update()));
163  }
164  }
165 
166  m_columns = m_model->getColumns();
167 
168  for (int i = 0; i < m_columns->size(); i++)
169  connect((*m_columns)[i], SIGNAL(visibilityChanged()), this, SLOT(update()));
170  }
171 
172 
180  int visibleTopLevelItemCount, int topLevelItemCount) {
181  m_visibleCount = visibleTopLevelItemCount;
182  m_totalCount = topLevelItemCount;
183 
184  if (m_visibleCount >= 0) {
185  TableColumnList visibleCols = m_columns->getVisibleColumns();
186  for (int i = 0; i < visibleCols.size(); i++) {
187  TableColumn *& col = visibleCols[i];
188 
189  if (col->getTitle().isEmpty())
190  col->setWidth(QFontMetrics(font()).width(
191  QString::number(m_visibleCount)) + 22);
192  }
193  }
194 
195  updateGeometry();
196  update();
197  }
198 
199 
206  m_horizontalOffset = newOffset;
207  update();
208  }
209 
210 
216  void TableViewHeader::mousePressEvent(QMouseEvent *event) {
217  QPoint mousePos = event->pos();
218 
219  m_clickedColumn = getMousedColumn(mousePos);
220 
221  // QRect priorityRect = getSortingPriorityRect(m_clickedColumn);
222  // QRect arrowRect = getSortingArrowRect(m_clickedColumn);
223 
224 
225  if (event->buttons() == Qt::LeftButton) {
226  m_clickedColumnEdge = getMousedColumnEdge(mousePos);
227  if (m_clickedColumnEdge == -1 && m_clickedColumn != -1) {
228  // The click wasn't on a column edge.
229  if (m_columns->getVisibleColumns()[m_clickedColumn]->getTitle().isEmpty()) {
230  emit requestedGlobalSelection(true);
231  }
232  else {
233  // if (priorityRect.contains(mousePos))
234  // {
235  // emit requestedColumnSelection(m_clickedColumn, true);
236  // }
237 
238  }
239  }
240  }
241  }
242 
243 
249  void TableViewHeader::mouseMoveEvent(QMouseEvent *event) {
250  QPoint mousePos = event->pos();
251 
252  if (m_clickedColumnEdge >= 0) {
253  // edge == column that we want to resize
254  QRect columnToResizeRect(getColumnRect(m_clickedColumnEdge));
255  columnToResizeRect.setRight(mousePos.x());
256 
257  TableColumn *col = m_columns->getVisibleColumns()[m_clickedColumnEdge];
258 
259  int newWidth = 1;
260  if (columnToResizeRect.width() > 1) {
261  newWidth = columnToResizeRect.width();
262  if (m_columns->getSortingOrder()[0] == col)
263  newWidth = qMax(newWidth, ARROW_WIDTH + SORT_ARROW_MARGIN * 2);
264  }
265 
266  m_columns->getVisibleColumns()[m_clickedColumnEdge]->setWidth(newWidth);
267  }
268 
269  if (mouseAtResizableColumnEdge(mousePos)) {
270  setCursor(Qt::SizeHorCursor);
271  }
272  else {
273  setCursor(Qt::ArrowCursor);
274  }
275 
276  update();
277  }
278 
279 
285  void TableViewHeader::mouseReleaseEvent(QMouseEvent *event) {
286  bool wasLastCol =
287  m_clickedColumnEdge >= m_columns->getVisibleColumns().size() - 2;
288  if (m_clickedColumnEdge != -1) {
289  emit columnResized(wasLastCol);
290  }
291  else {
292  if (m_clickedColumn == getMousedColumn(event->pos())) {
293  TableColumn *col = m_columns->getVisibleColumns()[m_clickedColumn];
294 
295  TableColumn const *sortCol =
296  m_columns->getVisibleColumns().getSortingOrder()[0];
297 
298  if (col == sortCol)
299  col->setSortAscending(!col->sortAscending());
300  else
301  m_columns->raiseToTop(col);
302 
303  if (!m_model->sortingOn()) {
304  QMessageBox::information(this, tr("Sorting Disabled"),
305  tr("Sorting is currently disabled for this table. Please configure your sorting "
306  "options before trying to sort by [<font color='red'>%1</font>].")
307  .arg(col->getTitle()),
308  QMessageBox::Ok);
309  }
310  }
311  }
312 
313  m_clickedColumnEdge = -1;
314  m_clickedColumn = -1;
315 
316  update();
317  }
318 
319 
325  void TableViewHeader::paintEvent(QPaintEvent *event) {
326  QPainter painter(this);
327  painter.setRenderHints(QPainter::Antialiasing |
328  QPainter::TextAntialiasing);
329 
330  ARROW_HEIGHT = qMax(height() / 5, 3);
331  ASSERT(height() > 8);
332  ARROW_WIDTH = ARROW_HEIGHT * 2 - 1;
333 
334  paintHeader(&painter, height());
335  // painter.drawRect(0, 0, width(), height());
336  painter.end();
337  }
338 
339 
344  m_model = NULL;
345  m_columns = NULL;
346  }
347 
348 
356  QRect TableViewHeader::getColumnRect(int column) const {
357  QRect colRect;
358 
359  TableColumnList visibleCols = m_columns->getVisibleColumns();
360 
361  if (column < visibleCols.size() && column >= 0) {
362  int indent = 1;
363 
364  for (int i = 0; i < column; i++)
365  indent += visibleCols[i]->getWidth() - 1;
366 
367  colRect = QRect(indent - m_horizontalOffset, 0,
368  visibleCols[column]->getWidth(), height());
369  }
370 
371  return colRect;
372  }
373 
374 
382  int TableViewHeader::getMousedColumn(QPoint mousePos) {
383  int mousedColumn = -1;
384 
385  for (int i = 0;
386  i < m_columns->getVisibleColumns().size() && mousedColumn < 0;
387  i++) {
388  QRect columnRect(getColumnRect(i));
389  if (columnRect.contains(mousePos))
390  mousedColumn = i;
391  }
392 
393  return mousedColumn;
394  }
395 
396 
405  int edge = -1;
406 
407  if (mouseAtResizableColumnEdge(mousePos)) {
408  int mousedColumn = getMousedColumn(mousePos);
409 
410  QRect columnRect(getColumnRect(mousedColumn));
411 
412  // mouseAtResizableColumnEdge can't be on left of first so this won't
413  // return -1 resulting from this particular logic.
414  if (mousePos.x() - columnRect.left() < TableColumn::EDGE_WIDTH)
415  edge = mousedColumn - 1;
416  else
417  edge = mousedColumn;
418  }
419 
420  return edge;
421  }
422 
423 
432  int columnNum = getMousedColumn(mousePos);
433 
434  QRect columnRect(getColumnRect(columnNum));
435 
436  bool isAtColumnEdge = false;
437 
438  if (!columnRect.isNull()) {
439  bool isOnLeft =
440  mousePos.x() - columnRect.left() < TableColumn::EDGE_WIDTH;
441  bool isOnRight =
442  columnRect.right() - mousePos.x() < TableColumn::EDGE_WIDTH;
443  bool isResizable = false;
444 
445  TableColumnList visCols = m_columns->getVisibleColumns();
446  if (isOnLeft && columnNum > 0)
447  isResizable = visCols[columnNum - 1]->getTitle().size();
448  else if (isOnRight)
449  isResizable = visCols[columnNum]->getTitle().size();
450 
451  isAtColumnEdge = (isOnLeft || isOnRight) && isResizable;
452  }
453 
454  return isAtColumnEdge;
455  }
456 
457 
464  void TableViewHeader::paintHeader(QPainter *painter, int rowHeight) {
465  int visibleColWidth = -m_horizontalOffset;
466  TableColumnList visibleCols = m_columns->getVisibleColumns();
467 
468  for (int i = 0; i < visibleCols.size(); i++)
469  visibleColWidth += visibleCols[i]->getWidth() - 1;
470 
471  QRect rect(0, 0, qMin(width(), visibleColWidth), rowHeight);
472 
473  int x = rect.center().x();
474  QLinearGradient gradient(x, rect.top(), x, rect.bottom());
475 
476  //FIXME: selected needs to be member variable
477  bool selected = false;
478  QColor color = selected ? palette().highlight().color() :
479  palette().button().color();
480 
481  // create gradient and fill header area with it
482  int adjustment = 110;
483  gradient.setColorAt(0, color.lighter(adjustment));
484  gradient.setColorAt(1, color.darker(adjustment));
485  painter->fillRect(rect, gradient);
486 
487  // Save off composition mode and brush, which will need to be restored
488  // after the progress is painted.
489  QBrush brush = painter->brush();
490  QPainter::CompositionMode compMode = painter->compositionMode();
491  painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
492 
493  // draw filter progress (if not at 100%)
494  painter->setBrush(QBrush(QColor(0, 70, 100, 30)));
495  paintProgress(painter, rect, m_filterProgressMin, m_filterProgressMax,
496  m_filterProgress, false);
497 
498  // draw rebuild progress (if not at 100%)
499  painter->setBrush(QBrush(QColor(100, 70, 0, 30)));
500  paintProgress(painter, rect, m_rebuildProgressMin, m_rebuildProgressMax,
501  m_rebuildProgress, false);
502 
503  // draw sort progress (if not at 100%)
504  painter->setBrush(QBrush(QColor(0, 100, 0, 30)));
505  paintProgress(painter, rect, m_sortProgressMin, m_sortProgressMax,
506  m_sortProgress, true);
507 
508  // draw the header's text. A rect will be drawn for each of the m_columns,
509  // with the column text in the center of it.
510  painter->setBrush(brush);
511  painter->setCompositionMode(compMode);
512 
513  for (int i = 0; i < visibleCols.size(); i++) {
514  TableColumn *visibleCol = visibleCols[i];
515 
516  QString columnText = visibleCol->getTitle();
517  QRect columnRect(getColumnRect(visibleCols.indexOf(visibleCol)));
518  QPen pen(palette().dark().color().darker(150));
519  pen.setCapStyle(Qt::RoundCap);
520  painter->setPen(pen);
521  painter->drawLine(columnRect.topLeft() + QPoint(0, 1),
522  columnRect.bottomLeft() + QPoint(0, 1));
523 
524  painter->drawLine(columnRect.topLeft() + QPoint(1, 0),
525  columnRect.topRight() - QPoint(0, 0));
526 
527  painter->drawLine(columnRect.topLeft() + QPoint(1, 1),
528  columnRect.topRight() + QPoint(0, 1));
529 
530  painter->drawLine(columnRect.bottomLeft() + QPoint(1, 1),
531  columnRect.bottomRight() + QPoint(0, 1));
532 
533  painter->drawLine(columnRect.bottomLeft() + QPoint(1, 1),
534  columnRect.bottomRight() + QPoint(0, 1));
535 
536  painter->drawLine(columnRect.topRight() + QPoint(0, 1),
537  columnRect.bottomRight() - QPoint(0, 0));
538 
539  painter->setPen(selected ? palette().highlightedText().color() :
540  palette().buttonText().color());
541 
542  QRect textRect(columnRect.x(),
543  columnRect.y(),
544  columnRect.width() - (SORT_ARROW_MARGIN * 2 + ARROW_WIDTH),
545  columnRect.height());
546  painter->drawText(textRect , Qt::AlignCenter | Qt::TextSingleLine,
547  columnText);
548 
549  if (visibleCol == visibleCols.getSortingOrder()[0] &&
550  visibleCol->getWidth() >= SORT_ARROW_MARGIN * 2 + ARROW_WIDTH) {
551  ASSERT(SORT_ARROW_MARGIN > 0);
552 
553  QRect arrowRect(textRect.right() + 1,
554  textRect.y(),
555  SORT_ARROW_MARGIN * 2 + ARROW_WIDTH,
556  textRect.height());
557 
558  ASSERT(arrowRect.width() + textRect.width() == columnRect.width());
559  ASSERT(arrowRect.right() == columnRect.right());
560 
561 
562  // assume ascending order (arrow looks like v)
563  QPoint left(arrowRect.left() + SORT_ARROW_MARGIN,
564  arrowRect.center().y() - ((ARROW_HEIGHT - 1) / 2));
565 
566  int yOffSet = ((ARROW_HEIGHT - 1) / 2);
567  if (ARROW_HEIGHT % 2 == 0)
568  yOffSet++;
569  QPoint center(left.x() + ((ARROW_WIDTH - 1) / 2),
570  arrowRect.center().y() + yOffSet);
571 
572  QPoint right(center.x() + ((ARROW_WIDTH - 1) / 2),
573  arrowRect.center().y() - ((ARROW_HEIGHT - 1) / 2));
574 
575  ASSERT(right.x() == arrowRect.right() - SORT_ARROW_MARGIN);
576  ASSERT(right.x() - center.x() == center.x() - left.x());
577 
578  if (!visibleCol->sortAscending()) {
579  // flip arrow (to look like ^)
580  left.setY(center.y());
581  center.setY(right.y());
582  right.setY(left.y());
583  }
584 
585  if (m_model->sortingOn()) {
586  painter->drawLine(left, center);
587  painter->drawLine(center, right);
588  }
589  }
590 
591  // Move the column rect to the position of the next column.
592  columnRect.moveLeft(columnRect.right());
593  }
594  }
595 
596 
607  void TableViewHeader::paintProgress(QPainter *painter,
608  const QRect &rect, int min, int max, int value, bool over100) {
609  double progressPercent = 1.0;
610  int progressRange = max - min;
611 
612  if (progressRange > 0)
613  progressPercent = ((double)(value - min)) / progressRange;
614  else if (progressRange == 0)
615  progressPercent = 0;
616 
617  if (progressPercent < 1.0 || over100) {
618  QRect progressRect(rect);
619  progressRect.setWidth((int)(progressRect.width() * progressPercent));
620  painter->fillRect(progressRect, painter->brush());
621  }
622  }
623 
624 
631  m_filterProgress = newProgress;
632  update();
633  }
634 
635 
643  m_filterProgressMin = min;
644  m_filterProgressMax = max;
645  update();
646  }
647 
648 
655  m_rebuildProgress = newProgress;
656  update();
657  }
658 
659 
667  m_rebuildProgressMin = min;
668  m_rebuildProgressMax = max;
669  update();
670  }
671 
672 
678  void TableViewHeader::updateSortProgress(int newProgress) {
679  m_sortProgress = newProgress;
680  update();
681  }
682 
683 
691  m_sortProgressMin = min;
692  m_sortProgressMax = max;
693  update();
694  }
695 }
Isis::TableViewHeader::updateFilterProgressRange
void updateFilterProgressRange(int min, int max)
Updates the range of the filter progress.
Definition: TableViewHeader.cpp:642
Isis::TableViewHeader::mousePressEvent
void mousePressEvent(QMouseEvent *event)
Overrides QWidget::mousePressEvent.
Definition: TableViewHeader.cpp:216
Isis::TableViewHeader::sizeHint
QSize sizeHint() const
Returns the minimum size based on the font.
Definition: TableViewHeader.cpp:106
Isis::TableViewHeader::mouseMoveEvent
void mouseMoveEvent(QMouseEvent *event)
Overrides QWidget::mouseMoveEvent.
Definition: TableViewHeader.cpp:249
Isis::TableColumn
Definition: TableColumn.h:26
Isis::TableViewHeader::updateRebuildProgressRange
void updateRebuildProgressRange(int min, int max)
Updates the range of the rebuild progress.
Definition: TableViewHeader.cpp:666
Isis::TableViewHeader::setModel
void setModel(AbstractTableModel *someModel)
Connects the table model to the functions that handle changes.
Definition: TableViewHeader.cpp:116
Isis::AbstractTableModel
Translates the tree model into a table model.
Definition: AbstractTableModel.h:48
Isis::TableViewHeader::mouseReleaseEvent
void mouseReleaseEvent(QMouseEvent *event)
Overrides QWidget::mouseReleaseEvent.
Definition: TableViewHeader.cpp:285
Isis::TableViewHeader::updateHeaderOffset
void updateHeaderOffset(int)
Updates the header offset.
Definition: TableViewHeader.cpp:205
Isis::TableViewHeader::paintHeader
void paintHeader(QPainter *painter, int rowheight)
Repaints the header.
Definition: TableViewHeader.cpp:464
Isis::TableViewHeader::~TableViewHeader
virtual ~TableViewHeader()
Destructor.
Definition: TableViewHeader.cpp:72
Isis::TableViewHeader::paintProgress
void paintProgress(QPainter *painter, const QRect &rect, int min, int max, int value, bool over100)
Updates the progress bar.
Definition: TableViewHeader.cpp:607
Isis::TableViewHeader::TableViewHeader
TableViewHeader(AbstractTableModel *someModel)
Constructor.
Definition: TableViewHeader.cpp:41
Isis::TableViewHeader::nullify
void nullify()
Sets all the member variables to NULL.
Definition: TableViewHeader.cpp:343
Isis::TableViewHeader::getMousedColumn
int getMousedColumn(QPoint mousePos)
Returns the column under the mouse.
Definition: TableViewHeader.cpp:382
Isis::TableViewHeader::mouseAtResizableColumnEdge
bool mouseAtResizableColumnEdge(QPoint mousePos)
Returns if the mouse is at the edge of a resizeable column.
Definition: TableViewHeader.cpp:431
Isis::TableViewHeader::updateFilterProgress
void updateFilterProgress(int newProgress)
Updates the current filter progress value.
Definition: TableViewHeader.cpp:630
Isis::TableViewHeader::paintEvent
void paintEvent(QPaintEvent *event)
Repaints the header.
Definition: TableViewHeader.cpp:325
Isis::TableViewHeader::updateSortProgress
void updateSortProgress(int newProgress)
Updates the current sort progress value.
Definition: TableViewHeader.cpp:678
Isis::TableViewHeader::minimumSizeHint
QSize minimumSizeHint() const
Returns the minimum size based on the font.
Definition: TableViewHeader.cpp:92
Isis::TableViewHeader::handleFilterCountsChanged
void handleFilterCountsChanged(int visibleTopLevelItemCount, int topLevelItemCount)
Updates the visible columns, and geometry when the filter count changes.
Definition: TableViewHeader.cpp:179
Isis::TableColumnList
Definition: TableColumnList.h:30
Isis::TableViewHeader::updateRebuildProgress
void updateRebuildProgress(int newProgress)
Updates the current rebuild progress value.
Definition: TableViewHeader.cpp:654
Isis::TableViewHeader::getColumnRect
QRect getColumnRect(int column) const
Returns the visible column rectangle.
Definition: TableViewHeader.cpp:356
Isis::TableViewHeader::setColumns
virtual void setColumns(TableColumnList *)
Sets the column list.
Definition: TableViewHeader.cpp:82
Isis::TableViewHeader::updateSortProgressRange
void updateSortProgressRange(int min, int max)
Updates the range of the sort progress.
Definition: TableViewHeader.cpp:690
Isis::TableViewHeader::getMousedColumnEdge
int getMousedColumnEdge(QPoint mousePos)
Returns the edge of the column under the mouse.
Definition: TableViewHeader.cpp:404
Isis
This is free and unencumbered software released into the public domain.
Definition: Apollo.h:16

U.S. Department of the Interior | U.S. Geological Survey
ISIS | Privacy & Disclaimers | Astrogeology Research Program
To contact us, please post comments and questions on the USGS Astrogeology Discussion Board
To report a bug, or suggest a feature go to: ISIS Github
File Modified: 07/13/2023 15:17:22