00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include <QtGui/QTreeWidget>
00015 #include <QtGui/QTreeWidgetItem>
00016 #include <QtGui/QVBoxLayout>
00017 #include <QtGui/QTabWidget>
00018 #include <QtGui/QHeaderView>
00019 #include <QtGui/QLabel>
00020 #include <QtGui/QTextBrowser>
00021 #include <QtGui/QPushButton>
00022 #include <QtGui/QSpacerItem>
00023 #include <QtGui/QSizePolicy>
00024 #include <QtGui/QSortFilterProxyModel>
00025 #include <QtCore/QDir>
00026 #include <QtCore/QFileInfo>
00027 #include <QtGui/QFileDialog>
00028 #include <QtGui/QMessageBox>
00029 #include <cassert>
00030 #include "SeExprEditor.h"
00031 #include "SeExprEdBrowser.h"
00032
00033 #define P3D_CONFIG_ENVVAR "P3D_CONFIG_PATH"
00034
00035
00036 class SeExprEdTreeItem
00037 {
00038 public:
00039 SeExprEdTreeItem(SeExprEdTreeItem* parent,const QString& label,const QString& path)
00040 :row(-1),parent(parent),label(label),path(path),populated(parent==0)
00041 {}
00042
00043 ~SeExprEdTreeItem()
00044 {
00045 for(unsigned int i=0;i<children.size();i++)
00046 delete children[i];
00047 }
00048
00049 SeExprEdTreeItem* find(QString path)
00050 {
00051 if(this->path==path) return this;
00052 else{
00053 populate();
00054 for(unsigned int i=0;i<children.size();i++){
00055 SeExprEdTreeItem* ret=children[i]->find(path);
00056 if(ret) return ret;
00057 }
00058 }
00059 return 0;
00060 }
00061
00062 void clear()
00063 {
00064 for(unsigned int i=0;i<children.size();i++) {
00065 delete children[i];
00066 }
00067 children.clear();
00068 }
00069
00070 void populate()
00071 {
00072 if(populated) return;
00073 populated=true;
00074 QFileInfo info(path);
00075 if(info.isDir()){
00076 QFileInfoList infos=QDir(path).entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
00077
00078
00079 for(QList<QFileInfo>::ConstIterator it=infos.constBegin();it!=infos.constEnd();++it){
00080 const QFileInfo* fi=&*it;
00081 if(fi->isDir() || fi->fileName().endsWith(".se")){
00082 addChild(new SeExprEdTreeItem(this,fi->fileName(),fi->filePath()));
00083 }
00084 }
00085 }
00086 }
00087
00088 void addChild(SeExprEdTreeItem* child)
00089 {
00090 child->row=children.size();
00091 children.push_back(child);
00092 }
00093
00094 SeExprEdTreeItem* getChild(const int row)
00095 {
00096 populate();
00097 if(row<0 || row>(int)children.size()){
00098 assert(false);
00099 }
00100 return children[row];
00101 }
00102
00103 int getChildCount()
00104 {
00105 populate();
00106 return children.size();
00107 }
00108
00109 void regen()
00110 {
00111 std::vector<QString> labels,paths;
00112 for(unsigned int i=0;i<children.size();i++){
00113 labels.push_back(children[i]->label);
00114 paths.push_back(children[i]->path);
00115 delete children[i];
00116 }
00117 children.clear();
00118
00119 for(unsigned int i=0;i<labels.size();i++)
00120 addChild(new SeExprEdTreeItem(this,labels[i],paths[i]));
00121
00122 }
00123
00124 int row;
00125 SeExprEdTreeItem* parent;
00126 QString label;
00127 QString path;
00128 private:
00129 std::vector<SeExprEdTreeItem*> children;
00130 bool populated;
00131 };
00132
00133 class SeExprEdTreeModel:public QAbstractItemModel
00134 {
00135 SeExprEdTreeItem* root;
00136 public:
00137 SeExprEdTreeModel()
00138 :root(new SeExprEdTreeItem(0,"",""))
00139 {}
00140
00141 ~SeExprEdTreeModel()
00142 {
00143 delete root;
00144 }
00145
00146 void update()
00147 {
00148 reset();
00149 }
00150
00151 void clear()
00152 {
00153 root->clear();
00154 update();
00155 }
00156
00157 void addPath(const char* label,const char* path)
00158 {
00159 root->addChild(new SeExprEdTreeItem(root,label,path));
00160 }
00161
00162 QModelIndex parent(const QModelIndex& index) const
00163 {
00164 if(!index.isValid()) return QModelIndex();
00165 SeExprEdTreeItem* item=(SeExprEdTreeItem*)(index.internalPointer());
00166 SeExprEdTreeItem* parentItem=item->parent;
00167 if(parentItem==root) return QModelIndex();
00168 else return createIndex(parentItem->row,0,parentItem);
00169 }
00170
00171 QModelIndex index(int row,int column,const QModelIndex& parent=QModelIndex()) const
00172 {
00173 if(!hasIndex(row,column,parent))
00174 return QModelIndex();
00175 else if(!parent.isValid()) return createIndex(row,column,root->getChild(row));
00176 else{
00177 SeExprEdTreeItem* item=(SeExprEdTreeItem*)(parent.internalPointer());
00178 return createIndex(row,column,item->getChild(row));
00179 }
00180 }
00181
00182 int columnCount(const QModelIndex& parent) const
00183 {Q_UNUSED(parent); return 1;}
00184
00185 int rowCount(const QModelIndex& parent=QModelIndex()) const
00186 {
00187 if(!parent.isValid()) return root->getChildCount();
00188 else{
00189 SeExprEdTreeItem* item=(SeExprEdTreeItem*)(parent.internalPointer());
00190 if(!item) return root->getChildCount();
00191 else return item->getChildCount();
00192 }
00193 }
00194
00195 QVariant data(const QModelIndex& index,int role=Qt::DisplayRole) const
00196 {
00197 if(!index.isValid()) return QVariant();
00198 if(role!=Qt::DisplayRole) return QVariant();
00199 SeExprEdTreeItem* item=(SeExprEdTreeItem*)(index.internalPointer());
00200 if(!item) return QVariant();
00201 else return QVariant(item->label);
00202 }
00203
00204 QModelIndex find(QString path)
00205 {
00206 SeExprEdTreeItem* item=root->find(path);
00207 if(!item) {
00208 root->regen();
00209 reset();
00210 item=root->find(path);
00211 }
00212 if(item){
00213 std::cerr<<"found it "<<std::endl;
00214 return createIndex(item->row,0,item);
00215 }
00216
00217 return QModelIndex();
00218 }
00219
00220 };
00221
00222 class SeExprEdTreeFilterModel:public QSortFilterProxyModel
00223 {
00224 public:
00225 SeExprEdTreeFilterModel(QWidget* parent=0)
00226 :QSortFilterProxyModel(parent)
00227 {}
00228
00229 void update()
00230 {
00231 reset();
00232 }
00233
00234 bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const
00235 {
00236 if(sourceParent.isValid() &&
00237 sourceModel()->data(sourceParent).toString().contains(filterRegExp())) return true;
00238 QString data=sourceModel()->data(sourceModel()->index(sourceRow,0,sourceParent)).toString();
00239 bool keep=data.contains(filterRegExp());
00240
00241 QModelIndex subIndex=sourceModel()->index(sourceRow,0,sourceParent);
00242 if(subIndex.isValid()){
00243 for(int i=0;i<sourceModel()->rowCount(subIndex);++i)
00244 keep = keep || filterAcceptsRow(i, subIndex);
00245 }
00246 return keep;
00247 }
00248
00249 };
00250
00251 SeExprEdBrowser::~SeExprEdBrowser()
00252 {
00253 delete treeModel;
00254 }
00255
00256 SeExprEdBrowser::SeExprEdBrowser(QWidget* parent, SeExprEditor* editor)
00257 :QWidget(parent),editor(editor),
00258 _context(""),
00259 _searchPath("")
00260 {
00261 QVBoxLayout* rootLayout = new QVBoxLayout;
00262 rootLayout->setMargin(0);
00263 this->setLayout(rootLayout);
00264
00265 QHBoxLayout* searchAndClearLayout=new QHBoxLayout();
00266 exprFilter=new QLineEdit();
00267 connect(exprFilter,SIGNAL(textChanged(const QString&)),SLOT(filterChanged(const QString&)));
00268 searchAndClearLayout->addWidget(exprFilter,2);
00269 QPushButton* clearFilterButton=new QPushButton("X");
00270 clearFilterButton->setFixedWidth(24);
00271 searchAndClearLayout->addWidget(clearFilterButton,1);
00272 rootLayout->addLayout(searchAndClearLayout);
00273 connect(clearFilterButton,SIGNAL(clicked()),SLOT(clearFilter()));
00274
00275 treeModel=new SeExprEdTreeModel();
00276 proxyModel=new SeExprEdTreeFilterModel(this);
00277 proxyModel->setSourceModel(treeModel);
00278
00279 treeNew=new QTreeView;
00280 treeNew->setModel(proxyModel);
00281 treeNew->hideColumn(1);
00282 treeNew->setHeaderHidden(true);
00283 rootLayout->addWidget(treeNew);
00284
00285 treeNew->setSelectionMode(QAbstractItemView::SingleSelection);
00286 connect(treeNew->selectionModel(),SIGNAL(currentChanged(const QModelIndex&,const QModelIndex&)),SLOT(handleSelection(const QModelIndex&,const QModelIndex&)));
00287 }
00288
00289 void SeExprEdBrowser::addPath(const std::string& name,const std::string& path)
00290 {
00291 labels.append(QString::fromStdString(name));
00292 paths.append(QString::fromStdString(path));
00293 treeModel->addPath(name.c_str(),path.c_str());
00294 }
00295
00296 void SeExprEdBrowser::setSearchPath(const QString& context, const QString& path)
00297 {
00298 _context = context.toStdString();
00299 _searchPath = path.toStdString();
00300 }
00301
00302 std::string SeExprEdBrowser::getSelectedPath()
00303 {
00304 QModelIndex sel=treeNew->currentIndex();
00305 if(sel.isValid()){
00306 QModelIndex realCurrent=proxyModel->mapToSource(sel);
00307 SeExprEdTreeItem* item=(SeExprEdTreeItem*)realCurrent.internalPointer();
00308 return item->path.toStdString();
00309 }
00310 return std::string("");
00311 }
00312
00313 void SeExprEdBrowser::selectPath(const char * path)
00314 {
00315 QModelIndex index=treeModel->find(path);
00316 treeNew->setCurrentIndex(proxyModel->mapFromSource(index));
00317 }
00318
00319 void SeExprEdBrowser::update()
00320 {
00321 treeModel->update();
00322 proxyModel->update();
00323 }
00324
00325 void SeExprEdBrowser::handleSelection(const QModelIndex& current,const QModelIndex& previous)
00326 {
00327 Q_UNUSED(previous)
00328 if(current.isValid()){
00329 QModelIndex realCurrent=proxyModel->mapToSource(current);
00330 SeExprEdTreeItem* item=(SeExprEdTreeItem*)realCurrent.internalPointer();
00331 QString path=item->path;
00332 if(path.endsWith(".se")){
00333 std::ifstream file(path.toStdString().c_str());
00334 std::string fileContents((std::istreambuf_iterator<char>(file)),std::istreambuf_iterator<char>());
00335 editor->setExpr(fileContents,true);
00336 }
00337 }
00338 }
00339
00340 void SeExprEdBrowser::clear()
00341 {
00342 labels.clear();
00343 paths.clear();
00344 clearSelection();
00345
00346 treeModel->clear();
00347 }
00348
00349
00350 void SeExprEdBrowser::clearSelection()
00351 {
00352 treeNew->clearSelection();
00353 }
00354
00355 void SeExprEdBrowser::clearFilter()
00356 {
00357 exprFilter->clear();
00358 }
00359
00360 void SeExprEdBrowser::filterChanged(const QString& str)
00361 {
00362 proxyModel->setFilterRegExp(QRegExp(str));
00363 proxyModel->setFilterKeyColumn(0);
00364 if(str!=""){
00365 treeNew->expandAll();
00366 }else{
00367 treeNew->collapseAll();
00368 }
00369 }
00370
00371 void SeExprEdBrowser::saveExpressionAs()
00372 {
00373 QString path = QFileDialog::getSaveFileName(
00374 this, "Save Expression", QString::fromStdString(_userExprDir),
00375 "*.se");
00376
00377 if (path.length() > 0) {
00378 std::ofstream file(path.toStdString().c_str());
00379 if (!file) {
00380 QString msg = QString("Could not open file %1 for writing").arg(path);
00381 QMessageBox::warning(this, "Error",
00382 QString("<font face=fixed>%1</font>")
00383 .arg(msg));
00384 return;
00385 }
00386 file << editor->getExpr();
00387 file.close();
00388
00389 update();
00390 selectPath(path.toStdString().c_str());
00391 }
00392 }
00393
00394 void SeExprEdBrowser::saveLocalExpressionAs()
00395 {
00396 QString path = QFileDialog::getSaveFileName(
00397 this, "Save Expression", QString::fromStdString(_localExprDir),
00398 "*.se");
00399
00400 if (path.length() > 0) {
00401 std::ofstream file(path.toStdString().c_str());
00402 if (!file) {
00403 QString msg = QString("Could not open file %1 for writing").arg(path);
00404 QMessageBox::warning(this, "Error",
00405 QString("<font face=fixed>%1</font>")
00406 .arg(msg));
00407 return;
00408 }
00409 file << editor->getExpr();
00410 file.close();
00411
00412 update();
00413 selectPath(path.toStdString().c_str());
00414 }
00415 }
00416
00417
00418 void SeExprEdBrowser::saveExpression()
00419 {
00420 std::string path = getSelectedPath();
00421 if (path.length() == 0) {
00422 saveExpressionAs();
00423 return;
00424 }
00425 std::ofstream file(path.c_str());
00426 if (!file) {
00427 QString msg = QString("Could not open file %1 for writing. Is it read-only?").arg(QString::fromStdString(path));
00428 QMessageBox::warning(this, "Error",
00429 QString("<font face=fixed>%1</font>")
00430 .arg(msg));
00431 return;
00432 }
00433 file << editor->getExpr();
00434 file.close();
00435 }
00436
00437 void SeExprEdBrowser::expandAll()
00438 {
00439 treeNew->expandAll();
00440 }
00441
00442
00443
00444
00445
00446
00447
00448 bool SeExprEdBrowser::getExpressionDirs()
00449 {
00450 const char *env;
00451 bool enableLocal = false;
00452
00453
00454 if (_searchPath.length() > 0)
00455 env = _searchPath.c_str();
00456 else
00457 env = getenv(P3D_CONFIG_ENVVAR);
00458
00459 if (!env)
00460 return enableLocal;
00461
00462 std::string context;
00463 if (_context.length() > 0) {
00464 context = _context;
00465 } else {
00466 context = "paint3d";
00467 }
00468
00469 clear();
00470
00471 std::string configFile=std::string(env)+"/config.txt";
00472 std::ifstream file(configFile.c_str());
00473 if(file){
00474
00475 std::string key;
00476 while(file){
00477 file>>key;
00478
00479 if(key[0]=='#'){
00480 char buffer[1024];
00481 file.getline(buffer,1024);
00482 } else {
00483 if (key=="ExpressionDir"){
00484 std::string label,path;
00485 file>>label;
00486 file>>path;
00487 if(QDir(QString(path.c_str())).exists())
00488 addPath(label,path);
00489 } else if (key=="ExpressionSubDir"){
00490 std::string path;
00491 file>>path;
00492 _localExprDir=path;
00493 if(QDir(QString(path.c_str())).exists()){
00494 addPath("Local",_localExprDir);
00495 enableLocal=true;
00496 }
00497
00498
00499
00500 } else if (key == "GlobalRepo") {
00501 std::string path;
00502 file>>path;
00503 path += "/expressions/";
00504 if(QDir(QString(path.c_str())).exists())
00505 addPath("Global", path);
00506 } else if (key == "LocalRepo") {
00507 std::string path;
00508 file>>path;
00509 path += "/expressions/";
00510 _localExprDir=path;
00511 if(QDir(QString(path.c_str())).exists()){
00512 addPath("Local",_localExprDir);
00513 enableLocal=true;
00514 }
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539
00540
00541
00542
00543 } else{
00544 char buffer[1024];
00545 file.getline(buffer,1024);
00546 }
00547 }
00548 }
00549 }
00550
00551 char* homepath = getenv("HOME");
00552 if(homepath){
00553 std::string path= std::string(homepath) + "/" + context + "/expressions/";
00554 if(QDir(QString(path.c_str())).exists()){
00555 _userExprDir=path;
00556 addPath("My Expressions",path);
00557 }
00558 }
00559 update();
00560 return enableLocal;
00561 }
00562