Resync
[CMakeLuaTailorHgBridge.git] / CMakeLua / Source / QtDialog / QCMakeCacheView.cxx
blob3e7840c2645cea11a60adc574319ec3edbfcae1a
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: QCMakeCacheView.cxx,v $
5 Language: C++
6 Date: $Date: 2008/02/15 00:58:31 $
7 Version: $Revision: 1.26 $
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 <QToolButton>
21 #include <QFileDialog>
22 #include <QHBoxLayout>
23 #include <QHeaderView>
24 #include <QEvent>
25 #include <QFileInfo>
26 #include <QStyle>
27 #include <QKeyEvent>
28 #include <QMenu>
29 #include <QDirModel>
31 static QRegExp AdvancedRegExp[2] = { QRegExp("(false)"), QRegExp("(true|false)") };
33 // filter for searches
34 class QCMakeSearchFilter : public QSortFilterProxyModel
36 public:
37 QCMakeSearchFilter(QObject* o) : QSortFilterProxyModel(o) {}
38 protected:
39 bool filterAcceptsRow(int row, const QModelIndex& p) const
41 // accept row if either column matches
42 QModelIndex idx0 = this->sourceModel()->index(row, 0, p);
43 QModelIndex idx1 = this->sourceModel()->index(row, 1, p);
44 QString str0 = this->sourceModel()->data(idx0).toString();
45 QString str1 = this->sourceModel()->data(idx1).toString();
47 return str0.contains(this->filterRegExp()) ||
48 str1.contains(this->filterRegExp());
52 QCMakeCacheView::QCMakeCacheView(QWidget* p)
53 : QTableView(p), Init(false)
55 // hook up our model and search/filter proxies
56 this->CacheModel = new QCMakeCacheModel(this);
57 this->AdvancedFilter = new QSortFilterProxyModel(this);
58 this->AdvancedFilter->setSourceModel(this->CacheModel);
59 this->AdvancedFilter->setFilterRole(QCMakeCacheModel::AdvancedRole);
60 this->AdvancedFilter->setFilterRegExp(AdvancedRegExp[0]);
61 this->AdvancedFilter->setDynamicSortFilter(true);
62 this->SearchFilter = new QCMakeSearchFilter(this);
63 this->SearchFilter->setSourceModel(this->AdvancedFilter);
64 this->SearchFilter->setFilterCaseSensitivity(Qt::CaseInsensitive);
65 this->SearchFilter->setDynamicSortFilter(true);
66 this->setModel(this->SearchFilter);
68 // our delegate for creating our editors
69 QCMakeCacheModelDelegate* delegate = new QCMakeCacheModelDelegate(this);
70 this->setItemDelegate(delegate);
72 this->setEditTriggers(QAbstractItemView::DoubleClicked |
73 QAbstractItemView::SelectedClicked |
74 QAbstractItemView::EditKeyPressed |
75 QAbstractItemView::AnyKeyPressed);
77 // tab, backtab doesn't step through items
78 this->setTabKeyNavigation(false);
80 // set up headers and sizes
81 int h = 0;
82 QFontMetrics met(this->font());
83 h = qMax(met.height(), this->style()->pixelMetric(QStyle::PM_IndicatorHeight));
84 this->verticalHeader()->setDefaultSectionSize(h + 4);
85 this->horizontalHeader()->setStretchLastSection(true);
86 this->verticalHeader()->hide();
89 void QCMakeCacheView::showEvent(QShowEvent* e)
91 if(!this->Init)
93 // initialize the table view column size
94 int colWidth = this->columnWidth(0) + this->columnWidth(1);
95 this->setColumnWidth(0, colWidth/2);
96 this->setColumnWidth(1, colWidth/2);
97 this->Init = true;
99 return QTableView::showEvent(e);
102 QCMakeCacheModel* QCMakeCacheView::cacheModel() const
104 return this->CacheModel;
107 QModelIndex QCMakeCacheView::moveCursor(CursorAction act,
108 Qt::KeyboardModifiers mod)
110 // want home/end to go to begin/end of rows, not columns
111 if(act == MoveHome)
113 return this->model()->index(0, 1);
115 else if(act == MoveEnd)
117 return this->model()->index(this->model()->rowCount()-1, 1);
119 return QTableView::moveCursor(act, mod);
122 void QCMakeCacheView::setShowAdvanced(bool s)
124 this->AdvancedFilter->setFilterRegExp(
125 s ? AdvancedRegExp[1] : AdvancedRegExp[0]);
128 bool QCMakeCacheView::showAdvanced() const
130 return this->AdvancedFilter->filterRegExp() == AdvancedRegExp[1];
133 void QCMakeCacheView::setSearchFilter(const QString& s)
135 this->SearchFilter->setFilterFixedString(s);
138 QCMakeCacheModel::QCMakeCacheModel(QObject* p)
139 : QAbstractTableModel(p),
140 NewCount(0), EditEnabled(true)
144 QCMakeCacheModel::~QCMakeCacheModel()
148 static uint qHash(const QCMakeCacheProperty& p)
150 return qHash(p.Key);
153 void QCMakeCacheModel::clear()
155 this->setProperties(QCMakeCachePropertyList());
158 void QCMakeCacheModel::setProperties(const QCMakeCachePropertyList& props)
160 QSet<QCMakeCacheProperty> newProps = props.toSet();
161 QSet<QCMakeCacheProperty> newProps2 = props.toSet();
162 QSet<QCMakeCacheProperty> oldProps = this->Properties.toSet();
164 oldProps.intersect(newProps);
165 newProps.subtract(oldProps);
166 newProps2.subtract(newProps);
168 this->NewCount = newProps.count();
169 this->Properties.clear();
171 this->Properties = newProps.toList();
172 qSort(this->Properties);
173 QCMakeCachePropertyList tmp = newProps2.toList();
174 qSort(tmp);
175 this->Properties += tmp;
177 this->reset();
180 QCMakeCachePropertyList QCMakeCacheModel::properties() const
182 return this->Properties;
185 void QCMakeCacheModel::setEditEnabled(bool e)
187 this->EditEnabled = e;
190 bool QCMakeCacheModel::editEnabled() const
192 return this->EditEnabled;
195 int QCMakeCacheModel::newCount() const
197 return this->NewCount;
200 int QCMakeCacheModel::columnCount (const QModelIndex& /*p*/ ) const
202 return 2;
205 QVariant QCMakeCacheModel::data (const QModelIndex& idx, int role) const
207 if(idx.column() == 0 && (role == Qt::DisplayRole || role == Qt::EditRole))
209 return this->Properties[idx.row()].Key;
211 else if(idx.column() == 0 && role == Qt::ToolTipRole)
213 return this->data(idx, Qt::DisplayRole).toString() + "\n" +
214 this->data(idx, QCMakeCacheModel::HelpRole).toString();
216 else if(idx.column() == 1 && (role == Qt::DisplayRole || role == Qt::EditRole))
218 if(this->Properties[idx.row()].Type != QCMakeCacheProperty::BOOL)
220 return this->Properties[idx.row()].Value;
223 else if(idx.column() == 1 && role == Qt::CheckStateRole)
225 if(this->Properties[idx.row()].Type == QCMakeCacheProperty::BOOL)
227 return this->Properties[idx.row()].Value.toBool() ? Qt::Checked : Qt::Unchecked;
230 else if(role == QCMakeCacheModel::HelpRole)
232 return this->Properties[idx.row()].Help;
234 else if(role == QCMakeCacheModel::TypeRole)
236 return this->Properties[idx.row()].Type;
238 else if(role == QCMakeCacheModel::AdvancedRole)
240 return this->Properties[idx.row()].Advanced;
242 else if(role == Qt::BackgroundRole && idx.row()+1 <= this->NewCount)
244 return QBrush(QColor(255,100,100));
246 return QVariant();
249 QModelIndex QCMakeCacheModel::parent (const QModelIndex& /*idx*/) const
251 return QModelIndex();
254 int QCMakeCacheModel::rowCount (const QModelIndex& p) const
256 if(p.isValid())
258 return 0;
260 return this->Properties.count();
263 QVariant QCMakeCacheModel::headerData (int section, Qt::Orientation orient, int role) const
265 // return header labels
266 if(role == Qt::DisplayRole && orient == Qt::Horizontal)
268 return section == 0 ? "Name" : "Value";
270 return QVariant();
273 Qt::ItemFlags QCMakeCacheModel::flags (const QModelIndex& idx) const
275 Qt::ItemFlags f = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
276 // all column 1's are editable
277 if(idx.column() == 1 && this->EditEnabled)
279 f |= Qt::ItemIsEditable;
280 // booleans are editable in place
281 if(this->Properties[idx.row()].Type == QCMakeCacheProperty::BOOL)
283 f |= Qt::ItemIsUserCheckable;
286 return f;
290 bool QCMakeCacheModel::setData (const QModelIndex& idx, const QVariant& value, int role)
292 if(idx.column() == 0 && (role == Qt::DisplayRole || role == Qt::EditRole))
294 this->Properties[idx.row()].Key = value.toString();
295 emit this->dataChanged(idx, idx);
297 else if(idx.column() == 1 && (role == Qt::DisplayRole || role == Qt::EditRole))
299 this->Properties[idx.row()].Value = value.toString();
300 emit this->dataChanged(idx, idx);
302 else if(idx.column() == 1 && (role == Qt::CheckStateRole))
304 this->Properties[idx.row()].Value = value.toInt() == Qt::Checked;
305 emit this->dataChanged(idx, idx);
307 else if(role == QCMakeCacheModel::HelpRole)
309 this->Properties[idx.row()].Help = value.toString();
310 emit this->dataChanged(idx, idx);
312 else if(role == QCMakeCacheModel::TypeRole)
314 this->Properties[idx.row()].Type = static_cast<QCMakeCacheProperty::PropertyType>(value.toInt());
316 else if(role == QCMakeCacheModel::AdvancedRole)
318 this->Properties[idx.row()].Advanced = value.toBool();
320 return false;
323 QModelIndex QCMakeCacheModel::buddy(const QModelIndex& idx) const
325 if(idx.column() == 0)
327 if(this->Properties[idx.row()].Type != QCMakeCacheProperty::BOOL)
329 return this->index(idx.row(), 1);
332 return idx;
335 bool QCMakeCacheModel::removeRows(int row, int num, const QModelIndex&)
337 if(row < 0 || row+num > this->Properties.count())
339 return false;
341 this->beginRemoveRows(QModelIndex(), row, row+num-1);
342 for(int i=0; i<num; i++)
344 this->Properties.removeAt(row);
345 if(this->NewCount >= row+1)
347 this->NewCount--;
350 this->endRemoveRows();
351 return true;
354 bool QCMakeCacheModel::insertRows(int row, int num, const QModelIndex&)
356 if(row < 0)
357 row = 0;
358 if(row > this->rowCount())
359 row = this->rowCount();
361 this->beginInsertRows(QModelIndex(), row, row+num-1);
362 for(int i=0; i<num; i++)
364 this->Properties.insert(row+i, QCMakeCacheProperty());
365 if(this->NewCount >= row)
367 this->NewCount++;
370 this->endInsertRows();
371 return true;
374 QCMakeCacheModelDelegate::QCMakeCacheModelDelegate(QObject* p)
375 : QItemDelegate(p)
379 QWidget* QCMakeCacheModelDelegate::createEditor(QWidget* p,
380 const QStyleOptionViewItem&, const QModelIndex& idx) const
382 const QAbstractItemModel* model = idx.model();
383 QModelIndex var = model->index(idx.row(), 0);
384 QVariant type = idx.data(QCMakeCacheModel::TypeRole);
385 if(type == QCMakeCacheProperty::BOOL)
387 return NULL;
389 else if(type == QCMakeCacheProperty::PATH)
391 return new QCMakeCachePathEditor(p,
392 var.data(Qt::DisplayRole).toString());
394 else if(type == QCMakeCacheProperty::FILEPATH)
396 return new QCMakeCacheFilePathEditor(p,
397 var.data(Qt::DisplayRole).toString());
400 return new QLineEdit(p);
403 bool QCMakeCacheModelDelegate::editorEvent(QEvent* e, QAbstractItemModel* model,
404 const QStyleOptionViewItem& option, const QModelIndex& index)
406 Qt::ItemFlags flags = model->flags(index);
407 if (!(flags & Qt::ItemIsUserCheckable) || !(option.state & QStyle::State_Enabled)
408 || !(flags & Qt::ItemIsEnabled))
410 return false;
413 QVariant value = index.data(Qt::CheckStateRole);
414 if (!value.isValid())
416 return false;
419 if ((e->type() == QEvent::MouseButtonRelease)
420 || (e->type() == QEvent::MouseButtonDblClick))
422 // eat the double click events inside the check rect
423 if (e->type() == QEvent::MouseButtonDblClick)
425 return true;
428 else if (e->type() == QEvent::KeyPress)
430 if(static_cast<QKeyEvent*>(e)->key() != Qt::Key_Space &&
431 static_cast<QKeyEvent*>(e)->key() != Qt::Key_Select)
433 return false;
436 else
438 return false;
441 Qt::CheckState state = (static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked
442 ? Qt::Unchecked : Qt::Checked);
443 return model->setData(index, state, Qt::CheckStateRole);
446 QCMakeCacheFileEditor::QCMakeCacheFileEditor(QWidget* p, const QString& var)
447 : QLineEdit(p), Variable(var)
449 // this *is* instead of has a line edit so QAbstractItemView
450 // doesn't get confused with what the editor really is
451 this->setContentsMargins(0, 0, 0, 0);
452 this->ToolButton = new QToolButton(this);
453 this->ToolButton->setText("...");
454 this->ToolButton->setCursor(QCursor(Qt::ArrowCursor));
455 QObject::connect(this->ToolButton, SIGNAL(clicked(bool)),
456 this, SLOT(chooseFile()));
459 QCMakeCacheFilePathEditor::QCMakeCacheFilePathEditor(QWidget* p, const QString& var)
460 : QCMakeCacheFileEditor(p, var)
462 this->setCompleter(new QCMakeFileCompleter(this, false));
465 QCMakeCachePathEditor::QCMakeCachePathEditor(QWidget* p, const QString& var)
466 : QCMakeCacheFileEditor(p, var)
468 this->setCompleter(new QCMakeFileCompleter(this, true));
471 void QCMakeCacheFileEditor::resizeEvent(QResizeEvent* e)
473 // make the tool button fit on the right side
474 int h = e->size().height();
475 this->ToolButton->resize(h, h);
476 this->ToolButton->move(this->width() - h, 0);
477 this->setContentsMargins(0, 0, h, 0);
480 void QCMakeCacheFilePathEditor::chooseFile()
482 // choose a file and set it
483 QString path;
484 QFileInfo info(this->text());
485 QString title;
486 if(this->Variable.isEmpty())
488 title = tr("Select File");
490 else
492 title = tr("Select File for %1");
493 title = title.arg(this->Variable);
495 path = QFileDialog::getOpenFileName(this, title, info.absolutePath());
497 if(!path.isEmpty())
499 this->setText(QDir::fromNativeSeparators(path));
503 void QCMakeCachePathEditor::chooseFile()
505 // choose a file and set it
506 QString path;
507 QString title;
508 if(this->Variable.isEmpty())
510 title = tr("Select Path");
512 else
514 title = tr("Select Path for %1");
515 title = title.arg(this->Variable);
517 path = QFileDialog::getExistingDirectory(this, title, this->text());
518 if(!path.isEmpty())
520 this->setText(QDir::fromNativeSeparators(path));
524 QCMakeFileCompleter::QCMakeFileCompleter(QObject* o, bool dirs)
525 : QCompleter(o)
527 QDirModel* model = new QDirModel(this);
528 if(dirs)
530 model->setFilter(QDir::AllDirs | QDir::Drives | QDir::NoDotAndDotDot);
532 this->setModel(model);
535 QString QCMakeFileCompleter::pathFromIndex(const QModelIndex& idx) const
537 return QDir::fromNativeSeparators(QCompleter::pathFromIndex(idx));