Source code of the Wt homepage example

Browse below the source code for Wt's Homepage example.

  • wt-homepage
    • class ExampleSourceViewer
      • ExampleSourceViewer.C
        • ExampleSourceViewer.h
        • class FileItem
          • class Home
            • class JWtHome
              • class SourceView
                • class WtHome
                  • jwt-home.xml
                    • main.C
                      • wt-home.xml
                        • wt-home_cn.xml
                          • wt-home_ru.xml
                            • icons
                              • css
                              /*
                              * Copyright (C) 2009 Emweb bv, Herent, Belgium
                              *
                              * See the LICENSE file for terms of use.
                              */

                              #include <iostream>
                              #include <stdlib.h>
                              #include <algorithm>

                              #include <Wt/WApplication.h>
                              #include <Wt/WContainerWidget.h>
                              #include <Wt/WEnvironment.h>
                              #include <Wt/WLineEdit.h>
                              #include <Wt/WGridLayout.h>
                              #include <Wt/WHBoxLayout.h>
                              #include <Wt/WPushButton.h>
                              #include <Wt/WTable.h>
                              #include <Wt/WText.h>
                              #include <Wt/WTreeView.h>
                              #include <Wt/WVBoxLayout.h>
                              #include <Wt/WViewWidget.h>

                              #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"

                              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(std::make_unique<WText>("No such example: " + exampleDir));
                              return;
                              }

                              model_ = std::make_shared<WStandardItemModel>(0, 1);
                              if (examplesType_ == "CPP") {
                              cppTraverseDir(model_->invisibleRootItem(), exampleDir);
                              } else if (examplesType_ == "JAVA") {
                              javaTraverseDir(model_->invisibleRootItem(), exampleDir);
                              }

                              WApplication::instance()->setTitle(tr("srcview.title." + example));
                              std::unique_ptr<WText> title(std::make_unique<WText>(
                              tr("srcview.title." + examplesType_ + "." + example)));
                              title->setInternalPathEncoding(true);

                              auto exampleView = std::make_unique<WTreeView>();
                              exampleView_ = exampleView.get();
                              exampleView_->setHeaderHeight(0);
                              exampleView_->resize(300, WLength::Auto);
                              exampleView_->setSortingEnabled(false);
                              exampleView_->setModel(model_);
                              exampleView_->expandToDepth(1);
                              exampleView_->setSelectionMode(SelectionMode::Single);
                              exampleView_->setAlternatingRowColors(false);
                              exampleView_->selectionChanged().connect
                              (this, &ExampleSourceViewer::showFile);

                              auto sourceView =
                              std::make_unique<SourceView>(FileItem::FileNameRole,
                              FileItem::ContentsRole,
                              FileItem::FilePathRole);
                              sourceView_ = sourceView.get();
                              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());
                              w = 0;
                              }
                              } while (w);

                              auto topLayout = std::make_unique<WVBoxLayout>();
                              topLayout->addWidget(std::move(title));

                              auto gitLayout = std::make_unique<WHBoxLayout>();
                              WHBoxLayout *g = gitLayout.get();
                              gitLayout->addWidget(std::move(exampleView), 0);
                              gitLayout->addWidget(std::move(sourceView), 1);
                              topLayout->addLayout(std::move(gitLayout), 1);
                              g->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(std::move(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
                              };

                              auto dir = std::make_unique<FileItem>("/icons/yellow-folder-open.png",
                              filename(path),
                              "");
                              FileItem *dirPtr = dir.get();
                              parent->appendRow(std::move(dir));
                              parent = dirPtr;
                              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<std::unique_ptr<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;

                              std::unique_ptr<FileItem> classItem =
                              std::make_unique<FileItem>("/icons/cppclass.png", label, std::string());
                              classItem->setFlags(classItem->flags() | ItemFlag::XHTMLText);

                              auto header
                              = std::make_unique<FileItem>("/icons/document.png", filename(p),
                              p.string());
                              auto cpp
                              = std::make_unique<FileItem>("/icons/document.png",
                              filename(*it_companion),
                              (*it_companion).string());
                              classItem->appendRow(std::move(header));
                              classItem->appendRow(std::move(cpp));

                              classes.push_back(std::move(classItem));
                              paths.erase(it_companion);
                              } else {
                              auto file
                              = std::make_unique<FileItem>("/icons/document.png", filename(p),
                              p.string());
                              files.push_back(std::move(file));
                              }
                              } else if (fs::is_directory(p)) {
                              dirs.push_back(p);
                              } else {
                              auto file
                              = std::make_unique<FileItem>("/icons/document.png", filename(p),
                              p.string());
                              files.push_back(std::move(file));
                              }
                              }

                              std::sort(dirs.begin(), dirs.end(), comparePaths);

                              for (unsigned int i = 0; i < classes.size(); i++)
                              parent->appendRow(std::move(classes[i]));

                              for (unsigned int i = 0; i < files.size(); i++)
                              parent->appendRow(std::move(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 = nullptr;
                              for (fs::directory_iterator i(srcPath); i != end_itr; ++i) {
                              fs::path p = *i;
                              if (fs::is_regular(p)) {
                              if (!packageItem) {
                              auto item = std::make_unique<FileItem>("/icons/package.png", packageName, "");
                              packageItem = item.get();
                              parent->appendRow(std::move(item));
                              }

                              auto file
                              = std::make_unique<FileItem>("/icons/javaclass.png", filename(p),
                              p.string());
                              packageItem->appendRow(std::move(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)
                              {
                              auto dir
                              = std::make_unique<FileItem>("/icons/yellow-folder-open.png",
                              filename(path),"");
                              FileItem *dirPtr = dir.get();
                              parent->appendRow(std::move(dir));
                              parent = dirPtr;

                              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") {
                              auto dir
                              = std::make_unique<FileItem>("/icons/package-folder-open.png",
                              filename(p), "");
                              FileItem *dirPtr = dir.get();
                              parent->appendRow(std::move(dir));
                              javaTraversePackages(dirPtr, 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 (auto item : dirs)
                              javaTraverseDir(parent, item);

                              for (auto item : files) {
                              auto file
                              = std::make_unique<FileItem>("/icons/document.png", filename(item),
                              item.string());
                              parent->appendRow(std::move(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);
                              }