Wt examples: /home/koen/project/wt/public-git/wt/examples/wt-homepage/ExampleSourceViewer.C Source File

Wt examples 3.3.0

- Main Page
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

/home/koen/project/wt/public-git/wt/examples/wt-homepage/ExampleSourceViewer.C
Go to the documentation of this file.

    00001 /*
    00002  * Copyright (C) 2009 Emweb bvba
    00003  *
    00004  * See the LICENSE file for terms of use.
    00005  */
    00006
    00007 #include <iostream>
    00008 #include <stdlib.h>
    00009 #include <algorithm>
    00010
    00011 #include <Wt/WApplication>
    00012 #include <Wt/WContainerWidget>
    00013 #include <Wt/WEnvironment>
    00014 #include <Wt/WLineEdit>
    00015 #include <Wt/WGridLayout>
    00016 #include <Wt/WHBoxLayout>
    00017 #include <Wt/WPushButton>
    00018 #include <Wt/WTable>
    00019 #include <Wt/WText>
    00020 #include <Wt/WTreeView>
    00021 #include <Wt/WVBoxLayout>
    00022 #include <Wt/WViewWidget>
    00023
    00024 #include <boost/filesystem/operations.hpp>
    00025 #include <boost/filesystem/exception.hpp>
    00026 #include <boost/filesystem/convenience.hpp>
    00027 #include <boost/algorithm/string.hpp>
    00028
    00029 #include "ExampleSourceViewer.h"
    00030 #include "FileItem.h"
    00031
    00032 using namespace Wt;
    00033 namespace fs = boost::filesystem;
    00034
    00035 // Same as p.filename() in latest boost::filesystem
    00036 static std::string filename(const fs::path& p)
    00037 {
    00038 #if BOOST_FILESYSTEM_VERSION < 3
    00039   return p.empty() ? std::string() : *--p.end();
    00040 #else
    00041   return p.empty() ? std::string() : (*--p.end()).string();
    00042 #endif
    00043 }
    00044
    00045 // Same as p.stem() in latest boost::filesystem
    00046 static std::string stem(const fs::path& p)
    00047 {
    00048   std::string fn = filename(p);
    00049   std::size_t pos = fn.find('.');
    00050   if (pos == std::string::npos)
    00051     return fn;
    00052   else
    00053     return fn.substr(0, pos);
    00054 }
    00055
    00056 // Should be same as p.parent_path() in latest boost::filesystem
    00057 // This is not entirely according to fs::path::parent_path() in 1.39.0
    00058 fs::path parent_path(const fs::path& p)
    00059 {
    00060   std::string fn = filename(p);
    00061   std::string path = p.string();
    00062
    00063   return path.substr(0, path.length() - fn.length() - 1);
    00064 }
    00065
    00066 static bool comparePaths(const fs::path& p1, const fs::path& p2)
    00067 {
    00068   return filename(p1) > filename(p2);
    00069 }
    00070
    00071 ExampleSourceViewer::ExampleSourceViewer(const std::string& deployPath,
    00072                                          const std::string& examplesRoot,
    00073                                          const std::string& examplesType)
    00074   : deployPath_(deployPath),
    00075     examplesRoot_(examplesRoot),
    00076     examplesType_(examplesType)
    00077 {
    00078   wApp->internalPathChanged().connect
    00079     (this, &ExampleSourceViewer::handlePathChange);
    00080
    00081   handlePathChange();
    00082 }
    00083
    00084 void ExampleSourceViewer::handlePathChange()
    00085 {
    00086   WApplication *app = wApp;
    00087
    00088   if (app->internalPathMatches(deployPath_)) {
    00089     std::string example = app->internalPathNextPart(deployPath_);
    00090
    00091     if (example.find("..") != std::string::npos
    00092         || example.find('/') != std::string::npos
    00093         || example.find('\\') != std::string::npos) {
    00094       app->setInternalPathValid(false);
    00095       setExample("INVALID_DIR", "INVALID");
    00096     } else
    00097       setExample(examplesRoot_ + example, example);
    00098   }
    00099 }
    00100
    00101 void ExampleSourceViewer::setExample(const std::string& exampleDir,
    00102                                      const std::string& example)
    00103 {
    00104   clear();
    00105
    00106   bool exists = false;
    00107   try {
    00108     exists = fs::exists(exampleDir);
    00109   } catch (std::exception&) {
    00110   }
    00111
    00112   if (!exists) {
    00113     WApplication::instance()->setInternalPathValid(false);
    00114     addWidget(new WText("No such example: " + exampleDir));
    00115     return;
    00116   }
    00117
    00118   model_ = new WStandardItemModel(0, 1, this);
    00119   if (examplesType_ == "CPP") {
    00120     cppTraverseDir(model_->invisibleRootItem(), exampleDir);
    00121   } else if (examplesType_ == "JAVA") {
    00122     javaTraverseDir(model_->invisibleRootItem(), exampleDir);
    00123   }
    00124
    00125   WApplication::instance()->setTitle(tr("srcview.title." + example));
    00126   WText *title =
    00127     new WText(tr("srcview.title." + examplesType_ + "." + example));
    00128   title->setInternalPathEncoding(true);
    00129
    00130   exampleView_ = new WTreeView();
    00131   exampleView_->setHeaderHeight(0);
    00132   exampleView_->resize(300, WLength::Auto);
    00133   exampleView_->setSortingEnabled(false);
    00134   exampleView_->setModel(model_);
    00135   exampleView_->expandToDepth(1);
    00136   exampleView_->setSelectionMode(SingleSelection);
    00137   exampleView_->setAlternatingRowColors(false);
    00138   exampleView_->selectionChanged().connect
    00139     (this, &ExampleSourceViewer::showFile);
    00140
    00141   sourceView_ = new SourceView(FileItem::FileNameRole,
    00142                                FileItem::ContentsRole,
    00143                                FileItem::FilePathRole);
    00144   sourceView_->setStyleClass("source-view");
    00145
    00146   /*
    00147    * Expand path to first file, to show something in the source viewer
    00148    */
    00149   WStandardItem *w = model_->item(0);
    00150   do {
    00151     exampleView_->setExpanded(w->index(), true);
    00152     if (w->rowCount() > 0)
    00153       w = w->child(0);
    00154     else {
    00155       exampleView_->select(w->index(), Select);
    00156       w = 0;
    00157     }
    00158   } while (w);
    00159
    00160   WVBoxLayout *topLayout = new WVBoxLayout();
    00161   topLayout->addWidget(title);
    00162
    00163   WHBoxLayout *gitLayout = new WHBoxLayout();
    00164   gitLayout->addWidget(exampleView_, 0);
    00165   gitLayout->addWidget(sourceView_, 1);
    00166   topLayout->addLayout(gitLayout, 1);
    00167   gitLayout->setResizable(0);
    00168
    00169   /*
    00170    * FIXME, in plain HTML mode, we should set a minimum size to the source
    00171    * view, and remove this in enableAjax() ?
    00172    */
    00173   // sourceView_->setHeight("100%");
    00174
    00175   setLayout(topLayout);
    00176   setStyleClass("maindiv");
    00177 }
    00178
    00179 /*
    00180  * Return the companion implementation/header file for a C++ source file.
    00181  */
    00182 static fs::path getCompanion(const fs::path& path)
    00183 {
    00184   std::string ext = fs::extension(path);
    00185
    00186   if (ext == ".h")
    00187     return parent_path(path) / (stem(path) + ".C");
    00188   else if (ext == ".C" || ext == ".cpp")
    00189     return parent_path(path) / (stem(path) + ".h");
    00190   else
    00191     return fs::path();
    00192 }
    00193
    00194 void ExampleSourceViewer::cppTraverseDir(WStandardItem* parent,
    00195                                          const fs::path& path)
    00196 {
    00197   static const char *supportedFiles[] = {
    00198     ".C", ".cpp", ".h", ".css", ".xml", ".png", ".gif", ".csv", ".ico", 0
    00199   };
    00200
    00201   FileItem* dir = new FileItem("/icons/yellow-folder-open.png", filename(path),
    00202                                "");
    00203   parent->appendRow(dir);
    00204   parent = dir;
    00205   try {
    00206     std::set<fs::path> paths;
    00207
    00208     fs::directory_iterator end_itr;
    00209     for (fs::directory_iterator i(path); i != end_itr; ++i)
    00210       paths.insert(*i);
    00211
    00212     std::vector<FileItem*> classes, files;
    00213     std::vector<fs::path> dirs;
    00214
    00215     while (!paths.empty()) {
    00216       fs::path p = *paths.begin();
    00217       paths.erase(p);
    00218
    00219       // skip symbolic links and other files
    00220       if (fs::is_symlink(p))
    00221         continue;
    00222
    00223       // skip files with an extension we do not want to handle
    00224       if (fs::is_regular(p)) {
    00225         std::string ext = fs::extension(p);
    00226         bool supported = false;
    00227         for (const char **s = supportedFiles; *s != 0; ++s)
    00228           if (*s == ext) {
    00229             supported = true;
    00230             break;
    00231           }
    00232
    00233         if (!supported)
    00234           continue;
    00235       }
    00236
    00237       // see if we have one file of a class (.C, .h)
    00238       fs::path companion = getCompanion(p);
    00239       if (!companion.empty()) {
    00240         std::set<fs::path>::iterator it_companion = paths.find(companion);
    00241
    00242           if (it_companion != paths.end()) {
    00243             std::string className = stem(p);
    00244             escapeText(className);
    00245             std::string label = "<i>class</i> " + className;
    00246
    00247             FileItem *classItem =
    00248               new FileItem("/icons/cppclass.png", label, std::string());
    00249             classItem->setFlags(classItem->flags() | ItemIsXHTMLText);
    00250
    00251             FileItem *header = new FileItem("/icons/document.png", filename(p),
    00252                                             p.string());
    00253             FileItem *cpp = new FileItem("/icons/document.png",
    00254                                          filename(*it_companion),
    00255                                          (*it_companion).string());
    00256             classItem->appendRow(header);
    00257             classItem->appendRow(cpp);
    00258
    00259             classes.push_back(classItem);
    00260             paths.erase(it_companion);
    00261           } else {
    00262             FileItem *file = new FileItem("/icons/document.png", filename(p),
    00263                                           p.string());
    00264             files.push_back(file);
    00265           }
    00266       } else if (fs::is_directory(p)) {
    00267         dirs.push_back(p);
    00268       } else {
    00269         FileItem *file = new FileItem("/icons/document.png", filename(p),
    00270                                       p.string());
    00271         files.push_back(file);
    00272       }
    00273     }
    00274
    00275     std::sort(dirs.begin(), dirs.end(), comparePaths);
    00276
    00277     for (unsigned int i = 0; i < classes.size(); i++)
    00278       parent->appendRow(classes[i]);
    00279
    00280     for (unsigned int i = 0; i < files.size(); i++)
    00281       parent->appendRow(files[i]);
    00282
    00283     for (unsigned int i = 0; i < dirs.size(); i++)
    00284       cppTraverseDir(parent, dirs[i]);
    00285   } catch (fs::filesystem_error& e) {
    00286     std::cerr << e.what() << std::endl;
    00287   }
    00288 }
    00289
    00290 void ExampleSourceViewer::javaTraversePackages(WStandardItem *parent,
    00291                                                const fs::path& srcPath,
    00292                                                const std::string packageName)
    00293 {
    00294   fs::directory_iterator end_itr;
    00295
    00296   FileItem *packageItem = 0;
    00297   for (fs::directory_iterator i(srcPath); i != end_itr; ++i) {
    00298     fs::path p = *i;
    00299     if (fs::is_regular(p)) {
    00300       if (!packageItem) {
    00301         packageItem = new FileItem("/icons/package.png", packageName, "");
    00302         parent->appendRow(packageItem);
    00303       }
    00304
    00305       FileItem *file = new FileItem("/icons/javaclass.png", filename(p),
    00306                                     p.string());
    00307       packageItem->appendRow(file);
    00308     }
    00309   }
    00310
    00311   for (fs::directory_iterator i(srcPath); i != end_itr; ++i) {
    00312     fs::path p = *i;
    00313     if (fs::is_directory(p)) {
    00314       std::string pn = packageName;
    00315       if (!pn.empty())
    00316         pn += ".";
    00317       pn += filename(p);
    00318
    00319       javaTraversePackages(parent, p, pn);
    00320     }
    00321   }
    00322 }
    00323
    00324 void ExampleSourceViewer::javaTraverseDir(WStandardItem* parent,
    00325                                           const fs::path& path)
    00326 {
    00327   FileItem* dir = new FileItem("/icons/yellow-folder-open.png", filename(path),
    00328                                "");
    00329   parent->appendRow(dir);
    00330   parent = dir;
    00331
    00332   std::vector<fs::path> files, dirs;
    00333
    00334   fs::directory_iterator end_itr;
    00335   for (fs::directory_iterator i(path); i != end_itr; ++i) {
    00336     fs::path p = *i;
    00337     if (fs::is_directory(p)) {
    00338       if (filename(p) == "src") {
    00339         FileItem* dir = new FileItem("/icons/package-folder-open.png",
    00340                                      filename(p), "");
    00341         parent->appendRow(dir);
    00342         javaTraversePackages(dir, p, "");
    00343       } else
    00344         dirs.push_back(p);
    00345     } else {
    00346       files.push_back(p);
    00347     }
    00348   }
    00349
    00350   std::sort(dirs.begin(), dirs.end(), comparePaths);
    00351   std::sort(files.begin(), files.end(), comparePaths);
    00352
    00353   for (unsigned int i = 0; i < dirs.size(); i++)
    00354     javaTraverseDir(parent, dirs[i]);
    00355
    00356   for (unsigned int i = 0; i < files.size(); i++) {
    00357     FileItem *file = new FileItem("/icons/document.png", filename(files[i]),
    00358                                   files[i].string());
    00359     parent->appendRow(file);
    00360   }
    00361 }
    00362
    00365 void ExampleSourceViewer::showFile() {
    00366   if (exampleView_->selectedIndexes().empty())
    00367     return;
    00368
    00369   WModelIndex selected = *exampleView_->selectedIndexes().begin();
    00370
    00371   // expand a folder when clicked
    00372   if (exampleView_->model()->rowCount(selected) > 0
    00373       && !exampleView_->isExpanded(selected))
    00374     exampleView_->setExpanded(selected, true);
    00375
    00376   // (for a file,) load data in source viewer
    00377   sourceView_->setIndex(selected);
    00378 }