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