1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: QCMakeCacheView.cxx,v $
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>
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
35 QCMakeSearchFilter(QObject
* o
) : QSortFilterProxyModel(o
) {}
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
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
)
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);
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
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
)
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();
173 this->Properties
+= tmp
;
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
,
203 this->setData(idx2
, value
, Qt::DisplayRole
);
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
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));
274 QModelIndex
QCMakeCacheModel::parent (const QModelIndex
& /*idx*/) const
276 return QModelIndex();
279 int QCMakeCacheModel::rowCount (const QModelIndex
& p
) const
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";
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
;
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();
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);
360 bool QCMakeCacheModel::removeRows(int row
, int num
, const QModelIndex
&)
362 if(row
< 0 || row
+num
> this->Properties
.count())
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)
375 this->endRemoveRows();
379 bool QCMakeCacheModel::insertRows(int row
, int num
, const QModelIndex
&)
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
)
395 this->endInsertRows();
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
)
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)));
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)));
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
))
451 QVariant value
= index
.data(Qt::CheckStateRole
);
452 if (!value
.isValid())
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
)
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
)
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
)
491 return QItemDelegate::eventFilter(object
, event
);