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