Wt examples  4.12.2
Loading...
Searching...
No Matches
ExampleSourceViewer.C
Go to the documentation of this file.
1/*
2 * Copyright (C) 2009 Emweb bv, Herent, Belgium
3 *
4 * See the LICENSE file for terms of use.
5 */
6
8#include "FileItem.h"
9
10#include <Wt/WApplication.h>
11#include <Wt/WContainerWidget.h>
12#include <Wt/WEnvironment.h>
13#include <Wt/WLineEdit.h>
14#include <Wt/WGridLayout.h>
15#include <Wt/WHBoxLayout.h>
16#include <Wt/WPushButton.h>
17#include <Wt/WTable.h>
18#include <Wt/WText.h>
19#include <Wt/WTreeView.h>
20#include <Wt/WVBoxLayout.h>
21#include <Wt/WViewWidget.h>
22
23#include <Wt/cpp17/filesystem.hpp>
24
25#include <iostream>
26#include <stdlib.h>
27#include <algorithm>
28
29namespace fs = cpp17::filesystem;
30
31// Same as p.filename() in latest boost::filesystem
32static std::string filename(const fs::path& p)
33{
34 return p.empty() ? std::string() : (*--p.end()).string();
35}
36
37// Same as p.stem() in latest boost::filesystem
38static std::string stem(const fs::path& p)
39{
40 std::string fn = filename(p);
41 std::size_t pos = fn.find('.');
42 if (pos == std::string::npos)
43 return fn;
44 else
45 return fn.substr(0, pos);
46}
47
48// Should be same as p.parent_path() in latest boost::filesystem
49// This is not entirely according to fs::path::parent_path() in 1.39.0
50fs::path parent_path(const fs::path& p)
51{
52 std::string fn = filename(p);
53 std::string path = p.string();
54
55 return path.substr(0, path.length() - fn.length() - 1);
56}
57
58static bool comparePaths(const fs::path& p1, const fs::path& p2)
59{
60 return filename(p1) > filename(p2);
61}
62
63ExampleSourceViewer::ExampleSourceViewer(const std::string& deployPath,
64 const std::string& examplesRoot,
65 const std::string& examplesType)
66 : deployPath_(deployPath),
67 examplesRoot_(examplesRoot),
68 examplesType_(examplesType)
69{
70 wApp->internalPathChanged().connect
72
74}
75
77{
78 WApplication *app = wApp;
79
81 std::string example = app->internalPathNextPart(deployPath_);
82
83 if (example.find("..") != std::string::npos
84 || example.find('/') != std::string::npos
85 || example.find('\\') != std::string::npos) {
86 app->setInternalPathValid(false);
87 setExample("INVALID_DIR", "INVALID");
88 } else
89 setExample(examplesRoot_ + example, example);
90 }
91}
92
93void ExampleSourceViewer::setExample(const std::string& exampleDir,
94 const std::string& example)
95{
96 clear();
97
98 bool exists = false;
99 try {
100 exists = fs::exists(exampleDir);
101 } catch (std::exception&) {
102 }
103
104 if (!exists) {
105 WApplication::instance()->setInternalPathValid(false);
106 addWidget(std::make_unique<WText>("No such example: " + exampleDir));
107 return;
108 }
109
110 model_ = std::make_shared<WStandardItemModel>(0, 1);
111 if (examplesType_ == "CPP") {
112 cppTraverseDir(model_->invisibleRootItem(), exampleDir);
113 } else if (examplesType_ == "JAVA") {
114 javaTraverseDir(model_->invisibleRootItem(), exampleDir);
115 }
116
117 WApplication::instance()->setTitle(tr("srcview.title." + example));
118 std::unique_ptr<WText> title(std::make_unique<WText>(
119 tr("srcview.title." + examplesType_ + "." + example)));
120 title->setInternalPathEncoding(true);
121
122 auto exampleView = std::make_unique<WTreeView>();
123 exampleView_ = exampleView.get();
129 exampleView_->setSelectionMode(SelectionMode::Single);
133
134 auto sourceView =
135 std::make_unique<SourceView>(FileItem::FileNameRole,
138 sourceView_ = sourceView.get();
139 sourceView_->setStyleClass("source-view");
140
141 /*
142 * Expand path to first file, to show something in the source viewer
143 */
144 WStandardItem *w = model_->item(0);
145 do {
146 exampleView_->setExpanded(w->index(), true);
147 if (w->rowCount() > 0)
148 w = w->child(0);
149 else {
151 w = 0;
152 }
153 } while (w);
154
155 auto topLayout = std::make_unique<WVBoxLayout>();
156 topLayout->addWidget(std::move(title));
157
158 auto gitLayout = std::make_unique<WHBoxLayout>();
159 WHBoxLayout *g = gitLayout.get();
160 gitLayout->addWidget(std::move(exampleView), 0);
161 gitLayout->addWidget(std::move(sourceView), 1);
162 topLayout->addLayout(std::move(gitLayout), 1);
163 g->setResizable(0);
164
165 /*
166 * FIXME, in plain HTML mode, we should set a minimum size to the source
167 * view, and remove this in enableAjax() ?
168 */
169 // sourceView_->setHeight("100%");
170
171 setLayout(std::move(topLayout));
172 setStyleClass("maindiv");
173}
174
175/*
176 * Return the companion implementation/header file for a C++ source file.
177 */
178static fs::path getCompanion(const fs::path& path)
179{
180 std::string ext = path.extension().string();
181
182 if (ext == ".h")
183 return parent_path(path) / (stem(path) + ".C");
184 else if (ext == ".C" || ext == ".cpp")
185 return parent_path(path) / (stem(path) + ".h");
186 else
187 return fs::path();
188}
189
191 const fs::path& path)
192{
193 static const char *supportedFiles[] = {
194 ".C", ".cpp", ".h", ".css", ".xml", ".png", ".gif", ".csv", ".ico", 0
195 };
196
197 auto dir = std::make_unique<FileItem>("/icons/yellow-folder-open.png",
198 filename(path),
199 "");
200 FileItem *dirPtr = dir.get();
201 parent->appendRow(std::move(dir));
202 parent = dirPtr;
203 try {
204 std::set<fs::path> paths;
205
206 fs::directory_iterator end_itr;
207 for (fs::directory_iterator i(path); i != end_itr; ++i)
208 paths.insert(*i);
209
210 std::vector<std::unique_ptr<FileItem>> classes, files;
211 std::vector<fs::path> dirs;
212
213 while (!paths.empty()) {
214 fs::path p = *paths.begin();
215 paths.erase(p);
216
217 // skip symbolic links and other files
218 if (fs::is_symlink(p))
219 continue;
220
221 // skip files with an extension we do not want to handle
222 if (fs::is_regular_file(p)) {
223 std::string ext = p.extension().string();
224 bool supported = false;
225 for (const char **s = supportedFiles; *s != 0; ++s)
226 if (*s == ext) {
227 supported = true;
228 break;
229 }
230
231 if (!supported)
232 continue;
233 }
234
235 // see if we have one file of a class (.C, .h)
236 fs::path companion = getCompanion(p);
237 if (!companion.empty()) {
238 std::set<fs::path>::iterator it_companion = paths.find(companion);
239
240 if (it_companion != paths.end()) {
241 std::string className = stem(p);
242 escapeText(className);
243 std::string label = "<i>class</i> " + className;
244
245 std::unique_ptr<FileItem> classItem =
246 std::make_unique<FileItem>("/icons/cppclass.png", label, std::string());
247 classItem->setFlags(classItem->flags() | ItemFlag::XHTMLText);
248
249 auto header
250 = std::make_unique<FileItem>("/icons/document.png", filename(p),
251 p.string());
252 auto cpp
253 = std::make_unique<FileItem>("/icons/document.png",
254 filename(*it_companion),
255 (*it_companion).string());
256 classItem->appendRow(std::move(header));
257 classItem->appendRow(std::move(cpp));
258
259 classes.push_back(std::move(classItem));
260 paths.erase(it_companion);
261 } else {
262 auto file
263 = std::make_unique<FileItem>("/icons/document.png", filename(p),
264 p.string());
265 files.push_back(std::move(file));
266 }
267 } else if (fs::is_directory(p)) {
268 dirs.push_back(p);
269 } else {
270 auto file
271 = std::make_unique<FileItem>("/icons/document.png", filename(p),
272 p.string());
273 files.push_back(std::move(file));
274 }
275 }
276
277 std::sort(dirs.begin(), dirs.end(), comparePaths);
278
279 for (unsigned int i = 0; i < classes.size(); i++)
280 parent->appendRow(std::move(classes[i]));
281
282 for (unsigned int i = 0; i < files.size(); i++)
283 parent->appendRow(std::move(files[i]));
284
285 for (unsigned int i = 0; i < dirs.size(); i++)
286 cppTraverseDir(parent, dirs[i]);
287 } catch (fs::filesystem_error& e) {
288 std::cerr << e.what() << std::endl;
289 }
290}
291
293 const fs::path& srcPath,
294 const std::string packageName)
295{
296 fs::directory_iterator end_itr;
297
298 FileItem *packageItem = nullptr;
299 for (fs::directory_iterator i(srcPath); i != end_itr; ++i) {
300 fs::path p = *i;
301 if (fs::is_regular_file(p)) {
302 if (!packageItem) {
303 auto item = std::make_unique<FileItem>("/icons/package.png", packageName, "");
304 packageItem = item.get();
305 parent->appendRow(std::move(item));
306 }
307
308 auto file
309 = std::make_unique<FileItem>("/icons/javaclass.png", filename(p),
310 p.string());
311 packageItem->appendRow(std::move(file));
312 }
313 }
314
315 for (fs::directory_iterator i(srcPath); i != end_itr; ++i) {
316 fs::path p = *i;
317 if (fs::is_directory(p)) {
318 std::string pn = packageName;
319 if (!pn.empty())
320 pn += ".";
321 pn += filename(p);
322
324 }
325 }
326}
327
329 const fs::path& path)
330{
331 auto dir
332 = std::make_unique<FileItem>("/icons/yellow-folder-open.png",
333 filename(path),"");
334 FileItem *dirPtr = dir.get();
335 parent->appendRow(std::move(dir));
336 parent = dirPtr;
337
338 std::vector<fs::path> files, dirs;
339
340 fs::directory_iterator end_itr;
341 for (fs::directory_iterator i(path); i != end_itr; ++i) {
342 fs::path p = *i;
343 if (fs::is_directory(p)) {
344 if (filename(p) == "src") {
345 auto dir
346 = std::make_unique<FileItem>("/icons/package-folder-open.png",
347 filename(p), "");
348 FileItem *dirPtr = dir.get();
349 parent->appendRow(std::move(dir));
350 javaTraversePackages(dirPtr, p, "");
351 } else
352 dirs.push_back(p);
353 } else {
354 files.push_back(p);
355 }
356 }
357
358 std::sort(dirs.begin(), dirs.end(), comparePaths);
359 std::sort(files.begin(), files.end(), comparePaths);
360
361 for (auto item : dirs)
362 javaTraverseDir(parent, item);
363
364 for (auto item : files) {
365 auto file
366 = std::make_unique<FileItem>("/icons/document.png", filename(item),
367 item.string());
368 parent->appendRow(std::move(file));
369 }
370}
371
375 if (exampleView_->selectedIndexes().empty())
376 return;
377
378 WModelIndex selected = *exampleView_->selectedIndexes().begin();
379
380 // expand a folder when clicked
381 if (exampleView_->model()->rowCount(selected) > 0
382 && !exampleView_->isExpanded(selected))
383 exampleView_->setExpanded(selected, true);
384
385 // (for a file,) load data in source viewer
386 sourceView_->setIndex(selected);
387}
static fs::path getCompanion(const fs::path &path)
static std::string stem(const fs::path &p)
static std::string filename(const fs::path &p)
static bool comparePaths(const fs::path &p1, const fs::path &p2)
fs::path parent_path(const fs::path &p)
void setExample(const std::string &exampleDir, const std::string &example)
std::shared_ptr< WStandardItemModel > model_
ExampleSourceViewer(const std::string &deployPath, const std::string &examplesRoot, const std::string &examplesType)
Constructor.
void cppTraverseDir(WStandardItem *parent, const cpp17::filesystem::path &path)
void showFile()
Displayed the currently selected file.
void javaTraverseDir(WStandardItem *parent, const cpp17::filesystem::path &path)
void javaTraversePackages(WStandardItem *parent, const cpp17::filesystem::path &srcPath, const std::string packageName)
WStandardItem which stores a file.
Definition FileItem.h:28
static const Wt::ItemDataRole FileNameRole
Definition FileItem.h:32
static const Wt::ItemDataRole FilePathRole
Definition FileItem.h:31
static const Wt::ItemDataRole ContentsRole
Definition FileItem.h:30
bool setIndex(const WModelIndex &index)
Sets the model index.
Definition SourceView.C:32
virtual Wt::Signals::connection connect(WObject *target, WObject::Method method) override
WModelIndexSet selectedIndexes() const
Signal & selectionChanged()
void select(const WModelIndex &index, SelectionFlag option=SelectionFlag::Select)
std::shared_ptr< WAbstractItemModel > model() const
void setSortingEnabled(bool enabled)
void setSelectionMode(SelectionMode mode)
std::string internalPathNextPart(const std::string &path) const
bool internalPathMatches(const std::string &path) const
void setInternalPathValid(bool valid)
void addWidget(std::unique_ptr< WWidget > widget, int stretch, WFlags< AlignmentFlag > alignment)
void setResizable(int index, bool enabled=true, const WLength &initialSize=WLength::Auto)
virtual void clear()
void setLayout(std::unique_ptr< WLayout > layout)
virtual void addWidget(std::unique_ptr< WWidget > widget)
static WLength Auto
WModelIndex index() const
void appendRow(std::vector< std::unique_ptr< WStandardItem > > items)
int rowCount() const
WStandardItem * child(int row, int column=0) const
bool isExpanded(const WModelIndex &index) const
void setExpanded(const WModelIndex &, bool expanded)
virtual void setAlternatingRowColors(bool enable) override
virtual void setHeaderHeight(const WLength &height) override
virtual void setModel(const std::shared_ptr< WAbstractItemModel > &model) override
void expandToDepth(int depth)
virtual void resize(const WLength &width, const WLength &height) override
virtual void setStyleClass(const WString &styleClass) override
static WString tr(const char *key)
WWidget * parent() const