| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505 | /*=========================================================================  Program:   CMake - Cross-Platform Makefile Generator  Module:    $RCSfile$  Language:  C++  Date:      $Date$  Version:   $Revision$  Copyright (c) 2002 Kitware, Inc., Insight Consortium.  All rights reserved.  See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.     This software is distributed WITHOUT ANY WARRANTY; without even      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      PURPOSE.  See the above copyright notices for more information.=========================================================================*/#include "QCMakeCacheView.h"#include <QToolButton>#include <QFileDialog>#include <QHBoxLayout>#include <QHeaderView>#include <QEvent>#include <QFileInfo>#include <QStyle>#include <QKeyEvent>#include <QMenu>#include <QDirModel>#include <QCompleter>static QRegExp AdvancedRegExp[2] = { QRegExp("(false)"), QRegExp("(true|false)") };QCMakeCacheView::QCMakeCacheView(QWidget* p)  : QTableView(p), Init(false){  // hook up our model and search/filter proxies  this->CacheModel = new QCMakeCacheModel(this);  this->AdvancedFilter = new QSortFilterProxyModel(this);  this->AdvancedFilter->setSourceModel(this->CacheModel);  this->AdvancedFilter->setFilterRole(QCMakeCacheModel::AdvancedRole);  this->AdvancedFilter->setFilterRegExp(AdvancedRegExp[0]);  this->AdvancedFilter->setDynamicSortFilter(true);  this->SearchFilter = new QSortFilterProxyModel(this);  this->SearchFilter->setSourceModel(this->AdvancedFilter);  this->SearchFilter->setFilterCaseSensitivity(Qt::CaseInsensitive);#if QT_VERSION >= 0x040300   // breaks search in Qt 4.2  this->SearchFilter->setFilterKeyColumn(-1); // all columns#endif  this->SearchFilter->setDynamicSortFilter(true);  this->setModel(this->SearchFilter);  // our delegate for creating our editors  QCMakeCacheModelDelegate* delegate = new QCMakeCacheModelDelegate(this);  this->setItemDelegate(delegate);  // set up headers and sizes  int h = 0;  QFontMetrics met(this->font());  h = qMax(met.height(), this->style()->pixelMetric(QStyle::PM_IndicatorHeight));  this->verticalHeader()->setDefaultSectionSize(h + 4);  this->horizontalHeader()->setStretchLastSection(true);  this->verticalHeader()->hide();}void QCMakeCacheView::showEvent(QShowEvent* e){  if(!this->Init)    {    // initialize the table view column size    int colWidth = this->columnWidth(0) + this->columnWidth(1);    this->setColumnWidth(0, colWidth/2);    this->setColumnWidth(1, colWidth/2);    this->Init = true;    }  return QTableView::showEvent(e);}  QCMakeCacheModel* QCMakeCacheView::cacheModel() const{  return this->CacheModel;} QModelIndex QCMakeCacheView::moveCursor(CursorAction act,   Qt::KeyboardModifiers mod){  // tab through values only (not names)  QModelIndex current = this->currentIndex();  if(act == MoveNext)    {    if(!current.isValid())      {      return this->model()->index(0, 1);      }    else if(current.column() == 0)      {      return this->model()->index(current.row(), 1);      }    else      {      return this->model()->index(current.row()+1, 1);      }    }  else if(act == MovePrevious)    {    if(!current.isValid())      {      return this->model()->index(0, 1);      }    else      {      return this->model()->index(current.row()-1, 1);      }    }  return QTableView::moveCursor(act, mod);}  void QCMakeCacheView::setShowAdvanced(bool s){  this->AdvancedFilter->setFilterRegExp(    s ? AdvancedRegExp[1] : AdvancedRegExp[0]);}bool QCMakeCacheView::showAdvanced() const{  return this->AdvancedFilter->filterRegExp() == AdvancedRegExp[1];}void QCMakeCacheView::setSearchFilter(const QString& s){  this->SearchFilter->setFilterFixedString(s);}QCMakeCacheModel::QCMakeCacheModel(QObject* p)  : QAbstractTableModel(p),    NewCount(0), EditEnabled(true){}QCMakeCacheModel::~QCMakeCacheModel(){}static uint qHash(const QCMakeCacheProperty& p){  return qHash(p.Key);}void QCMakeCacheModel::clear(){  this->setProperties(QCMakeCachePropertyList());}void QCMakeCacheModel::setProperties(const QCMakeCachePropertyList& props){  QSet<QCMakeCacheProperty> newProps = props.toSet();  QSet<QCMakeCacheProperty> newProps2 = props.toSet();  QSet<QCMakeCacheProperty> oldProps = this->Properties.toSet();    oldProps.intersect(newProps);  newProps.subtract(oldProps);  newProps2.subtract(newProps);  this->NewCount = newProps.count();  this->Properties.clear();  this->Properties = newProps.toList();  qSort(this->Properties);  QCMakeCachePropertyList tmp = newProps2.toList();  qSort(tmp);  this->Properties += tmp;    this->reset();}  QCMakeCachePropertyList QCMakeCacheModel::properties() const{  return this->Properties;}void QCMakeCacheModel::setEditEnabled(bool e){  this->EditEnabled = e;}bool QCMakeCacheModel::editEnabled() const{  return this->EditEnabled;}int QCMakeCacheModel::newCount() const{  return this->NewCount;}int QCMakeCacheModel::columnCount (const QModelIndex& /*p*/ ) const{  return 2;}QVariant QCMakeCacheModel::data (const QModelIndex& idx, int role) const{  if(idx.column() == 0 && (role == Qt::DisplayRole || role == Qt::EditRole))    {    return this->Properties[idx.row()].Key;    }  else if(idx.column() == 0 && role == Qt::ToolTipRole)    {    return this->data(idx, Qt::DisplayRole).toString() + "\n" +           this->data(idx, QCMakeCacheModel::HelpRole).toString();    }  else if(idx.column() == 1 && (role == Qt::DisplayRole || role == Qt::EditRole))    {    if(this->Properties[idx.row()].Type != QCMakeCacheProperty::BOOL)      {      return this->Properties[idx.row()].Value;      }    }  else if(idx.column() == 1 && role == Qt::CheckStateRole)    {    if(this->Properties[idx.row()].Type == QCMakeCacheProperty::BOOL)      {      return this->Properties[idx.row()].Value.toBool() ? Qt::Checked : Qt::Unchecked;      }    }  else if(role == QCMakeCacheModel::HelpRole)    {    return this->Properties[idx.row()].Help;    }  else if(role == QCMakeCacheModel::TypeRole)    {    return this->Properties[idx.row()].Type;    }  else if(role == QCMakeCacheModel::AdvancedRole)    {    return this->Properties[idx.row()].Advanced;    }  else if(role == Qt::BackgroundRole && idx.row()+1 <= this->NewCount)    {    return QBrush(QColor(255,100,100));    }  return QVariant();}QModelIndex QCMakeCacheModel::parent (const QModelIndex& /*idx*/) const{  return QModelIndex();}int QCMakeCacheModel::rowCount (const QModelIndex& p) const{  if(p.isValid())    {    return 0;    }  return this->Properties.count();}QVariant QCMakeCacheModel::headerData (int section, Qt::Orientation orient, int role) const{  // return header labels  if(role == Qt::DisplayRole && orient == Qt::Horizontal)    {    return section == 0 ? "Name" : "Value";    }  return QVariant();}  Qt::ItemFlags QCMakeCacheModel::flags (const QModelIndex& idx) const{  Qt::ItemFlags f = Qt::ItemIsEnabled | Qt::ItemIsSelectable;  // all column 1's are editable  if(idx.column() == 1 && this->EditEnabled)    {    f |= Qt::ItemIsEditable;    // booleans are editable in place    if(this->Properties[idx.row()].Type == QCMakeCacheProperty::BOOL)      {      f |= Qt::ItemIsUserCheckable;      }    }  return f;}bool QCMakeCacheModel::setData (const QModelIndex& idx, const QVariant& value, int role){  if(idx.column() == 0 && (role == Qt::DisplayRole || role == Qt::EditRole))    {    this->Properties[idx.row()].Key = value.toString();    emit this->dataChanged(idx, idx);    }  else if(idx.column() == 1 && (role == Qt::DisplayRole || role == Qt::EditRole))    {    this->Properties[idx.row()].Value = value.toString();    emit this->dataChanged(idx, idx);    }  else if(idx.column() == 1 && (role == Qt::CheckStateRole))    {    this->Properties[idx.row()].Value = value.toInt() == Qt::Checked;    emit this->dataChanged(idx, idx);    }  else if(role == QCMakeCacheModel::HelpRole)    {    this->Properties[idx.row()].Help = value.toString();    emit this->dataChanged(idx, idx);    }  else if(role == QCMakeCacheModel::TypeRole)    {    this->Properties[idx.row()].Type = static_cast<QCMakeCacheProperty::PropertyType>(value.toInt());    }  else if(role == QCMakeCacheModel::AdvancedRole)    {    this->Properties[idx.row()].Advanced = value.toBool();    }  return false;}QModelIndex QCMakeCacheModel::buddy(const QModelIndex& idx) const{  if(idx.column() == 0)    {    if(this->Properties[idx.row()].Type != QCMakeCacheProperty::BOOL)      {      return this->index(idx.row(), 1);      }    }  return idx;}  bool QCMakeCacheModel::removeRows(int row, int num, const QModelIndex&){  if(row < 0 || row+num > this->Properties.count())    {    return false;    }  this->beginRemoveRows(QModelIndex(), row, row+num-1);  for(int i=0; i<num; i++)    {    this->Properties.removeAt(row);    if(this->NewCount >= row+1)      {      this->NewCount--;      }    }  this->endRemoveRows();  return true;}bool QCMakeCacheModel::insertRows(int row, int num, const QModelIndex&){  if(row < 0)    row = 0;  if(row > this->rowCount())    row = this->rowCount();  this->beginInsertRows(QModelIndex(), row, row+num-1);  for(int i=0; i<num; i++)    {    this->Properties.insert(row+i, QCMakeCacheProperty());    if(this->NewCount >= row)      {      this->NewCount++;      }    }  this->endInsertRows();  return true;}QCMakeCacheModelDelegate::QCMakeCacheModelDelegate(QObject* p)  : QItemDelegate(p){}QWidget* QCMakeCacheModelDelegate::createEditor(QWidget* p,     const QStyleOptionViewItem&, const QModelIndex& idx) const{  QVariant type = idx.data(QCMakeCacheModel::TypeRole);  if(type == QCMakeCacheProperty::BOOL)    {    return NULL;    }  else if(type == QCMakeCacheProperty::PATH)    {    return new QCMakeCachePathEditor(p);    }  else if(type == QCMakeCacheProperty::FILEPATH)    {    return new QCMakeCacheFilePathEditor(p);    }  return new QLineEdit(p);}  bool QCMakeCacheModelDelegate::editorEvent(QEvent* event, QAbstractItemModel* model,        const QStyleOptionViewItem& option, const QModelIndex& index){  Qt::ItemFlags flags = model->flags(index);  if (!(flags & Qt::ItemIsUserCheckable) || !(option.state & QStyle::State_Enabled)      || !(flags & Qt::ItemIsEnabled))    {    return false;    }  QVariant value = index.data(Qt::CheckStateRole);  if (!value.isValid())    {    return false;    }  if ((event->type() == QEvent::MouseButtonRelease)      || (event->type() == QEvent::MouseButtonDblClick))    {    // eat the double click events inside the check rect    if (event->type() == QEvent::MouseButtonDblClick)      {      return true;      }    }   else if (event->type() == QEvent::KeyPress)    {    if(static_cast<QKeyEvent*>(event)->key() != Qt::Key_Space &&       static_cast<QKeyEvent*>(event)->key() != Qt::Key_Select)      {      return false;      }    }   else     {    return false;    }  Qt::CheckState state = (static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked                          ? Qt::Unchecked : Qt::Checked);  return model->setData(index, state, Qt::CheckStateRole);}  QCMakeCacheFileEditor::QCMakeCacheFileEditor(QWidget* p)  : QLineEdit(p){  // this *is* instead of has a line edit so QAbstractItemView  // doesn't get confused with what the editor really is  this->setContentsMargins(0, 0, 0, 0);  this->ToolButton = new QToolButton(this);  this->ToolButton->setText("...");  this->ToolButton->setCursor(QCursor(Qt::ArrowCursor));  QObject::connect(this->ToolButton, SIGNAL(clicked(bool)),                   this, SLOT(chooseFile()));}QCMakeCacheFilePathEditor::QCMakeCacheFilePathEditor(QWidget* p) : QCMakeCacheFileEditor(p){  QCompleter* comp = new QCompleter(this);  QDirModel* model = new QDirModel(comp);  comp->setModel(model);  this->setCompleter(comp);}QCMakeCachePathEditor::QCMakeCachePathEditor(QWidget* p) : QCMakeCacheFileEditor(p){  QCompleter* comp = new QCompleter(this);  QDirModel* model = new QDirModel(comp);  model->setFilter(QDir::AllDirs | QDir::Drives);  comp->setModel(model);  this->setCompleter(comp);}void QCMakeCacheFileEditor::resizeEvent(QResizeEvent* e){  // make the tool button fit on the right side  int h = e->size().height();  this->ToolButton->resize(h, h);  this->ToolButton->move(this->width() - h, 0);  this->setContentsMargins(0, 0, h, 0);}void QCMakeCacheFilePathEditor::chooseFile(){  // choose a file and set it  QString path;  QFileInfo info(this->text());  path = QFileDialog::getOpenFileName(this, tr("Select File"),       info.absolutePath());    if(!path.isEmpty())    {    this->setText(path);    }}void QCMakeCachePathEditor::chooseFile(){  // choose a file and set it  QString path;  path = QFileDialog::getExistingDirectory(this, tr("Select Path"),       this->text());  if(!path.isEmpty())    {    this->setText(path);    }}
 |