QCMakeCacheView.cxx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. /*=========================================================================
  2. Program: CMake - Cross-Platform Makefile Generator
  3. Module: $RCSfile$
  4. Language: C++
  5. Date: $Date$
  6. Version: $Revision$
  7. Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
  8. See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
  9. This software is distributed WITHOUT ANY WARRANTY; without even
  10. the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  11. PURPOSE. See the above copyright notices for more information.
  12. =========================================================================*/
  13. #include "QCMakeCacheView.h"
  14. #include <QToolButton>
  15. #include <QFileDialog>
  16. #include <QHBoxLayout>
  17. #include <QHeaderView>
  18. #include <QEvent>
  19. #include <QFileInfo>
  20. #include <QStyle>
  21. #include <QKeyEvent>
  22. #include <QMenu>
  23. #include <QDirModel>
  24. #include <QCompleter>
  25. static QRegExp AdvancedRegExp[2] = { QRegExp("(false)"), QRegExp("(true|false)") };
  26. QCMakeCacheView::QCMakeCacheView(QWidget* p)
  27. : QTableView(p), Init(false)
  28. {
  29. // hook up our model and search/filter proxies
  30. this->CacheModel = new QCMakeCacheModel(this);
  31. this->AdvancedFilter = new QSortFilterProxyModel(this);
  32. this->AdvancedFilter->setSourceModel(this->CacheModel);
  33. this->AdvancedFilter->setFilterRole(QCMakeCacheModel::AdvancedRole);
  34. this->AdvancedFilter->setFilterRegExp(AdvancedRegExp[0]);
  35. this->AdvancedFilter->setDynamicSortFilter(true);
  36. this->SearchFilter = new QSortFilterProxyModel(this);
  37. this->SearchFilter->setSourceModel(this->AdvancedFilter);
  38. this->SearchFilter->setFilterCaseSensitivity(Qt::CaseInsensitive);
  39. this->SearchFilter->setFilterKeyColumn(-1); // all columns
  40. this->SearchFilter->setDynamicSortFilter(true);
  41. this->setModel(this->SearchFilter);
  42. // our delegate for creating our editors
  43. QCMakeCacheModelDelegate* delegate = new QCMakeCacheModelDelegate(this);
  44. this->setItemDelegate(delegate);
  45. // set up headers and sizes
  46. int h = 0;
  47. QFontMetrics met(this->font());
  48. h = qMax(met.height(), this->style()->pixelMetric(QStyle::PM_IndicatorHeight));
  49. this->verticalHeader()->setDefaultSectionSize(h + 4);
  50. this->horizontalHeader()->setStretchLastSection(true);
  51. this->verticalHeader()->hide();
  52. }
  53. void QCMakeCacheView::showEvent(QShowEvent* e)
  54. {
  55. if(!this->Init)
  56. {
  57. // initialize the table view column size
  58. int colWidth = this->columnWidth(0) + this->columnWidth(1);
  59. this->setColumnWidth(0, colWidth/2);
  60. this->setColumnWidth(1, colWidth/2);
  61. this->Init = true;
  62. }
  63. return QTableView::showEvent(e);
  64. }
  65. QCMakeCacheModel* QCMakeCacheView::cacheModel() const
  66. {
  67. return this->CacheModel;
  68. }
  69. QModelIndex QCMakeCacheView::moveCursor(CursorAction act,
  70. Qt::KeyboardModifiers mod)
  71. {
  72. // tab through values only (not names)
  73. QModelIndex current = this->currentIndex();
  74. if(act == MoveNext)
  75. {
  76. if(!current.isValid())
  77. {
  78. return this->model()->index(0, 1);
  79. }
  80. else if(current.column() == 0)
  81. {
  82. return this->model()->index(current.row(), 1);
  83. }
  84. else
  85. {
  86. return this->model()->index(current.row()+1, 1);
  87. }
  88. }
  89. else if(act == MovePrevious)
  90. {
  91. if(!current.isValid())
  92. {
  93. return this->model()->index(0, 1);
  94. }
  95. else
  96. {
  97. return this->model()->index(current.row()-1, 1);
  98. }
  99. }
  100. return QTableView::moveCursor(act, mod);
  101. }
  102. void QCMakeCacheView::setShowAdvanced(bool s)
  103. {
  104. this->AdvancedFilter->setFilterRegExp(
  105. s ? AdvancedRegExp[1] : AdvancedRegExp[0]);
  106. }
  107. bool QCMakeCacheView::showAdvanced() const
  108. {
  109. return this->AdvancedFilter->filterRegExp() == AdvancedRegExp[1];
  110. }
  111. void QCMakeCacheView::setSearchFilter(const QString& s)
  112. {
  113. this->SearchFilter->setFilterFixedString(s);
  114. }
  115. QCMakeCacheModel::QCMakeCacheModel(QObject* p)
  116. : QAbstractTableModel(p),
  117. NewCount(0), EditEnabled(true)
  118. {
  119. }
  120. QCMakeCacheModel::~QCMakeCacheModel()
  121. {
  122. }
  123. static uint qHash(const QCMakeCacheProperty& p)
  124. {
  125. return qHash(p.Key);
  126. }
  127. void QCMakeCacheModel::clear()
  128. {
  129. this->setProperties(QCMakeCachePropertyList());
  130. }
  131. void QCMakeCacheModel::setProperties(const QCMakeCachePropertyList& props)
  132. {
  133. QSet<QCMakeCacheProperty> newProps = props.toSet();
  134. QSet<QCMakeCacheProperty> newProps2 = props.toSet();
  135. QSet<QCMakeCacheProperty> oldProps = this->Properties.toSet();
  136. oldProps.intersect(newProps);
  137. newProps.subtract(oldProps);
  138. newProps2.subtract(newProps);
  139. this->NewCount = newProps.count();
  140. this->Properties.clear();
  141. this->Properties = newProps.toList();
  142. qSort(this->Properties);
  143. QCMakeCachePropertyList tmp = newProps2.toList();
  144. qSort(tmp);
  145. this->Properties += tmp;
  146. this->reset();
  147. }
  148. QCMakeCachePropertyList QCMakeCacheModel::properties() const
  149. {
  150. return this->Properties;
  151. }
  152. void QCMakeCacheModel::setEditEnabled(bool e)
  153. {
  154. this->EditEnabled = e;
  155. }
  156. bool QCMakeCacheModel::editEnabled() const
  157. {
  158. return this->EditEnabled;
  159. }
  160. int QCMakeCacheModel::newCount() const
  161. {
  162. return this->NewCount;
  163. }
  164. int QCMakeCacheModel::columnCount (const QModelIndex& /*p*/ ) const
  165. {
  166. return 2;
  167. }
  168. QVariant QCMakeCacheModel::data (const QModelIndex& idx, int role) const
  169. {
  170. if(idx.column() == 0 && (role == Qt::DisplayRole || role == Qt::EditRole))
  171. {
  172. return this->Properties[idx.row()].Key;
  173. }
  174. else if(idx.column() == 0 && role == Qt::ToolTipRole)
  175. {
  176. return this->data(idx, Qt::DisplayRole).toString() + "\n" +
  177. this->data(idx, QCMakeCacheModel::HelpRole).toString();
  178. }
  179. else if(idx.column() == 1 && (role == Qt::DisplayRole || role == Qt::EditRole))
  180. {
  181. if(this->Properties[idx.row()].Type != QCMakeCacheProperty::BOOL)
  182. {
  183. return this->Properties[idx.row()].Value;
  184. }
  185. }
  186. else if(idx.column() == 1 && role == Qt::CheckStateRole)
  187. {
  188. if(this->Properties[idx.row()].Type == QCMakeCacheProperty::BOOL)
  189. {
  190. return this->Properties[idx.row()].Value.toBool() ? Qt::Checked : Qt::Unchecked;
  191. }
  192. }
  193. else if(role == QCMakeCacheModel::HelpRole)
  194. {
  195. return this->Properties[idx.row()].Help;
  196. }
  197. else if(role == QCMakeCacheModel::TypeRole)
  198. {
  199. return this->Properties[idx.row()].Type;
  200. }
  201. else if(role == QCMakeCacheModel::AdvancedRole)
  202. {
  203. return this->Properties[idx.row()].Advanced;
  204. }
  205. else if(role == Qt::BackgroundRole && idx.row()+1 <= this->NewCount)
  206. {
  207. return QBrush(QColor(255,100,100));
  208. }
  209. return QVariant();
  210. }
  211. QModelIndex QCMakeCacheModel::parent (const QModelIndex& /*idx*/) const
  212. {
  213. return QModelIndex();
  214. }
  215. int QCMakeCacheModel::rowCount (const QModelIndex& p) const
  216. {
  217. if(p.isValid())
  218. {
  219. return 0;
  220. }
  221. return this->Properties.count();
  222. }
  223. QVariant QCMakeCacheModel::headerData (int section, Qt::Orientation orient, int role) const
  224. {
  225. // return header labels
  226. if(role == Qt::DisplayRole && orient == Qt::Horizontal)
  227. {
  228. return section == 0 ? "Name" : "Value";
  229. }
  230. return QVariant();
  231. }
  232. Qt::ItemFlags QCMakeCacheModel::flags (const QModelIndex& idx) const
  233. {
  234. Qt::ItemFlags f = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
  235. // all column 1's are editable
  236. if(idx.column() == 1 && this->EditEnabled)
  237. {
  238. f |= Qt::ItemIsEditable;
  239. // booleans are editable in place
  240. if(this->Properties[idx.row()].Type == QCMakeCacheProperty::BOOL)
  241. {
  242. f |= Qt::ItemIsUserCheckable;
  243. }
  244. }
  245. return f;
  246. }
  247. bool QCMakeCacheModel::setData (const QModelIndex& idx, const QVariant& value, int role)
  248. {
  249. if(idx.column() == 0 && (role == Qt::DisplayRole || role == Qt::EditRole))
  250. {
  251. this->Properties[idx.row()].Key = value.toString();
  252. emit this->dataChanged(idx, idx);
  253. }
  254. else if(idx.column() == 1 && (role == Qt::DisplayRole || role == Qt::EditRole))
  255. {
  256. this->Properties[idx.row()].Value = value.toString();
  257. emit this->dataChanged(idx, idx);
  258. }
  259. else if(idx.column() == 1 && (role == Qt::CheckStateRole))
  260. {
  261. this->Properties[idx.row()].Value = value.toInt() == Qt::Checked;
  262. emit this->dataChanged(idx, idx);
  263. }
  264. else if(role == QCMakeCacheModel::HelpRole)
  265. {
  266. this->Properties[idx.row()].Help = value.toString();
  267. emit this->dataChanged(idx, idx);
  268. }
  269. else if(role == QCMakeCacheModel::TypeRole)
  270. {
  271. this->Properties[idx.row()].Type = static_cast<QCMakeCacheProperty::PropertyType>(value.toInt());
  272. }
  273. else if(role == QCMakeCacheModel::AdvancedRole)
  274. {
  275. this->Properties[idx.row()].Advanced = value.toBool();
  276. }
  277. return false;
  278. }
  279. QModelIndex QCMakeCacheModel::buddy ( const QModelIndex& idx ) const
  280. {
  281. if(idx.column() == 0)
  282. {
  283. return this->index(idx.row(), 1);
  284. }
  285. return idx;
  286. }
  287. bool QCMakeCacheModel::removeRows(int row, int num, const QModelIndex&)
  288. {
  289. if(row < 0 || row+num > this->Properties.count())
  290. {
  291. return false;
  292. }
  293. this->beginRemoveRows(QModelIndex(), row, row+num-1);
  294. for(int i=0; i<num; i++)
  295. {
  296. this->Properties.removeAt(row);
  297. if(this->NewCount >= row+1)
  298. {
  299. this->NewCount--;
  300. }
  301. }
  302. this->endRemoveRows();
  303. return true;
  304. }
  305. bool QCMakeCacheModel::insertRows(int row, int num, const QModelIndex&)
  306. {
  307. if(row < 0)
  308. row = 0;
  309. if(row > this->rowCount())
  310. row = this->rowCount();
  311. this->beginInsertRows(QModelIndex(), row, row+num-1);
  312. for(int i=0; i<num; i++)
  313. {
  314. this->Properties.insert(row+i, QCMakeCacheProperty());
  315. if(this->NewCount >= row)
  316. {
  317. this->NewCount++;
  318. }
  319. }
  320. this->endInsertRows();
  321. return true;
  322. }
  323. QCMakeCacheModelDelegate::QCMakeCacheModelDelegate(QObject* p)
  324. : QItemDelegate(p)
  325. {
  326. }
  327. QWidget* QCMakeCacheModelDelegate::createEditor(QWidget* p,
  328. const QStyleOptionViewItem&, const QModelIndex& idx) const
  329. {
  330. QVariant type = idx.data(QCMakeCacheModel::TypeRole);
  331. if(type == QCMakeCacheProperty::BOOL)
  332. {
  333. return NULL;
  334. }
  335. else if(type == QCMakeCacheProperty::PATH)
  336. {
  337. return new QCMakeCachePathEditor(p);
  338. }
  339. else if(type == QCMakeCacheProperty::FILEPATH)
  340. {
  341. return new QCMakeCacheFilePathEditor(p);
  342. }
  343. return new QLineEdit(p);
  344. }
  345. QCMakeCacheFileEditor::QCMakeCacheFileEditor(QWidget* p)
  346. : QLineEdit(p)
  347. {
  348. // this *is* instead of has a line edit so QAbstractItemView
  349. // doesn't get confused with what the editor really is
  350. this->setContentsMargins(0, 0, 0, 0);
  351. this->ToolButton = new QToolButton(this);
  352. this->ToolButton->setText("...");
  353. this->ToolButton->setCursor(QCursor(Qt::ArrowCursor));
  354. QObject::connect(this->ToolButton, SIGNAL(clicked(bool)),
  355. this, SLOT(chooseFile()));
  356. }
  357. QCMakeCacheFilePathEditor::QCMakeCacheFilePathEditor(QWidget* p)
  358. : QCMakeCacheFileEditor(p)
  359. {
  360. QCompleter* comp = new QCompleter(this);
  361. QDirModel* model = new QDirModel(comp);
  362. comp->setModel(model);
  363. this->setCompleter(comp);
  364. }
  365. QCMakeCachePathEditor::QCMakeCachePathEditor(QWidget* p)
  366. : QCMakeCacheFileEditor(p)
  367. {
  368. QCompleter* comp = new QCompleter(this);
  369. QDirModel* model = new QDirModel(comp);
  370. model->setFilter(QDir::AllDirs | QDir::Drives);
  371. comp->setModel(model);
  372. this->setCompleter(comp);
  373. }
  374. void QCMakeCacheFileEditor::resizeEvent(QResizeEvent* e)
  375. {
  376. // make the tool button fit on the right side
  377. int h = e->size().height();
  378. this->ToolButton->resize(h, h);
  379. this->ToolButton->move(this->width() - h, 0);
  380. this->setContentsMargins(0, 0, h, 0);
  381. }
  382. void QCMakeCacheFilePathEditor::chooseFile()
  383. {
  384. // choose a file and set it
  385. QString path;
  386. QFileInfo info(this->text());
  387. path = QFileDialog::getOpenFileName(this, tr("Select File"),
  388. info.absolutePath());
  389. if(!path.isEmpty())
  390. {
  391. this->setText(path);
  392. }
  393. }
  394. void QCMakeCachePathEditor::chooseFile()
  395. {
  396. // choose a file and set it
  397. QString path;
  398. path = QFileDialog::getExistingDirectory(this, tr("Select Path"),
  399. this->text());
  400. if(!path.isEmpty())
  401. {
  402. this->setText(path);
  403. }
  404. }