Wt examples  3.2.1
ExampleSourceViewer.C
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2009 Emweb bvba
3  *
4  * See the LICENSE file for terms of use.
5  */
6 
7 #include <iostream>
8 #include <stdlib.h>
9 #include <algorithm>
10 
11 #include <Wt/WApplication>
12 #include <Wt/WContainerWidget>
13 #include <Wt/WEnvironment>
14 #include <Wt/WLineEdit>
15 #include <Wt/WGridLayout>
16 #include <Wt/WHBoxLayout>
17 #include <Wt/WPushButton>
18 #include <Wt/WTable>
19 #include <Wt/WText>
20 #include <Wt/WTreeView>
21 #include <Wt/WVBoxLayout>
22 #include <Wt/WViewWidget>
23 
24 #include <boost/filesystem/operations.hpp>
25 #include <boost/filesystem/exception.hpp>
26 #include <boost/filesystem/convenience.hpp>
27 #include <boost/algorithm/string.hpp>
28 
29 #include "ExampleSourceViewer.h"
30 #include "FileItem.h"
31 
32 using namespace Wt;
33 namespace fs = boost::filesystem;
34 
35 // Same as p.filename() in latest boost::filesystem
36 static std::string filename(const fs::path& p)
37 {
38 #if BOOST_FILESYSTEM_VERSION < 3
39  return p.empty() ? std::string() : *--p.end();
40 #else
41  return p.empty() ? std::string() : (*--p.end()).string();
42 #endif
43 }
44 
45 // Same as p.stem() in latest boost::filesystem
46 static std::string stem(const fs::path& p)
47 {
48  std::string fn = filename(p);
49  std::size_t pos = fn.find('.');
50  if (pos == std::string::npos)
51  return fn;
52  else
53  return fn.substr(0, pos);
54 }
55 
56 // Should be same as p.parent_path() in latest boost::filesystem
57 // This is not entirely according to fs::path::parent_path() in 1.39.0
58 fs::path parent_path(const fs::path& p)
59 {
60  std::string fn = filename(p);
61  std::string path = p.string();
62 
63  return path.substr(0, path.length() - fn.length() - 1);
64 }
65 
66 static bool comparePaths(const fs::path& p1, const fs::path& p2)
67 {
68  return filename(p1) > filename(p2);
69 }
70 
71 ExampleSourceViewer::ExampleSourceViewer(const std::string& deployPath,
72  const std::string& examplesRoot,
73  const std::string& examplesType)
74  : deployPath_(deployPath),
75  examplesRoot_(examplesRoot),
76  examplesType_(examplesType)
77 {
78  wApp->internalPathChanged().connect
80 
82 }
83 
85 {
86  WApplication *app = wApp;
87 
88  if (app->internalPathMatches(deployPath_)) {
89  std::string example = app->internalPathNextPart(deployPath_);
90 
91  if (example.find("..") != std::string::npos
92  || example.find('/') != std::string::npos
93  || example.find('\\') != std::string::npos)
94  setExample("INVALID_DIR", "INVALID");
95  else
96  setExample(examplesRoot_ + example, example);
97  }
98 }
99 
100 void ExampleSourceViewer::setExample(const std::string& exampleDir,
101  const std::string& example)
102 {
103  clear();
104 
105  bool exists = false;
106  try {
107  exists = fs::exists(exampleDir);
108  } catch (std::exception&) {
109  }
110 
111  if (!exists) {
112  addWidget(new WText("No such example: " + exampleDir));
113  return;
114  }
115 
116  model_ = new WStandardItemModel(0, 1, this);
117  if (examplesType_ == "CPP") {
118  cppTraverseDir(model_->invisibleRootItem(), exampleDir);
119  } else if (examplesType_ == "JAVA") {
120  javaTraverseDir(model_->invisibleRootItem(), exampleDir);
121  }
122 
123  WApplication::instance()->setTitle(tr("srcview.title." + example));
124  WText *title =
125  new WText(tr("srcview.title." + examplesType_ + "." + example));
126  title->setInternalPathEncoding(true);
127 
128  exampleView_ = new WTreeView();
130  exampleView_->resize(300, WLength::Auto);
138 
142  sourceView_->setStyleClass("source-view");
143 
144  /*
145  * Expand path to first file, to show something in the source viewer
146  */
147  WStandardItem *w = model_->item(0);
148  do {
149  exampleView_->setExpanded(w->index(), true);
150  if (w->rowCount() > 0)
151  w = w->child(0);
152  else {
154  w = 0;
155  }
156  } while (w);
157 
158  WVBoxLayout *topLayout = new WVBoxLayout();
159  topLayout->addWidget(title, 0, AlignTop | AlignJustify);
160 
161  WHBoxLayout *gitLayout = new WHBoxLayout();
162  gitLayout->addWidget(exampleView_, 0);
163  gitLayout->addWidget(sourceView_, 1);
164  topLayout->addLayout(gitLayout, 1);
165  gitLayout->setResizable(0);
166 
167  /*
168  * FIXME, in plain HTML mode, we should set a minimum size to the source
169  * view, and remove this in enableAjax() ?
170  */
171  // sourceView_->setHeight("100%");
172 
173  setLayout(topLayout);
174  setStyleClass("maindiv");
175 }
176 
177 /*
178  * Return the companion implementation/header file for a C++ source file.
179  */
180 static fs::path getCompanion(const fs::path& path)
181 {
182  std::string ext = fs::extension(path);
183 
184  if (ext == ".h")
185  return parent_path(path) / (stem(path) + ".C");
186  else if (ext == ".C" || ext == ".cpp")
187  return parent_path(path) / (stem(path) + ".h");
188  else
189  return fs::path();
190 }
191 
193  const fs::path& path)
194 {
195  static const char *supportedFiles[] = {
196  ".C", ".cpp", ".h", ".css", ".xml", ".png", ".gif", ".csv", ".ico", 0
197  };
198 
199  FileItem* dir = new FileItem("/icons/yellow-folder-open.png", filename(path),
200  "");
201  parent->appendRow(dir);
202  parent = dir;
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<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(p)) {
223  std::string ext = fs::extension(p);
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  FileItem *classItem =
246  new FileItem("/icons/cppclass.png", label, std::string());
247  classItem->setFlags(classItem->flags() | ItemIsXHTMLText);
248 
249  FileItem *header = new FileItem("/icons/document.png", filename(p),
250  p.string());
251  FileItem *cpp = new FileItem("/icons/document.png",
252  filename(*it_companion),
253  (*it_companion).string());
254  classItem->appendRow(header);
255  classItem->appendRow(cpp);
256 
257  classes.push_back(classItem);
258  paths.erase(it_companion);
259  } else {
260  FileItem *file = new FileItem("/icons/document.png", filename(p),
261  p.string());
262  files.push_back(file);
263  }
264  } else if (fs::is_directory(p)) {
265  dirs.push_back(p);
266  } else {
267  FileItem *file = new FileItem("/icons/document.png", filename(p),
268  p.string());
269  files.push_back(file);
270  }
271  }
272 
273  std::sort(dirs.begin(), dirs.end(), comparePaths);
274 
275  for (unsigned int i = 0; i < classes.size(); i++)
276  parent->appendRow(classes[i]);
277 
278  for (unsigned int i = 0; i < files.size(); i++)
279  parent->appendRow(files[i]);
280 
281  for (unsigned int i = 0; i < dirs.size(); i++)
282  cppTraverseDir(parent, dirs[i]);
283  } catch (fs::filesystem_error& e) {
284  std::cerr << e.what() << std::endl;
285  }
286 }
287 
289  const fs::path& srcPath,
290  const std::string packageName)
291 {
292  fs::directory_iterator end_itr;
293 
294  FileItem *packageItem = 0;
295  for (fs::directory_iterator i(srcPath); i != end_itr; ++i) {
296  fs::path p = *i;
297  if (fs::is_regular(p)) {
298  if (!packageItem) {
299  packageItem = new FileItem("/icons/package.png", packageName, "");
300  parent->appendRow(packageItem);
301  }
302 
303  FileItem *file = new FileItem("/icons/javaclass.png", filename(p),
304  p.string());
305  packageItem->appendRow(file);
306  }
307  }
308 
309  for (fs::directory_iterator i(srcPath); i != end_itr; ++i) {
310  fs::path p = *i;
311  if (fs::is_directory(p)) {
312  std::string pn = packageName;
313  if (!pn.empty())
314  pn += ".";
315  pn += filename(p);
316 
317  javaTraversePackages(parent, p, pn);
318  }
319  }
320 }
321 
323  const fs::path& path)
324 {
325  FileItem* dir = new FileItem("/icons/yellow-folder-open.png", filename(path),
326  "");
327  parent->appendRow(dir);
328  parent = dir;
329 
330  std::vector<fs::path> files, dirs;
331 
332  fs::directory_iterator end_itr;
333  for (fs::directory_iterator i(path); i != end_itr; ++i) {
334  fs::path p = *i;
335  if (fs::is_directory(p)) {
336  if (filename(p) == "src") {
337  FileItem* dir = new FileItem("/icons/package-folder-open.png",
338  filename(p), "");
339  parent->appendRow(dir);
340  javaTraversePackages(dir, p, "");
341  } else
342  dirs.push_back(p);
343  } else {
344  files.push_back(p);
345  }
346  }
347 
348  std::sort(dirs.begin(), dirs.end(), comparePaths);
349  std::sort(files.begin(), files.end(), comparePaths);
350 
351  for (unsigned int i = 0; i < dirs.size(); i++)
352  javaTraverseDir(parent, dirs[i]);
353 
354  for (unsigned int i = 0; i < files.size(); i++) {
355  FileItem *file = new FileItem("/icons/document.png", filename(files[i]),
356  files[i].string());
357  parent->appendRow(file);
358  }
359 }
360 
364  if (exampleView_->selectedIndexes().empty())
365  return;
366 
367  WModelIndex selected = *exampleView_->selectedIndexes().begin();
368 
369  // expand a folder when clicked
370  if (exampleView_->model()->rowCount(selected) > 0
371  && !exampleView_->isExpanded(selected))
372  exampleView_->setExpanded(selected, true);
373 
374  // (for a file,) load data in source viewer
375  sourceView_->setIndex(selected);
376 }

Generated on Tue Jun 19 2012 for the C++ Web Toolkit (Wt) by doxygen 1.8.1