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