SeExpr
ExprBrowser.cpp
Go to the documentation of this file.
1 /*
2 * Copyright Disney Enterprises, Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License
6 * and the following modification to it: Section 6 Trademarks.
7 * deleted and replaced with:
8 *
9 * 6. Trademarks. This License does not grant permission to use the
10 * trade names, trademarks, service marks, or product names of the
11 * Licensor and its affiliates, except as required for reproducing
12 * the content of the NOTICE file.
13 *
14 * You may obtain a copy of the License at
15 * http://www.apache.org/licenses/LICENSE-2.0
16 *
17 * @file ExprBrowser.cpp
18 * @brief Qt browser widget for list of expressions
19 * @author aselle
20 */
21 #include <QDir>
22 #include <QFileInfo>
23 #include <QTreeWidget>
24 #include <QTreeWidgetItem>
25 #include <QVBoxLayout>
26 #include <QTabWidget>
27 #include <QHeaderView>
28 #include <QLabel>
29 #include <QTextBrowser>
30 #include <QPushButton>
31 #include <QSpacerItem>
32 #include <QSizePolicy>
33 #include <QSortFilterProxyModel>
34 #include <QFileDialog>
35 #include <QMessageBox>
36 
37 #include <cassert>
38 #include "ExprEditor.h"
39 #include "ExprBrowser.h"
40 
41 #define P3D_CONFIG_ENVVAR "P3D_CONFIG_PATH"
42 
43 class ExprTreeItem {
44  public:
45  ExprTreeItem(ExprTreeItem* parent, const QString& label, const QString& path)
46  : row(-1), parent(parent), label(label), path(path), populated(parent == 0) {}
47 
49  for (unsigned int i = 0; i < children.size(); i++) delete children[i];
50  }
51 
52  ExprTreeItem* find(QString path) {
53  if (this->path == path)
54  return this;
55  else {
56  populate();
57  for (unsigned int i = 0; i < children.size(); i++) {
58  ExprTreeItem* ret = children[i]->find(path);
59  if (ret) return ret;
60  }
61  }
62  return 0;
63  }
64 
65  void clear() {
66  for (unsigned int i = 0; i < children.size(); i++) {
67  delete children[i];
68  }
69  children.clear();
70  }
71 
72  void populate() {
73  if (populated) return;
74  populated = true;
75  QFileInfo info(path);
76  if (info.isDir()) {
77  QFileInfoList infos = QDir(path).entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
78 
79  // std::cerr<<"is dir and populating "<<path.toStdString()<<std::endl;
80  for (QList<QFileInfo>::ConstIterator it = infos.constBegin(); it != infos.constEnd(); ++it) {
81  const QFileInfo* fi = &*it;
82  if (fi->isDir() || fi->fileName().endsWith(".se")) {
83  addChild(new ExprTreeItem(this, fi->fileName(), fi->filePath()));
84  }
85  }
86  }
87  }
88 
89  void addChild(ExprTreeItem* child) {
90  child->row = children.size();
91  children.push_back(child);
92  }
93 
94  ExprTreeItem* getChild(const int row) {
95  populate();
96  if (row < 0 || row > (int)children.size()) {
97  assert(false);
98  }
99  return children[row];
100  }
101 
103  populate();
104  return children.size();
105  }
106 
107  void regen() {
108  std::vector<QString> labels, paths;
109  for (unsigned int i = 0; i < children.size(); i++) {
110  labels.push_back(children[i]->label);
111  paths.push_back(children[i]->path);
112  delete children[i];
113  }
114  children.clear();
115 
116  for (unsigned int i = 0; i < labels.size(); i++) addChild(new ExprTreeItem(this, labels[i], paths[i]));
117  }
118 
119  int row;
121  QString label;
122  QString path;
123 
124  private:
125  std::vector<ExprTreeItem*> children;
126  bool populated;
127 };
128 
129 class ExprTreeModel : public QAbstractItemModel {
131 
132  public:
133  ExprTreeModel() : root(new ExprTreeItem(0, "", "")) {}
134 
135  ~ExprTreeModel() { delete root; }
136 
137  void update()
138  {
139  beginResetModel();
140  endResetModel();
141  }
142 
143  void clear() {
144  beginResetModel();
145  root->clear();
146  endResetModel();
147  }
148 
149  void addPath(const char* label, const char* path) { root->addChild(new ExprTreeItem(root, label, path)); }
150 
151  QModelIndex parent(const QModelIndex& index) const {
152  if (!index.isValid()) return QModelIndex();
153  ExprTreeItem* item = (ExprTreeItem*)(index.internalPointer());
154  ExprTreeItem* parentItem = item->parent;
155  if (parentItem == root)
156  return QModelIndex();
157  else
158  return createIndex(parentItem->row, 0, parentItem);
159  }
160 
161  QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const {
162  if (!hasIndex(row, column, parent))
163  return QModelIndex();
164  else if (!parent.isValid())
165  return createIndex(row, column, root->getChild(row));
166  else {
167  ExprTreeItem* item = (ExprTreeItem*)(parent.internalPointer());
168  return createIndex(row, column, item->getChild(row));
169  }
170  }
171 
172  int columnCount(const QModelIndex& parent) const {
173  Q_UNUSED(parent);
174  return 1;
175  }
176 
177  int rowCount(const QModelIndex& parent = QModelIndex()) const {
178  if (!parent.isValid())
179  return root->getChildCount();
180  else {
181  ExprTreeItem* item = (ExprTreeItem*)(parent.internalPointer());
182  if (!item)
183  return root->getChildCount();
184  else
185  return item->getChildCount();
186  }
187  }
188 
189  QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const {
190  if (!index.isValid()) return QVariant();
191  if (role != Qt::DisplayRole) return QVariant();
192  ExprTreeItem* item = (ExprTreeItem*)(index.internalPointer());
193  if (!item)
194  return QVariant();
195  else
196  return QVariant(item->label);
197  }
198 
199  QModelIndex find(QString path) {
200  ExprTreeItem* item = root->find(path);
201  if (!item) {
202  beginResetModel();
203  root->regen();
204  endResetModel();
205  item = root->find(path);
206  }
207  if (item) {
208  std::cerr << "found it " << std::endl;
209  return createIndex(item->row, 0, item);
210  }
211 
212  return QModelIndex();
213  }
214 };
215 
216 class ExprTreeFilterModel : public QSortFilterProxyModel {
217  public:
218  ExprTreeFilterModel(QWidget* parent = 0) : QSortFilterProxyModel(parent) {}
219 
220  void update()
221  {
222  beginResetModel();
223  endResetModel();
224  }
225 
226  bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const {
227  if (sourceParent.isValid() && sourceModel()->data(sourceParent).toString().contains(filterRegExp()))
228  return true;
229  QString data = sourceModel()->data(sourceModel()->index(sourceRow, 0, sourceParent)).toString();
230  bool keep = data.contains(filterRegExp());
231 
232  QModelIndex subIndex = sourceModel()->index(sourceRow, 0, sourceParent);
233  if (subIndex.isValid()) {
234  for (int i = 0; i < sourceModel()->rowCount(subIndex); ++i) keep = keep || filterAcceptsRow(i, subIndex);
235  }
236  return keep;
237  }
238 };
239 
241 
242 ExprBrowser::ExprBrowser(QWidget* parent, ExprEditor* editor)
243  : QWidget(parent), editor(editor), _context(""), _searchPath(""), _applyOnSelect(true) {
244  QVBoxLayout* rootLayout = new QVBoxLayout;
245  rootLayout->setMargin(0);
246  this->setLayout(rootLayout);
247  // search and clear widgets
248  QHBoxLayout* searchAndClearLayout = new QHBoxLayout();
249  exprFilter = new QLineEdit();
250  connect(exprFilter, SIGNAL(textChanged(const QString&)), SLOT(filterChanged(const QString&)));
251  searchAndClearLayout->addWidget(exprFilter, 2);
252  QPushButton* clearFilterButton = new QPushButton("X");
253  clearFilterButton->setFixedWidth(24);
254  searchAndClearLayout->addWidget(clearFilterButton, 1);
255  rootLayout->addLayout(searchAndClearLayout);
256  connect(clearFilterButton, SIGNAL(clicked()), SLOT(clearFilter()));
257  // model of tree
258  treeModel = new ExprTreeModel();
259  proxyModel = new ExprTreeFilterModel(this);
260  proxyModel->setSourceModel(treeModel);
261  // tree widget
262  treeNew = new QTreeView;
263  treeNew->setModel(proxyModel);
264  treeNew->hideColumn(1);
265  treeNew->setHeaderHidden(true);
266  rootLayout->addWidget(treeNew);
267  // selection mode and signal
268  treeNew->setSelectionMode(QAbstractItemView::SingleSelection);
269  connect(treeNew->selectionModel(),
270  SIGNAL(currentChanged(const QModelIndex&, const QModelIndex&)),
271  SLOT(handleSelection(const QModelIndex&, const QModelIndex&)));
272 }
273 
274 void ExprBrowser::addPath(const std::string& name, const std::string& path) {
275  labels.append(QString::fromStdString(name));
276  paths.append(QString::fromStdString(path));
277  treeModel->addPath(name.c_str(), path.c_str());
278 }
279 
280 void ExprBrowser::setSearchPath(const QString& context, const QString& path) {
281  _context = context.toStdString();
282  _searchPath = path.toStdString();
283 }
284 
286  QModelIndex sel = treeNew->currentIndex();
287  if (sel.isValid()) {
288  QModelIndex realCurrent = proxyModel->mapToSource(sel);
289  ExprTreeItem* item = (ExprTreeItem*)realCurrent.internalPointer();
290  return item->path.toStdString();
291  }
292  return std::string("");
293 }
294 
295 void ExprBrowser::selectPath(const char* path) {
296  QModelIndex index = treeModel->find(path);
297  treeNew->setCurrentIndex(proxyModel->mapFromSource(index));
298 }
299 
301  treeModel->update();
302  proxyModel->update();
303 }
304 
305 void ExprBrowser::handleSelection(const QModelIndex& current, const QModelIndex& previous) {
306  Q_UNUSED(previous)
307  if (current.isValid()) {
308  QModelIndex realCurrent = proxyModel->mapToSource(current);
309  ExprTreeItem* item = (ExprTreeItem*)realCurrent.internalPointer();
310  QString path = item->path;
311  if (path.endsWith(".se")) {
312  std::ifstream file(path.toStdString().c_str());
313  std::string fileContents((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
314  editor->setExpr(fileContents, _applyOnSelect);
315  }
316  }
317 }
318 
320  labels.clear();
321  paths.clear();
322  clearSelection();
323 
324  treeModel->clear();
325 }
326 
327 void ExprBrowser::clearSelection() { treeNew->clearSelection(); }
328 
330 
331 void ExprBrowser::filterChanged(const QString& str) {
332  proxyModel->setFilterRegExp(QRegExp(str));
333  proxyModel->setFilterKeyColumn(0);
334  if (str != "") {
335  treeNew->expandAll();
336  } else {
337  treeNew->collapseAll();
338  }
339 }
340 
342  QString path = QFileDialog::getSaveFileName(this, "Save Expression", QString::fromStdString(_userExprDir), "*.se");
343 
344  if (path.length() > 0) {
345  std::ofstream file(path.toStdString().c_str());
346  if (!file) {
347  QString msg = QString("Could not open file %1 for writing").arg(path);
348  QMessageBox::warning(this, "Error", QString("<font face=fixed>%1</font>").arg(msg));
349  return;
350  }
351  file << editor->getExpr();
352  file.close();
353 
354  update();
355  selectPath(path.toStdString().c_str());
356  }
357 }
358 
360  QString path = QFileDialog::getSaveFileName(this, "Save Expression", QString::fromStdString(_localExprDir), "*.se");
361 
362  if (path.length() > 0) {
363  std::ofstream file(path.toStdString().c_str());
364  if (!file) {
365  QString msg = QString("Could not open file %1 for writing").arg(path);
366  QMessageBox::warning(this, "Error", QString("<font face=fixed>%1</font>").arg(msg));
367  return;
368  }
369  file << editor->getExpr();
370  file.close();
371 
372  update();
373  selectPath(path.toStdString().c_str());
374  }
375 }
376 
378  std::string path = getSelectedPath();
379  if (path.length() == 0) {
381  return;
382  }
383  std::ofstream file(path.c_str());
384  if (!file) {
385  QString msg =
386  QString("Could not open file %1 for writing. Is it read-only?").arg(QString::fromStdString(path));
387  QMessageBox::warning(this, "Error", QString("<font face=fixed>%1</font>").arg(msg));
388  return;
389  }
390  file << editor->getExpr();
391  file.close();
392 }
393 
394 void ExprBrowser::expandAll() { treeNew->expandAll(); }
395 
396 void ExprBrowser::expandToDepth(int depth) { treeNew->expandToDepth(depth); }
397 
398 // Location for storing user's expression files
399 void ExprBrowser::addUserExpressionPath(const std::string& context) {
400  char* homepath = getenv("HOME");
401  if (homepath) {
402  std::string path = std::string(homepath) + "/" + context + "/expressions/";
403  if (QDir(QString(path.c_str())).exists()) {
404  _userExprDir = path;
405  addPath("My Expressions", path);
406  }
407  }
408 }
409 
410 /*
411  * NOTE: The hard-coded paint3d assumptions can be removed once
412  * it (and bonsai?) are adjusted to call setSearchPath(context, path)
413  */
414 
416  const char* env;
417  bool enableLocal = false;
418  /*bool homeFound = false; -- for xgen's config.txt UserRepo section below */
419 
420  if (_searchPath.length() > 0)
421  env = _searchPath.c_str();
422  else
423  env = getenv(P3D_CONFIG_ENVVAR); /* For backwards compatibility */
424 
425  if (!env) return enableLocal;
426 
427  std::string context;
428  if (_context.length() > 0) {
429  context = _context;
430  } else {
431  context = "paint3d"; /* For backwards compatibility */
432  }
433 
434  clear();
435 
436  std::string configFile = std::string(env) + "/config.txt";
437  std::ifstream file(configFile.c_str());
438  if (file) {
439 
440  std::string key;
441  while (file) {
442  file >> key;
443 
444  if (key[0] == '#') {
445  char buffer[1024];
446  file.getline(buffer, 1024);
447  } else {
448  if (key == "ExpressionDir") {
449  std::string label, path;
450  file >> label;
451  file >> path;
452  if (QDir(QString(path.c_str())).exists()) addPath(label, path);
453  } else if (key == "ExpressionSubDir") {
454  std::string path;
455  file >> path;
456  _localExprDir = path;
457  if (QDir(QString(path.c_str())).exists()) {
458  addPath("Local", _localExprDir);
459  enableLocal = true;
460  }
461  /* These are for compatibility with xgen.
462  * Long-term, xgen should use the same format.
463  * Longer-term, we should use JSON or something */
464  } else if (key == "GlobalRepo") {
465  std::string path;
466  file >> path;
467  path += "/expressions/";
468  if (QDir(QString(path.c_str())).exists()) addPath("Global", path);
469  } else if (key == "LocalRepo") {
470  std::string path;
471  file >> path;
472  path += "/expressions/";
473  _localExprDir = path;
474  if (QDir(QString(path.c_str())).exists()) {
475  addPath("Local", _localExprDir);
476  enableLocal = true;
477  }
478 
479  /*
480  * xgen's config.txt has a "UserRepo" section but we
481  * intentionally ignore it since we already add the user dir
482  * down where the HOME stuff is handled
483  */
484 
485  /*
486  } else if (key == "UserRepo") {
487  std::string path;
488  file>>path;
489  path += "/expressions/";
490 
491  size_t found = path.find("${HOME}");
492 
493  if (found != std::string::npos) {
494  char *homepath = getenv("HOME");
495  if (homepath) {
496  path.replace(found, strlen("${HOME}"), homepath);
497  } else {
498  continue;
499  }
500  }
501  if(QDir(QString(path.c_str())).exists()){
502  addPath("User", path);
503  homeFound = true;
504  }
505  */
506  } else {
507  char buffer[1024];
508  file.getline(buffer, 1024);
509  }
510  }
511  }
512  }
514  update();
515  return enableLocal;
516 }
ExprBrowser::clearSelection
void clearSelection()
Definition: ExprBrowser.cpp:327
index
The result is computed int int< br >< div style="margin-left: 40px;"> Picks values randomly between loRange and hiRange based on supplied index(which is automatically hashed). &nbsp
ExprTreeItem::parent
ExprTreeItem * parent
Definition: ExprBrowser.cpp:120
ExprBrowser::_localExprDir
std::string _localExprDir
Definition: ExprBrowser.h:54
ExprEditor
Definition: ExprEditor.h:94
ExprTreeItem::clear
void clear()
Definition: ExprBrowser.cpp:65
ExprBrowser::expandAll
void expandAll()
Definition: ExprBrowser.cpp:394
ExprTreeModel::index
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const
Definition: ExprBrowser.cpp:161
ExprBrowser::filterChanged
void filterChanged(const QString &str)
Definition: ExprBrowser.cpp:331
ExprBrowser::update
void update()
Definition: ExprBrowser.cpp:300
ExprTreeModel::addPath
void addPath(const char *label, const char *path)
Definition: ExprBrowser.cpp:149
ExprBrowser::saveLocalExpressionAs
void saveLocalExpressionAs()
Definition: ExprBrowser.cpp:359
ExprBrowser::saveExpressionAs
void saveExpressionAs()
Definition: ExprBrowser.cpp:341
ExprTreeItem::children
std::vector< ExprTreeItem * > children
Definition: ExprBrowser.cpp:125
ExprBrowser::_applyOnSelect
bool _applyOnSelect
Definition: ExprBrowser.h:57
ExprTreeItem::addChild
void addChild(ExprTreeItem *child)
Definition: ExprBrowser.cpp:89
ExprBrowser::handleSelection
void handleSelection(const QModelIndex &current, const QModelIndex &previous)
Definition: ExprBrowser.cpp:305
ExprTreeItem::regen
void regen()
Definition: ExprBrowser.cpp:107
ExprBrowser::setSearchPath
void setSearchPath(const QString &context, const QString &path)
Definition: ExprBrowser.cpp:280
ExprTreeModel::rowCount
int rowCount(const QModelIndex &parent=QModelIndex()) const
Definition: ExprBrowser.cpp:177
ExprTreeItem::label
QString label
Definition: ExprBrowser.cpp:121
ExprBrowser::expandToDepth
void expandToDepth(int depth)
Definition: ExprBrowser.cpp:396
ExprBrowser::proxyModel
ExprTreeFilterModel * proxyModel
Definition: ExprBrowser.h:50
ExprTreeItem::populated
bool populated
Definition: ExprBrowser.cpp:126
ExprBrowser::treeNew
QTreeView * treeNew
Definition: ExprBrowser.h:51
ExprTreeItem::find
ExprTreeItem * find(QString path)
Definition: ExprBrowser.cpp:52
ExprTreeItem
Definition: ExprBrowser.cpp:43
ExprTreeItem::path
QString path
Definition: ExprBrowser.cpp:122
ExprTreeItem::populate
void populate()
Definition: ExprBrowser.cpp:72
ExprBrowser::_searchPath
std::string _searchPath
Definition: ExprBrowser.h:56
ExprTreeItem::getChild
ExprTreeItem * getChild(const int row)
Definition: ExprBrowser.cpp:94
ExprTreeModel::ExprTreeModel
ExprTreeModel()
Definition: ExprBrowser.cpp:133
ExprTreeModel::find
QModelIndex find(QString path)
Definition: ExprBrowser.cpp:199
ExprTreeModel::~ExprTreeModel
~ExprTreeModel()
Definition: ExprBrowser.cpp:135
ExprBrowser::saveExpression
void saveExpression()
Definition: ExprBrowser.cpp:377
ExprTreeModel::columnCount
int columnCount(const QModelIndex &parent) const
Definition: ExprBrowser.cpp:172
ExprBrowser::_context
std::string _context
Definition: ExprBrowser.h:55
ExprEditor::getExpr
std::string getExpr()
Definition: ExprEditor.cpp:373
ExprBrowser::ExprBrowser
ExprBrowser(QWidget *parent, ExprEditor *editor)
Definition: ExprBrowser.cpp:242
it
you may not use this file except in compliance with the License and the following modification to it
Definition: license.txt:10
ExprTreeItem::row
int row
Definition: ExprBrowser.cpp:119
ExprBrowser::labels
QList< QString > labels
Definition: ExprBrowser.h:47
ExprBrowser.h
ExprBrowser::_userExprDir
std::string _userExprDir
Definition: ExprBrowser.h:53
ExprTreeModel::update
void update()
Definition: ExprBrowser.cpp:137
ExprTreeFilterModel
Definition: ExprBrowser.cpp:216
file
file(GLOB io_cpp "*.cpp") file(GLOB to_remove "ExprLLVMCodeGeneration.cpp") list(REMOVE_ITEM io_cpp $
Definition: CMakeLists.txt:17
ExprTreeItem::getChildCount
int getChildCount()
Definition: ExprBrowser.cpp:102
ExprTreeFilterModel::filterAcceptsRow
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
Definition: ExprBrowser.cpp:226
ExprBrowser::selectPath
void selectPath(const char *path)
Definition: ExprBrowser.cpp:295
ExprTreeFilterModel::ExprTreeFilterModel
ExprTreeFilterModel(QWidget *parent=0)
Definition: ExprBrowser.cpp:218
ExprEditor::setExpr
void setExpr(const std::string &expression, const bool apply=false)
Definition: ExprEditor.cpp:375
ExprTreeModel::parent
QModelIndex parent(const QModelIndex &index) const
Definition: ExprBrowser.cpp:151
ExprTreeModel::clear
void clear()
Definition: ExprBrowser.cpp:143
ExprTreeModel::root
ExprTreeItem * root
Definition: ExprBrowser.cpp:130
ExprBrowser::getSelectedPath
std::string getSelectedPath()
Definition: ExprBrowser.cpp:285
ExprBrowser::paths
QList< QString > paths
Definition: ExprBrowser.h:48
ExprTreeItem::ExprTreeItem
ExprTreeItem(ExprTreeItem *parent, const QString &label, const QString &path)
Definition: ExprBrowser.cpp:45
P3D_CONFIG_ENVVAR
#define P3D_CONFIG_ENVVAR
Definition: ExprBrowser.cpp:41
ExprTreeFilterModel::update
void update()
Definition: ExprBrowser.cpp:220
ExprBrowser::clearFilter
void clearFilter()
Definition: ExprBrowser.cpp:329
ExprEditor.h
ExprBrowser::addPath
void addPath(const std::string &name, const std::string &path)
Definition: ExprBrowser.cpp:274
ExprBrowser::getExpressionDirs
bool getExpressionDirs()
Definition: ExprBrowser.cpp:415
context
If a scalar is used in a vector context
Definition: userdoc.txt:436
ExprBrowser::clear
void clear()
Definition: ExprBrowser.cpp:319
ExprBrowser::exprFilter
QLineEdit * exprFilter
Definition: ExprBrowser.h:52
ExprTreeModel
Definition: ExprBrowser.cpp:129
ExprBrowser::addUserExpressionPath
void addUserExpressionPath(const std::string &context)
Definition: ExprBrowser.cpp:399
ExprBrowser::~ExprBrowser
~ExprBrowser()
Definition: ExprBrowser.cpp:240
ExprTreeItem::~ExprTreeItem
~ExprTreeItem()
Definition: ExprBrowser.cpp:48
ExprTreeModel::data
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const
Definition: ExprBrowser.cpp:189
ExprBrowser::editor
ExprEditor * editor
Definition: ExprBrowser.h:46
ExprBrowser::treeModel
ExprTreeModel * treeModel
Definition: ExprBrowser.h:49