ENH: Add cross compiling support in the GUI in the same dialog that prompts for
[cmake.git] / Source / QtDialog / QCMakeCacheView.cxx
blob0d8fb735a16c553d24d9e3cd53c55fc88901f0a2
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: QCMakeCacheView.cxx,v $
5 Language: C++
6 Date: $Date: 2008-05-15 23:21:01 $
7 Version: $Revision: 1.28 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
18 #include "QCMakeCacheView.h"
20 #include <QHBoxLayout>
21 #include <QHeaderView>
22 #include <QEvent>
23 #include <QStyle>
24 #include <QKeyEvent>
25 #include <QSortFilterProxyModel>
27 #include "QCMakeWidgets.h"
29 static QRegExp AdvancedRegExp[2] = { QRegExp("(false)"), QRegExp("(true|false)") };
31 // filter for searches
32 class QCMakeSearchFilter : public QSortFilterProxyModel
34 public:
35 QCMakeSearchFilter(QObject* o) : QSortFilterProxyModel(o) {}
36 protected:
37 bool filterAcceptsRow(int row, const QModelIndex& p) const
39 // accept row if either column matches
40 QModelIndex idx0 = this->sourceModel()->index(row, 0, p);
41 QModelIndex idx1 = this->sourceModel()->index(row, 1, p);
42 QString str0 = this->sourceModel()->data(idx0).toString();
43 QString str1 = this->sourceModel()->data(idx1).toString();
45 return str0.contains(this->filterRegExp()) ||
46 str1.contains(this->filterRegExp());
50 QCMakeCacheView::QCMakeCacheView(QWidget* p)
51 : QTableView(p), Init(false)
53 // hook up our model and search/filter proxies
54 this->CacheModel = new QCMakeCacheModel(this);
55 this->AdvancedFilter = new QSortFilterProxyModel(this);
56 this->AdvancedFilter->setSourceModel(this->CacheModel);
57 this->AdvancedFilter->setFilterRole(QCMakeCacheModel::AdvancedRole);
58 this->AdvancedFilter->setFilterRegExp(AdvancedRegExp[0]);
59 this->AdvancedFilter->setDynamicSortFilter(true);
60 this->SearchFilter = new QCMakeSearchFilter(this);
61 this->SearchFilter->setSourceModel(this->AdvancedFilter);
62 this->SearchFilter->setFilterCaseSensitivity(Qt::CaseInsensitive);
63 this->SearchFilter->setDynamicSortFilter(true);
64 this->setModel(this->SearchFilter);
66 // our delegate for creating our editors
67 QCMakeCacheModelDelegate* delegate = new QCMakeCacheModelDelegate(this);
68 this->setItemDelegate(delegate);
70 this->setEditTriggers(QAbstractItemView::DoubleClicked |
71 QAbstractItemView::SelectedClicked |
72 QAbstractItemView::EditKeyPressed |
73 QAbstractItemView::AnyKeyPressed);
75 // tab, backtab doesn't step through items
76 this->setTabKeyNavigation(false);
78 // set up headers and sizes
79 int h = 0;
80 QFontMetrics met(this->font());
81 h = qMax(met.height(), this->style()->pixelMetric(QStyle::PM_IndicatorHeight));
82 this->verticalHeader()->setDefaultSectionSize(h + 4);
83 this->horizontalHeader()->setStretchLastSection(true);
84 this->verticalHeader()->hide();
87 void QCMakeCacheView::showEvent(QShowEvent* e)
89 if(!this->Init)
91 // initialize the table view column size
92 int colWidth = this->columnWidth(0) + this->columnWidth(1);
93 this->setColumnWidth(0, colWidth/2);
94 this->setColumnWidth(1, colWidth/2);
95 this->Init = true;
97 return QTableView::showEvent(e);
100 QCMakeCacheModel* QCMakeCacheView::cacheModel() const
102 return this->CacheModel;
105 QModelIndex QCMakeCacheView::moveCursor(CursorAction act,
106 Qt::KeyboardModifiers mod)
108 // want home/end to go to begin/end of rows, not columns
109 if(act == MoveHome)
111 return this->model()->index(0, 1);
113 else if(act == MoveEnd)
115 return this->model()->index(this->model()->rowCount()-1, 1);
117 return QTableView::moveCursor(act, mod);
120 void QCMakeCacheView::setShowAdvanced(bool s)
122 this->AdvancedFilter->setFilterRegExp(
123 s ? AdvancedRegExp[1] : AdvancedRegExp[0]);
126 bool QCMakeCacheView::showAdvanced() const
128 return this->AdvancedFilter->filterRegExp() == AdvancedRegExp[1];
131 void QCMakeCacheView::setSearchFilter(const QString& s)
133 this->SearchFilter->setFilterFixedString(s);
136 QCMakeCacheModel::QCMakeCacheModel(QObject* p)
137 : QAbstractTableModel(p),
138 NewCount(0), EditEnabled(true)
142 QCMakeCacheModel::~QCMakeCacheModel()
146 static uint qHash(const QCMakeProperty& p)
148 return qHash(p.Key);
151 void QCMakeCacheModel::clear()
153 this->setProperties(QCMakePropertyList());
156 void QCMakeCacheModel::setProperties(const QCMakePropertyList& props)
158 QSet<QCMakeProperty> newProps = props.toSet();
159 QSet<QCMakeProperty> newProps2 = props.toSet();
160 QSet<QCMakeProperty> oldProps = this->Properties.toSet();
162 oldProps.intersect(newProps);
163 newProps.subtract(oldProps);
164 newProps2.subtract(newProps);
166 this->NewCount = newProps.count();
167 this->Properties.clear();
169 this->Properties = newProps.toList();
170 qSort(this->Properties);
171 QCMakePropertyList tmp = newProps2.toList();
172 qSort(tmp);
173 this->Properties += tmp;
175 this->reset();
178 QCMakePropertyList QCMakeCacheModel::properties() const
180 return this->Properties;
183 bool QCMakeCacheModel::insertProperty(int row, QCMakeProperty::PropertyType t,
184 const QString& name, const QString& description,
185 const QVariant& value, bool advanced)
187 if(this->insertRows(row, 1, QModelIndex()))
189 QModelIndex idx1 = this->index(row, 0);
190 QModelIndex idx2 = this->index(row, 1);
192 this->setData(idx1, t, QCMakeCacheModel::TypeRole);
193 this->setData(idx1, name, Qt::DisplayRole);
194 this->setData(idx1, description, QCMakeCacheModel::HelpRole);
195 this->setData(idx1, advanced, QCMakeCacheModel::AdvancedRole);
196 if(t == QCMakeProperty::BOOL)
198 this->setData(idx2, value.toBool() ? Qt::Checked : Qt::Unchecked,
199 Qt::CheckStateRole);
201 else
203 this->setData(idx2, value, Qt::DisplayRole);
205 return true;
207 return false;
210 void QCMakeCacheModel::setEditEnabled(bool e)
212 this->EditEnabled = e;
215 bool QCMakeCacheModel::editEnabled() const
217 return this->EditEnabled;
220 int QCMakeCacheModel::newCount() const
222 return this->NewCount;
225 int QCMakeCacheModel::columnCount (const QModelIndex& /*p*/ ) const
227 return 2;
230 QVariant QCMakeCacheModel::data (const QModelIndex& idx, int role) const
232 if(idx.column() == 0 && (role == Qt::DisplayRole || role == Qt::EditRole))
234 return this->Properties[idx.row()].Key;
236 else if(idx.column() == 0 && role == Qt::ToolTipRole)
238 return this->data(idx, Qt::DisplayRole).toString() + "\n" +
239 this->data(idx, QCMakeCacheModel::HelpRole).toString();
241 else if(idx.column() == 1 && (role == Qt::DisplayRole || role == Qt::EditRole))
243 if(this->Properties[idx.row()].Type != QCMakeProperty::BOOL)
245 return this->Properties[idx.row()].Value;
248 else if(idx.column() == 1 && role == Qt::CheckStateRole)
250 if(this->Properties[idx.row()].Type == QCMakeProperty::BOOL)
252 return this->Properties[idx.row()].Value.toBool() ? Qt::Checked : Qt::Unchecked;
255 else if(role == QCMakeCacheModel::HelpRole)
257 return this->Properties[idx.row()].Help;
259 else if(role == QCMakeCacheModel::TypeRole)
261 return this->Properties[idx.row()].Type;
263 else if(role == QCMakeCacheModel::AdvancedRole)
265 return this->Properties[idx.row()].Advanced;
267 else if(role == Qt::BackgroundRole && idx.row()+1 <= this->NewCount)
269 return QBrush(QColor(255,100,100));
271 return QVariant();
274 QModelIndex QCMakeCacheModel::parent (const QModelIndex& /*idx*/) const
276 return QModelIndex();
279 int QCMakeCacheModel::rowCount (const QModelIndex& p) const
281 if(p.isValid())
283 return 0;
285 return this->Properties.count();
288 QVariant QCMakeCacheModel::headerData (int section, Qt::Orientation orient, int role) const
290 // return header labels
291 if(role == Qt::DisplayRole && orient == Qt::Horizontal)
293 return section == 0 ? "Name" : "Value";
295 return QVariant();
298 Qt::ItemFlags QCMakeCacheModel::flags (const QModelIndex& idx) const
300 Qt::ItemFlags f = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
301 // all column 1's are editable
302 if(idx.column() == 1 && this->EditEnabled)
304 f |= Qt::ItemIsEditable;
305 // booleans are editable in place
306 if(this->Properties[idx.row()].Type == QCMakeProperty::BOOL)
308 f |= Qt::ItemIsUserCheckable;
311 return f;
315 bool QCMakeCacheModel::setData (const QModelIndex& idx, const QVariant& value, int role)
317 if(idx.column() == 0 && (role == Qt::DisplayRole || role == Qt::EditRole))
319 this->Properties[idx.row()].Key = value.toString();
320 emit this->dataChanged(idx, idx);
322 else if(idx.column() == 1 && (role == Qt::DisplayRole || role == Qt::EditRole))
324 this->Properties[idx.row()].Value = value.toString();
325 emit this->dataChanged(idx, idx);
327 else if(idx.column() == 1 && (role == Qt::CheckStateRole))
329 this->Properties[idx.row()].Value = value.toInt() == Qt::Checked;
330 emit this->dataChanged(idx, idx);
332 else if(role == QCMakeCacheModel::HelpRole)
334 this->Properties[idx.row()].Help = value.toString();
335 emit this->dataChanged(idx, idx);
337 else if(role == QCMakeCacheModel::TypeRole)
339 this->Properties[idx.row()].Type = static_cast<QCMakeProperty::PropertyType>(value.toInt());
341 else if(role == QCMakeCacheModel::AdvancedRole)
343 this->Properties[idx.row()].Advanced = value.toBool();
345 return false;
348 QModelIndex QCMakeCacheModel::buddy(const QModelIndex& idx) const
350 if(idx.column() == 0)
352 if(this->Properties[idx.row()].Type != QCMakeProperty::BOOL)
354 return this->index(idx.row(), 1);
357 return idx;
360 bool QCMakeCacheModel::removeRows(int row, int num, const QModelIndex&)
362 if(row < 0 || row+num > this->Properties.count())
364 return false;
366 this->beginRemoveRows(QModelIndex(), row, row+num-1);
367 for(int i=0; i<num; i++)
369 this->Properties.removeAt(row);
370 if(this->NewCount >= row+1)
372 this->NewCount--;
375 this->endRemoveRows();
376 return true;
379 bool QCMakeCacheModel::insertRows(int row, int num, const QModelIndex&)
381 if(row < 0)
382 row = 0;
383 if(row > this->rowCount())
384 row = this->rowCount();
386 this->beginInsertRows(QModelIndex(), row, row+num-1);
387 for(int i=0; i<num; i++)
389 this->Properties.insert(row+i, QCMakeProperty());
390 if(this->NewCount >= row)
392 this->NewCount++;
395 this->endInsertRows();
396 return true;
399 QCMakeCacheModelDelegate::QCMakeCacheModelDelegate(QObject* p)
400 : QItemDelegate(p), FileDialogFlag(false)
404 void QCMakeCacheModelDelegate::setFileDialogFlag(bool f)
406 this->FileDialogFlag = f;
409 QWidget* QCMakeCacheModelDelegate::createEditor(QWidget* p,
410 const QStyleOptionViewItem&, const QModelIndex& idx) const
412 const QAbstractItemModel* model = idx.model();
413 QModelIndex var = model->index(idx.row(), 0);
414 QVariant type = idx.data(QCMakeCacheModel::TypeRole);
415 if(type == QCMakeProperty::BOOL)
417 return NULL;
419 else if(type == QCMakeProperty::PATH)
421 QCMakePathEditor* editor =
422 new QCMakePathEditor(p,
423 var.data(Qt::DisplayRole).toString());
424 QObject::connect(editor, SIGNAL(fileDialogExists(bool)), this,
425 SLOT(setFileDialogFlag(bool)));
426 return editor;
428 else if(type == QCMakeProperty::FILEPATH)
430 QCMakeFilePathEditor* editor =
431 new QCMakeFilePathEditor(p,
432 var.data(Qt::DisplayRole).toString());
433 QObject::connect(editor, SIGNAL(fileDialogExists(bool)), this,
434 SLOT(setFileDialogFlag(bool)));
435 return editor;
438 return new QLineEdit(p);
441 bool QCMakeCacheModelDelegate::editorEvent(QEvent* e, QAbstractItemModel* model,
442 const QStyleOptionViewItem& option, const QModelIndex& index)
444 Qt::ItemFlags flags = model->flags(index);
445 if (!(flags & Qt::ItemIsUserCheckable) || !(option.state & QStyle::State_Enabled)
446 || !(flags & Qt::ItemIsEnabled))
448 return false;
451 QVariant value = index.data(Qt::CheckStateRole);
452 if (!value.isValid())
454 return false;
457 if ((e->type() == QEvent::MouseButtonRelease)
458 || (e->type() == QEvent::MouseButtonDblClick))
460 // eat the double click events inside the check rect
461 if (e->type() == QEvent::MouseButtonDblClick)
463 return true;
466 else if (e->type() == QEvent::KeyPress)
468 if(static_cast<QKeyEvent*>(e)->key() != Qt::Key_Space &&
469 static_cast<QKeyEvent*>(e)->key() != Qt::Key_Select)
471 return false;
474 else
476 return false;
479 Qt::CheckState state = (static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked
480 ? Qt::Unchecked : Qt::Checked);
481 return model->setData(index, state, Qt::CheckStateRole);
484 bool QCMakeCacheModelDelegate::eventFilter(QObject* object, QEvent* event)
486 // workaround for what looks like a bug in Qt on Mac OS X
487 if(event->type() == QEvent::FocusOut && this->FileDialogFlag)
489 return false;
491 return QItemDelegate::eventFilter(object, event);