Wt examples  4.10.4
SourceView.C
Go to the documentation of this file.
1 #include "SourceView.h"
2 
3 #include <iostream>
4 #include <fstream>
5 #include <sstream>
6 
7 #include <stdlib.h>
8 
9 #include <boost/algorithm/string.hpp>
10 #include <boost/filesystem/operations.hpp>
11 #include <boost/filesystem/convenience.hpp>
12 
13 #include <Wt/WApplication.h>
14 #include <Wt/WText.h>
15 #include <Wt/WImage.h>
16 
17 using namespace Wt;
18 namespace fs = boost::filesystem;
19 
21  ItemDataRole contentRole,
22  ItemDataRole filePathRole)
23  : fileNameRole_(fileNameRole),
24  contentRole_(contentRole),
25  filePathRole_(filePathRole),
26  imageResource_(0)
27 {}
28 
30 { }
31 
33 {
34  if (index != index_ && index.isValid()) {
35  std::string fp = !cpp17::any_has_value(index.data(filePathRole_)) ? std::string()
36  : asString(index.data(filePathRole_)).toUTF8();
37 
38  if (cpp17::any_has_value(index.data(contentRole_))
39  || (!fp.empty() && !fs::is_directory(fp))) {
40  index_ = index;
41  update();
42 
43  return true;
44  }
45  }
46 
47  return false;
48 }
49 
50 std::string tempFileName()
51 {
52 #ifndef WT_WIN32
53  char spool[20];
54  strcpy(spool, "/tmp/wtXXXXXX");
55 
56  int i = mkstemp(spool);
57  close(i);
58 #else
59  char spool[2 * L_tmpnam];
60  tmpnam(spool);
61 #endif
62  return std::string(spool);
63 }
64 
65 std::string getLanguageFromFileExtension(const std::string &fileName)
66 {
67  if (boost::iends_with(fileName, ".h")
68  || boost::iends_with(fileName, ".C")
69  || boost::iends_with(fileName, ".cpp"))
70  return "cpp";
71  else if (boost::iends_with(fileName, ".xml"))
72  return "xml";
73  else if (boost::iends_with(fileName, ".html"))
74  return "html";
75  else if (boost::iends_with(fileName, ".java"))
76  return "java";
77  else if (boost::iends_with(fileName, ".js"))
78  return "javascript";
79  else if (boost::iends_with(fileName, ".css"))
80  return "css";
81  else
82  return std::string();
83 }
84 
85 std::string readFileToString(const std::string& fileName)
86 {
87  std::size_t outputFileSize = (std::size_t)fs::file_size(fileName);
88  std::fstream file (fileName.c_str(), std::ios::in | std::ios::binary);
89  char* memblock = new char [outputFileSize];
90  file.read(memblock, (std::streamsize)outputFileSize);
91  file.close();
92  std::string data = std::string(memblock, outputFileSize);
93  delete [] memblock;
94  return data;
95 }
96 
97 std::unique_ptr<WWidget> SourceView::renderView()
98 {
99  if (!index_.isValid()) {
100  // no content
101  auto result = std::make_unique<WText>();
102  result->setInline(false);
103  return std::move(result);
104  }
105 
106  /*
107  * read the contents, from string or file name
108  */
109  cpp17::any contentsData = index_.data(contentRole_);
110  std::string content;
111  if (cpp17::any_has_value(contentsData))
112  content = asString(contentsData).toUTF8();
113  cpp17::any fileNameData = index_.data(fileNameRole_);
114  std::string fileName =
115  asString(fileNameData).toUTF8();
116  cpp17::any filePathData = index_.data(filePathRole_);
117  std::string filePath;
118  if (cpp17::any_has_value(filePathData))
119  filePath = asString(filePathData).toUTF8();
120 
121  /*
122  * determine source language, for source highlight
123  */
124  std::string lang = getLanguageFromFileExtension(fileName);
125  if (content != "" && content.substr(0, 100).find("-*- C++ -*-")
126  != std::string::npos)
127  lang = "cpp";
128 
129  std::string outputFileName;
130 
131  if (lang != "") {
132  std::string inputFileName;
133 
134  if (cpp17::any_has_value(filePathData))
135  inputFileName = filePath;
136  else {
137  inputFileName = tempFileName();
138  std::ofstream out(inputFileName.c_str(),
139  std::ios::out | std::ios::binary);
140  out.write(content.c_str(), (std::streamsize)content.length());
141  out.close();
142  }
143 
144  outputFileName = tempFileName();
145 
146  std::string sourceHighlightCommand = "source-highlight ";
147  sourceHighlightCommand += "--src-lang=" + lang + " ";
148  sourceHighlightCommand += "--out-format=xhtml ";
149  sourceHighlightCommand += "--input=" + inputFileName + " ";
150  sourceHighlightCommand += "--output=" + outputFileName + " ";
151 
152  std::cerr << sourceHighlightCommand << std::endl;
153  bool sourceHighlightOk = system(sourceHighlightCommand.c_str()) == 0;
154 
155  if (sourceHighlightOk)
156  content = readFileToString(outputFileName);
157  else {
158  content = readFileToString(inputFileName);
159  lang = "";
160  }
161  unlink(outputFileName.c_str());
162 
163  if (!cpp17::any_has_value(filePathData))
164  unlink(inputFileName.c_str());
165  }
166 
167  if (content == "")
168  // do not load binary files, we would need to perform proper UTF-8
169  // transcoding to display them
170  if (!boost::iends_with(fileName, ".jar")
171  && !boost::iends_with(fileName, ".war")
172  && !boost::iends_with(fileName, ".class"))
173  content = readFileToString(fileName);
174 
175  std::unique_ptr<WWidget> result;
176 
177  if (!imageExtension(fileName).empty()) {
178  std::unique_ptr<WImage> image(std::make_unique<WImage>());
179  imageResource_ = std::make_shared<WMemoryResource>();
180  imageResource_->setMimeType("mime/" + imageExtension(fileName));
181  imageResource_->setData((const unsigned char*)content.data(),
182  (int)content.length());
183  image->setImageLink(WLink(imageResource_));
184  result = std::move(image);
185  } else if (lang != "") {
186  auto text = std::make_unique<WText>();
187  text->setTextFormat(TextFormat::UnsafeXHTML);
188  text->setText(content);
189  result = std::move(text);
190  } else {
191  auto text = std::make_unique<WText>();
192  text->setTextFormat(TextFormat::Plain);
193  text->setText(content);
194  result = std::move(text);
195  }
196 
197  result->setInline(false);
198  WApplication::instance()
199  ->doJavaScript(result->jsRef() + ".parentNode.scrollTop = 0;");
200  return std::move(result);
201 }
202 
203 std::string SourceView::imageExtension(const std::string& fileName)
204 {
205  static const char *imageExtensions[] = {
206  ".png", ".gif", ".jpg", "jpeg", ".ico", 0
207  };
208 
209  fs::path p(fileName);
210  std::string extension = fs::extension(p);
211 
212  for (const char **s = imageExtensions; *s != 0; ++s)
213  if (*s == extension)
214  return extension.substr(1);
215 
216  return std::string();
217 }
std::string readFileToString(const std::string &fileName)
Definition: SourceView.C:85
std::string getLanguageFromFileExtension(const std::string &fileName)
Definition: SourceView.C:65
std::string tempFileName()
Definition: SourceView.C:50
virtual std::unique_ptr< WWidget > renderView()
Returns the widget that renders the view.
Definition: SourceView.C:97
Wt::ItemDataRole filePathRole_
Definition: SourceView.h:66
WModelIndex index_
The index that is currently displayed.
Definition: SourceView.h:61
std::string imageExtension(const std::string &fileName)
Definition: SourceView.C:203
bool setIndex(const WModelIndex &index)
Sets the model index.
Definition: SourceView.C:32
Wt::ItemDataRole fileNameRole_
The role that is currently displayed.
Definition: SourceView.h:64
std::shared_ptr< WMemoryResource > imageResource_
Definition: SourceView.h:68
SourceView(ItemDataRole fileNameRole, ItemDataRole contentRole, ItemDataRole filePathRole)
Constructor.
Definition: SourceView.C:20
Wt::ItemDataRole contentRole_
Definition: SourceView.h:65
virtual ~SourceView()
Destructor.
Definition: SourceView.C:29
bool isValid() const
cpp17::any data(ItemDataRole role=ItemDataRole::Display) const
std::string toUTF8() const
WString asString(const cpp17::any &v, const WString &formatString=WString())