labplot  2.8.2
About: LabPlot is an application for plotting and analysis of 2D and 3D functions and data. It is a complete rewrite of LabPlot1 and lacks in the first release a lot of features available in the predecessor. On the other hand, the GUI and the usability is more superior.
  Fossies Dox: labplot-2.8.2.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

TreeViewComboBox.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  File : TreeViewComboBox.cpp
3  Project : LabPlot
4  Description : Provides a QTreeView in a QComboBox
5  --------------------------------------------------------------------
6  Copyright : (C) 2008-2016 by Alexander Semke (alexander.semke@web.de)
7  Copyright : (C) 2008 Tilman Benkert (thzs@gmx.net)
8 
9  ***************************************************************************/
10 
11 /***************************************************************************
12  * *
13  * This program is free software; you can redistribute it and/or modify *
14  * it under the terms of the GNU General Public License as published by *
15  * the Free Software Foundation; either version 2 of the License, or *
16  * (at your option) any later version. *
17  * *
18  * This program is distributed in the hope that it will be useful, *
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
21  * GNU General Public License for more details. *
22  * *
23  * You should have received a copy of the GNU General Public License *
24  * along with this program; if not, write to the Free Software *
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, *
26  * Boston, MA 02110-1301 USA *
27  * *
28  ***************************************************************************/
29 
33 #include "backend/lib/macros.h"
34 
35 #include <QEvent>
36 #include <QGroupBox>
37 #include <QHeaderView>
38 #include <QLineEdit>
39 #include <QTreeView>
40 #include <QVBoxLayout>
41 #include <QStylePainter>
42 
43 #include <KLocalizedString>
44 
45 #include <cstring> // strcmp()
46 
47 /*!
48  \class TreeViewComboBox
49  \brief Provides a QTreeView in a QComboBox.
50 
51  \ingroup backend/widgets
52 */
53 TreeViewComboBox::TreeViewComboBox(QWidget* parent) : QComboBox(parent),
54  m_treeView(new QTreeView),
55  m_groupBox(new QGroupBox),
56  m_lineEdit(new QLineEdit) {
57 
58  auto* layout = new QVBoxLayout;
59  layout->setContentsMargins(0, 0, 0, 0);
60  layout->setSpacing(0);
61 
62  layout->addWidget(m_lineEdit);
63  layout->addWidget(m_treeView);
64 
65  m_groupBox->setLayout(layout);
66  m_groupBox->setParent(parent, Qt::Popup);
67  m_groupBox->hide();
68  m_groupBox->installEventFilter(this);
69 
70  m_treeView->header()->hide();
71  m_treeView->setSelectionMode(QAbstractItemView::SingleSelection);
72  m_treeView->setUniformRowHeights(true);
73 
74  m_lineEdit->setPlaceholderText(i18n("Search/Filter text"));
75  m_lineEdit->setClearButtonEnabled(true);
76  m_lineEdit->setFocus();
77 
78  addItem(QString());
79  setCurrentIndex(0);
80  setEditText(m_lineEditText);
81 
82  // signal activated() is platform dependent
83  connect(m_treeView, &QTreeView::pressed, this, &TreeViewComboBox::treeViewIndexActivated);
84  connect(m_lineEdit, &QLineEdit::textChanged, this, &TreeViewComboBox::filterChanged);
85 }
86 
88 {
89  m_topLevelClasses = list;
90 }
91 
93  m_hiddenAspects = list;
94 }
95 
96 /*!
97  Sets the \a model for the view to present.
98 */
99 void TreeViewComboBox::setModel(QAbstractItemModel* model) {
100  m_treeView->setModel(model);
101 
102  //show only the first column in the combo box
103  for (int i = 1; i < model->columnCount(); i++)
104  m_treeView->hideColumn(i);
105 
106  //Expand the complete tree in order to see everything in the first popup.
107  m_treeView->expandAll();
108 
109  setEditText(m_lineEditText);
110 }
111 
112 /*!
113  Sets the current item to be the item at \a index and selects it.
114  \sa currentIndex()
115 */
116 void TreeViewComboBox::setCurrentModelIndex(const QModelIndex& index) {
117  m_treeView->setCurrentIndex(index);
118  QComboBox::setItemText(0, index.data().toString());
119 }
120 
121 /*!
122  Returns the model index of the current item.
123  \sa setCurrentModelIndex()
124 */
126  return m_treeView->currentIndex();
127 }
128 
129 /*!
130  Displays the tree view of items in the combobox.
131  Triggers showTopLevelOnly() to show toplevel items only.
132 */
134  if (!m_treeView->model() || !m_treeView->model()->hasChildren())
135  return;
136 
137  QModelIndex root = m_treeView->model()->index(0,0);
138  showTopLevelOnly(root);
139  m_groupBox->show();
140  m_groupBox->resize(this->width(), 250);
141  m_groupBox->move(mapToGlobal( this->rect().topLeft() ));
142 
143  setEditText(m_lineEditText);
144  m_lineEdit->setText(""); //delete the previous search string
145  m_lineEdit->setFocus();
146 }
147 
148 /*!
149  \reimp
150  TODO: why do I have to reimplement paintEvent. It should work
151  also without
152 */
153 void TreeViewComboBox::paintEvent(QPaintEvent *)
154 {
155  QStylePainter painter(this);
156  painter.setPen(palette().color(QPalette::Text));
157  // draw the combobox frame, focusrect and selected etc.
158  QStyleOptionComboBox opt;
159  initStyleOption(&opt);
160  opt.currentText = currentText(); // TODO: why it's not working when letting this away?
161  painter.drawComplexControl(QStyle::CC_ComboBox, opt);
162  // draw the icon and text
163  painter.drawControl(QStyle::CE_ComboBoxLabel, opt);
164 }
165 
167  m_groupBox->hide();
168 }
169 
170 
172  m_useCurrentIndexText = set;
173 }
174 
175 /*!
176  \property QComboBox::currentText
177  \brief the current text
178  If the combo box is editable, the current text is the value displayed
179  by the line edit. Otherwise, it is the value of the current item or
180  an empty string if the combo box is empty or no current item is set.
181  The setter setCurrentText() simply calls setEditText() if the combo box is editable.
182  Otherwise, if there is a matching text in the list, currentIndex is set to the
183  corresponding index.
184  If m_useCurrentIndexText is false, the Text set with setText is used. The intention of displaying
185  this text is to show a text in the case of removed element.
186  \sa editable, setEditText()
187 */
189  if (lineEdit())
190  return lineEdit()->text();
191  else if (currentModelIndex().isValid() && m_useCurrentIndexText)
192  return itemText(currentIndex());
193  else if (!m_useCurrentIndexText)
194  return m_lineEditText;
195  else
196  return QString();
197 }
198 
199 void TreeViewComboBox::setText(const QString& text) {
200  m_lineEditText = text;
201 }
202 
203 void TreeViewComboBox::setInvalid(bool invalid, const QString& tooltip) {
204  if (invalid) {
205  setStyleSheet("background: red;");
206  setToolTip(tooltip);
207  return;
208  }
209 
210  setToolTip("");
211  setStyleSheet("");
212 }
213 
214 /*!
215  Hides the non-toplevel items of the model used in the tree view.
216 */
217 void TreeViewComboBox::showTopLevelOnly(const QModelIndex & index) {
218  int rows = index.model()->rowCount(index);
219  for (int i = 0; i < rows; i++) {
220  QModelIndex child = index.model()->index(i, 0, index);
221  showTopLevelOnly(child);
222  const auto* aspect = static_cast<const AbstractAspect*>(child.internalPointer());
223  m_treeView->setRowHidden(i, index, !(isTopLevel(aspect) && !isHidden(aspect)));
224  }
225 }
226 
227 /*!
228  catches the MouseButtonPress-event and hides the tree view on mouse clicking.
229 */
230 bool TreeViewComboBox::eventFilter(QObject* object, QEvent* event) {
231  if ( (object == m_groupBox) && event->type() == QEvent::MouseButtonPress ) {
232  m_groupBox->hide();
233  this->setFocus();
234  return true;
235  }
236  return QComboBox::eventFilter(object, event);
237 }
238 
239 //SLOTs
240 void TreeViewComboBox::treeViewIndexActivated(const QModelIndex& index) {
241  if (index.internalPointer()) {
242  QComboBox::setCurrentIndex(0);
243  QComboBox::setItemText(0, index.data().toString());
244  emit currentModelIndexChanged(index);
245  m_groupBox->hide();
246  return;
247  }
248 
249  m_treeView->setCurrentIndex(QModelIndex());
250  setCurrentIndex(0);
251  QComboBox::setItemText(0, QString());
252  emit currentModelIndexChanged(QModelIndex());
253  m_groupBox->hide();
254 }
255 
256 void TreeViewComboBox::filterChanged(const QString& text) {
257  QModelIndex root = m_treeView->model()->index(0,0);
258  filter(root, text);
259 }
260 
261 bool TreeViewComboBox::filter(const QModelIndex& index, const QString& text) {
262  bool childVisible = false;
263  const int rows = index.model()->rowCount(index);
264  for (int i = 0; i < rows; i++) {
265  QModelIndex child = index.model()->index(i, 0, index);
266  auto* aspect = static_cast<AbstractAspect*>(child.internalPointer());
267  bool topLevel = isTopLevel(aspect);
268  if (!topLevel)
269  continue;
270 
271  bool visible = aspect->name().contains(text, Qt::CaseInsensitive);
272 
273  if (visible) {
274  //current item is visible -> make all its children (allowed top level types only and not hidden) visible without applying the filter
275  for (int j = 0; j < child.model()->rowCount(child); ++j) {
276  AbstractAspect* aspect = static_cast<AbstractAspect*>((child.model()->index(j, 0, child)).internalPointer());
277  m_treeView->setRowHidden(j, child, !(isTopLevel(aspect) && !isHidden(aspect)));
278  }
279 
280  childVisible = true;
281  } else {
282  //check children items. if one of the children is visible, make the parent (current) item visible too.
283  visible = filter(child, text);
284  if (visible)
285  childVisible = true;
286  }
287 
288  m_treeView->setRowHidden(i, index, !(visible && !isHidden(aspect)));
289  }
290 
291  return childVisible;
292 }
293 
294 /*!
295  checks whether \c aspect is one of the allowed top level types
296 */
297 bool TreeViewComboBox::isTopLevel(const AbstractAspect* aspect) const {
299  if (aspect->type() == type)
300  return true;
301 
304  return true;
305  }
306  return false;
307 }
308 
309 bool TreeViewComboBox::isHidden(const AbstractAspect* aspect) const {
310  return (m_hiddenAspects.indexOf(aspect) != -1);
311 }
AspectType
Base class of all persistent objects in a Project.
AspectType type() const
bool inherits(AspectType type) const
void setCurrentModelIndex(const QModelIndex &)
bool isTopLevel(const AbstractAspect *) const
QList< const AbstractAspect * > m_hiddenAspects
void showPopup() override
void setInvalid(bool invalid, const QString &tooltip=QString())
QTreeView * m_treeView
void paintEvent(QPaintEvent *) override
void filterChanged(const QString &)
QString currentText() const
QList< AspectType > m_topLevelClasses
bool filter(const QModelIndex &, const QString &)
void setModel(QAbstractItemModel *)
void setHiddenAspects(const QList< const AbstractAspect * > &)
void showTopLevelOnly(const QModelIndex &)
void setText(const QString &text)
QLineEdit * m_lineEdit
bool isHidden(const AbstractAspect *) const
TreeViewComboBox(QWidget *parent=nullptr)
QModelIndex currentModelIndex() const
void hidePopup() override
bool eventFilter(QObject *, QEvent *) override
void useCurrentIndexText(const bool set)
QGroupBox * m_groupBox
void setTopLevelClasses(const QList< AspectType > &)
void currentModelIndexChanged(const QModelIndex &)
void treeViewIndexActivated(const QModelIndex &)
@ Text
Definition: OriginObj.h:45
#define i18n(m)
Definition: nsl_common.h:38