123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379 |
- /*
- * Copyright (C) 2009 Emweb bvba
- *
- * See the LICENSE file for terms of use.
- */
- #include <iostream>
- #include <stdlib.h>
- #include <algorithm>
- #include <Wt/WApplication>
- #include <Wt/WContainerWidget>
- #include <Wt/WEnvironment>
- #include <Wt/WLineEdit>
- #include <Wt/WGridLayout>
- #include <Wt/WHBoxLayout>
- #include <Wt/WPushButton>
- #include <Wt/WTable>
- #include <Wt/WText>
- #include <Wt/WTreeView>
- #include <Wt/WVBoxLayout>
- #include <Wt/WViewWidget>
- #include <boost/filesystem/operations.hpp>
- #include <boost/filesystem/exception.hpp>
- #include <boost/filesystem/convenience.hpp>
- #include <boost/algorithm/string.hpp>
- #include "ExampleSourceViewer.h"
- #include "FileItem.h"
- using namespace Wt;
- namespace fs = boost::filesystem;
- // Same as p.filename() in latest boost::filesystem
- static std::string filename(const fs::path& p)
- {
- #if BOOST_FILESYSTEM_VERSION < 3
- return p.empty() ? std::string() : *--p.end();
- #else
- return p.empty() ? std::string() : (*--p.end()).string();
- #endif
- }
- // Same as p.stem() in latest boost::filesystem
- static std::string stem(const fs::path& p)
- {
- std::string fn = filename(p);
- std::size_t pos = fn.find('.');
- if (pos == std::string::npos)
- return fn;
- else
- return fn.substr(0, pos);
- }
- // Should be same as p.parent_path() in latest boost::filesystem
- // This is not entirely according to fs::path::parent_path() in 1.39.0
- fs::path parent_path(const fs::path& p)
- {
- std::string fn = filename(p);
- std::string path = p.string();
- return path.substr(0, path.length() - fn.length() - 1);
- }
- static bool comparePaths(const fs::path& p1, const fs::path& p2)
- {
- return filename(p1) > filename(p2);
- }
- ExampleSourceViewer::ExampleSourceViewer(const std::string& deployPath,
- const std::string& examplesRoot,
- const std::string& examplesType)
- : deployPath_(deployPath),
- examplesRoot_(examplesRoot),
- examplesType_(examplesType)
- {
- wApp->internalPathChanged().connect
- (this, &ExampleSourceViewer::handlePathChange);
- handlePathChange();
- }
- void ExampleSourceViewer::handlePathChange()
- {
- WApplication *app = wApp;
- if (app->internalPathMatches(deployPath_)) {
- std::string example = app->internalPathNextPart(deployPath_);
- if (example.find("..") != std::string::npos
- || example.find('/') != std::string::npos
- || example.find('\\') != std::string::npos) {
- app->setInternalPathValid(false);
- setExample("INVALID_DIR", "INVALID");
- } else
- setExample(examplesRoot_ + example, example);
- }
- }
- void ExampleSourceViewer::setExample(const std::string& exampleDir,
- const std::string& example)
- {
- clear();
- bool exists = false;
- try {
- exists = fs::exists(exampleDir);
- } catch (std::exception&) {
- }
- if (!exists) {
- WApplication::instance()->setInternalPathValid(false);
- addWidget(new WText("No such example: " + exampleDir));
- return;
- }
- model_ = new WStandardItemModel(0, 1, this);
- if (examplesType_ == "CPP") {
- cppTraverseDir(model_->invisibleRootItem(), exampleDir);
- } else if (examplesType_ == "JAVA") {
- javaTraverseDir(model_->invisibleRootItem(), exampleDir);
- }
- WApplication::instance()->setTitle(tr("srcview.title." + example));
- WText *title =
- new WText(tr("srcview.title." + examplesType_ + "." + example));
- title->setInternalPathEncoding(true);
- exampleView_ = new WTreeView();
- exampleView_->setHeaderHeight(0);
- exampleView_->resize(300, WLength::Auto);
- exampleView_->setSortingEnabled(false);
- exampleView_->setModel(model_);
- exampleView_->expandToDepth(1);
- exampleView_->setSelectionMode(SingleSelection);
- exampleView_->setAlternatingRowColors(false);
- exampleView_->selectionChanged().connect
- (this, &ExampleSourceViewer::showFile);
- sourceView_ = new SourceView(FileItem::FileNameRole,
- FileItem::ContentsRole,
- FileItem::FilePathRole);
- sourceView_->setStyleClass("source-view");
- /*
- * Expand path to first file, to show something in the source viewer
- */
- WStandardItem *w = model_->item(0);
- do {
- exampleView_->setExpanded(w->index(), true);
- if (w->rowCount() > 0)
- w = w->child(0);
- else {
- exampleView_->select(w->index(), Select);
- w = 0;
- }
- } while (w);
- WVBoxLayout *topLayout = new WVBoxLayout();
- topLayout->addWidget(title);
- WHBoxLayout *gitLayout = new WHBoxLayout();
- gitLayout->addWidget(exampleView_, 0);
- gitLayout->addWidget(sourceView_, 1);
- topLayout->addLayout(gitLayout, 1);
- gitLayout->setResizable(0);
- /*
- * FIXME, in plain HTML mode, we should set a minimum size to the source
- * view, and remove this in enableAjax() ?
- */
- // sourceView_->setHeight("100%");
- setLayout(topLayout);
- setStyleClass("maindiv");
- }
- /*
- * Return the companion implementation/header file for a C++ source file.
- */
- static fs::path getCompanion(const fs::path& path)
- {
- std::string ext = fs::extension(path);
- if (ext == ".h")
- return parent_path(path) / (stem(path) + ".C");
- else if (ext == ".C" || ext == ".cpp")
- return parent_path(path) / (stem(path) + ".h");
- else
- return fs::path();
- }
- void ExampleSourceViewer::cppTraverseDir(WStandardItem* parent,
- const fs::path& path)
- {
- static const char *supportedFiles[] = {
- ".C", ".cpp", ".h", ".css", ".xml", ".png", ".gif", ".csv", ".ico", 0
- };
- FileItem* dir = new FileItem("/icons/yellow-folder-open.png", filename(path),
- "");
- parent->appendRow(dir);
- parent = dir;
- try {
- std::set<fs::path> paths;
- fs::directory_iterator end_itr;
- for (fs::directory_iterator i(path); i != end_itr; ++i)
- paths.insert(*i);
- std::vector<FileItem*> classes, files;
- std::vector<fs::path> dirs;
- while (!paths.empty()) {
- fs::path p = *paths.begin();
- paths.erase(p);
- // skip symbolic links and other files
- if (fs::is_symlink(p))
- continue;
- // skip files with an extension we do not want to handle
- if (fs::is_regular(p)) {
- std::string ext = fs::extension(p);
- bool supported = false;
- for (const char **s = supportedFiles; *s != 0; ++s)
- if (*s == ext) {
- supported = true;
- break;
- }
-
- if (!supported)
- continue;
- }
- // see if we have one file of a class (.C, .h)
- fs::path companion = getCompanion(p);
- if (!companion.empty()) {
- std::set<fs::path>::iterator it_companion = paths.find(companion);
-
- if (it_companion != paths.end()) {
- std::string className = stem(p);
- escapeText(className);
- std::string label = "<i>class</i> " + className;
- FileItem *classItem =
- new FileItem("/icons/cppclass.png", label, std::string());
- classItem->setFlags(classItem->flags() | ItemIsXHTMLText);
- FileItem *header = new FileItem("/icons/document.png", filename(p),
- p.string());
- FileItem *cpp = new FileItem("/icons/document.png",
- filename(*it_companion),
- (*it_companion).string());
- classItem->appendRow(header);
- classItem->appendRow(cpp);
-
- classes.push_back(classItem);
- paths.erase(it_companion);
- } else {
- FileItem *file = new FileItem("/icons/document.png", filename(p),
- p.string());
- files.push_back(file);
- }
- } else if (fs::is_directory(p)) {
- dirs.push_back(p);
- } else {
- FileItem *file = new FileItem("/icons/document.png", filename(p),
- p.string());
- files.push_back(file);
- }
- }
- std::sort(dirs.begin(), dirs.end(), comparePaths);
- for (unsigned int i = 0; i < classes.size(); i++)
- parent->appendRow(classes[i]);
- for (unsigned int i = 0; i < files.size(); i++)
- parent->appendRow(files[i]);
- for (unsigned int i = 0; i < dirs.size(); i++)
- cppTraverseDir(parent, dirs[i]);
- } catch (fs::filesystem_error& e) {
- std::cerr << e.what() << std::endl;
- }
- }
- void ExampleSourceViewer::javaTraversePackages(WStandardItem *parent,
- const fs::path& srcPath,
- const std::string packageName)
- {
- fs::directory_iterator end_itr;
- FileItem *packageItem = 0;
- for (fs::directory_iterator i(srcPath); i != end_itr; ++i) {
- fs::path p = *i;
- if (fs::is_regular(p)) {
- if (!packageItem) {
- packageItem = new FileItem("/icons/package.png", packageName, "");
- parent->appendRow(packageItem);
- }
- FileItem *file = new FileItem("/icons/javaclass.png", filename(p),
- p.string());
- packageItem->appendRow(file);
- }
- }
- for (fs::directory_iterator i(srcPath); i != end_itr; ++i) {
- fs::path p = *i;
- if (fs::is_directory(p)) {
- std::string pn = packageName;
- if (!pn.empty())
- pn += ".";
- pn += filename(p);
- javaTraversePackages(parent, p, pn);
- }
- }
- }
- void ExampleSourceViewer::javaTraverseDir(WStandardItem* parent,
- const fs::path& path)
- {
- FileItem* dir = new FileItem("/icons/yellow-folder-open.png", filename(path),
- "");
- parent->appendRow(dir);
- parent = dir;
- std::vector<fs::path> files, dirs;
- fs::directory_iterator end_itr;
- for (fs::directory_iterator i(path); i != end_itr; ++i) {
- fs::path p = *i;
- if (fs::is_directory(p)) {
- if (filename(p) == "src") {
- FileItem* dir = new FileItem("/icons/package-folder-open.png",
- filename(p), "");
- parent->appendRow(dir);
- javaTraversePackages(dir, p, "");
- } else
- dirs.push_back(p);
- } else {
- files.push_back(p);
- }
- }
- std::sort(dirs.begin(), dirs.end(), comparePaths);
- std::sort(files.begin(), files.end(), comparePaths);
- for (unsigned int i = 0; i < dirs.size(); i++)
- javaTraverseDir(parent, dirs[i]);
- for (unsigned int i = 0; i < files.size(); i++) {
- FileItem *file = new FileItem("/icons/document.png", filename(files[i]),
- files[i].string());
- parent->appendRow(file);
- }
- }
- /*! \brief Displayed the currently selected file.
- */
- void ExampleSourceViewer::showFile() {
- if (exampleView_->selectedIndexes().empty())
- return;
- WModelIndex selected = *exampleView_->selectedIndexes().begin();
- // expand a folder when clicked
- if (exampleView_->model()->rowCount(selected) > 0
- && !exampleView_->isExpanded(selected))
- exampleView_->setExpanded(selected, true);
- // (for a file,) load data in source viewer
- sourceView_->setIndex(selected);
- }
|