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 (SLOT(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& e) {
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, 300);
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 (SLOT(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
00161 setLayout(topLayout);
00162 setStyleClass("maindiv");
00163 }
00164
00165
00166
00167
00168 static fs::path getCompanion(const fs::path& path)
00169 {
00170 std::string ext = fs::extension(path);
00171
00172 if (ext == ".h")
00173 return parent_path(path) / (stem(path) + ".C");
00174 else if (ext == ".C" || ext == ".cpp")
00175 return parent_path(path) / (stem(path) + ".h");
00176 else
00177 return fs::path();
00178 }
00179
00180 void ExampleSourceViewer::cppTraverseDir(WStandardItem* parent,
00181 const fs::path& path)
00182 {
00183 static const char *supportedFiles[] = {
00184 ".C", ".cpp", ".h", ".css", ".xml", ".png", ".gif", ".csv", ".ico", 0
00185 };
00186
00187 FileItem* dir = new FileItem("icons/yellow-folder-open.png", filename(path),
00188 "");
00189 parent->appendRow(dir);
00190 parent = dir;
00191 try {
00192 std::set<fs::path> paths;
00193
00194 fs::directory_iterator end_itr;
00195 for (fs::directory_iterator i(path); i != end_itr; ++i)
00196 paths.insert(*i);
00197
00198 std::vector<FileItem*> classes, files;
00199 std::vector<fs::path> dirs;
00200
00201 while (!paths.empty()) {
00202 fs::path p = *paths.begin();
00203 paths.erase(p);
00204
00205
00206 if (fs::is_symlink(p))
00207 continue;
00208
00209
00210 if (fs::is_regular(p)) {
00211 std::string ext = fs::extension(p);
00212 bool supported = false;
00213 for (const char **s = supportedFiles; *s != 0; ++s)
00214 if (*s == ext) {
00215 supported = true;
00216 break;
00217 }
00218
00219 if (!supported)
00220 continue;
00221 }
00222
00223
00224 fs::path companion = getCompanion(p);
00225 if (!companion.empty()) {
00226 std::set<fs::path>::iterator it_companion = paths.find(companion);
00227
00228 if (it_companion != paths.end()) {
00229 std::string className = stem(p);
00230 escapeText(className);
00231 std::string label = "<i>class</i> " + className;
00232
00233 FileItem *classItem =
00234 new FileItem("icons/cppclass.png", label, std::string());
00235 classItem->setFlags(classItem->flags() | ItemIsXHTMLText);
00236
00237 FileItem *header = new FileItem("icons/document.png", filename(p),
00238 p.string());
00239 FileItem *cpp = new FileItem("icons/document.png",
00240 filename(*it_companion),
00241 (*it_companion).string());
00242 classItem->appendRow(header);
00243 classItem->appendRow(cpp);
00244
00245 classes.push_back(classItem);
00246 paths.erase(it_companion);
00247 } else {
00248 FileItem *file = new FileItem("icons/document.png", filename(p),
00249 p.string());
00250 files.push_back(file);
00251 }
00252 } else if (fs::is_directory(p)) {
00253 dirs.push_back(p);
00254 } else {
00255 FileItem *file = new FileItem("icons/document.png", filename(p),
00256 p.string());
00257 files.push_back(file);
00258 }
00259 }
00260
00261 std::sort(dirs.begin(), dirs.end(), comparePaths);
00262
00263 for (unsigned int i = 0; i < classes.size(); i++)
00264 parent->appendRow(classes[i]);
00265
00266 for (unsigned int i = 0; i < files.size(); i++)
00267 parent->appendRow(files[i]);
00268
00269 for (unsigned int i = 0; i < dirs.size(); i++)
00270 cppTraverseDir(parent, dirs[i]);
00271 } catch (fs::filesystem_error& e) {
00272 std::cerr << e.what() << std::endl;
00273 }
00274 }
00275
00276 void ExampleSourceViewer::javaTraversePackages(WStandardItem *parent,
00277 const fs::path& srcPath,
00278 const std::string packageName)
00279 {
00280 fs::directory_iterator end_itr;
00281
00282 FileItem *packageItem = 0;
00283 for (fs::directory_iterator i(srcPath); i != end_itr; ++i) {
00284 fs::path p = *i;
00285 if (fs::is_regular(p)) {
00286 if (!packageItem) {
00287 packageItem = new FileItem("icons/package.png", packageName, "");
00288 parent->appendRow(packageItem);
00289 }
00290
00291 FileItem *file = new FileItem("icons/javaclass.png", filename(p),
00292 p.string());
00293 packageItem->appendRow(file);
00294 }
00295 }
00296
00297 for (fs::directory_iterator i(srcPath); i != end_itr; ++i) {
00298 fs::path p = *i;
00299 if (fs::is_directory(p)) {
00300 std::string pn = packageName;
00301 if (!pn.empty())
00302 pn += ".";
00303 pn += filename(p);
00304
00305 javaTraversePackages(parent, p, pn);
00306 }
00307 }
00308 }
00309
00310 void ExampleSourceViewer::javaTraverseDir(WStandardItem* parent,
00311 const fs::path& path)
00312 {
00313 FileItem* dir = new FileItem("icons/yellow-folder-open.png", filename(path),
00314 "");
00315 parent->appendRow(dir);
00316 parent = dir;
00317
00318 std::vector<fs::path> files, dirs;
00319
00320 fs::directory_iterator end_itr;
00321 for (fs::directory_iterator i(path); i != end_itr; ++i) {
00322 fs::path p = *i;
00323 if (fs::is_directory(p)) {
00324 if (filename(p) == "src") {
00325 FileItem* dir = new FileItem("icons/package-folder-open.png",
00326 filename(p), "");
00327 parent->appendRow(dir);
00328 javaTraversePackages(dir, p, "");
00329 } else
00330 dirs.push_back(p);
00331 } else {
00332 files.push_back(p);
00333 }
00334 }
00335
00336 std::sort(dirs.begin(), dirs.end(), comparePaths);
00337 std::sort(files.begin(), files.end(), comparePaths);
00338
00339 for (unsigned int i = 0; i < dirs.size(); i++)
00340 javaTraverseDir(parent, dirs[i]);
00341
00342 for (unsigned int i = 0; i < files.size(); i++) {
00343 FileItem *file = new FileItem("icons/document.png", filename(files[i]),
00344 files[i].string());
00345 parent->appendRow(file);
00346 }
00347 }
00348
00351 void ExampleSourceViewer::showFile() {
00352 if (exampleView_->selectedIndexes().empty())
00353 return;
00354
00355 WModelIndex selected = *exampleView_->selectedIndexes().begin();
00356
00357
00358 if (exampleView_->model()->rowCount(selected) > 0
00359 && !exampleView_->isExpanded(selected))
00360 exampleView_->setExpanded(selected, true);
00361
00362
00363 sourceView_->setIndex(selected);
00364 }