Wt examples  4.10.4
Home.C
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2008 Emweb bv, Herent, Belgium.
3  *
4  * See the LICENSE file for terms of use.
5  */
6 
7 #include <fstream>
8 #include <iostream>
9 
10 #include <boost/lexical_cast.hpp>
11 #include <boost/tokenizer.hpp>
12 #include <boost/algorithm/string.hpp>
13 
14 #include <Wt/WAnchor.h>
15 #include <Wt/WApplication.h>
16 #include <Wt/WEnvironment.h>
17 #include <Wt/WLogger.h>
18 #include <Wt/WMenu.h>
19 #include <Wt/WPushButton.h>
20 #include <Wt/WStackedWidget.h>
21 #include <Wt/WTabWidget.h>
22 #include <Wt/WTable.h>
23 #include <Wt/WTableCell.h>
24 #include <Wt/WTemplate.h>
25 #include <Wt/WText.h>
26 #include <Wt/WViewWidget.h>
27 #include <Wt/WVBoxLayout.h>
28 
29 #include "Home.h"
30 #include "view/BlogView.h"
31 
32 using namespace Wt;
33 
34 static const std::string SRC_INTERNAL_PATH = "src";
35 
37 {
38 }
39 
41  Dbo::SqlConnectionPool& blogDb,
42  const std::string& title, const std::string& resourceBundle,
43  const std::string& cssPath)
44  : WApplication(env),
45  blogDb_(blogDb),
46  homePage_(0),
47  sourceViewer_(0)
48 {
49  messageResourceBundle().use(appRoot() + resourceBundle, false);
50 
51  useStyleSheet(cssPath + "/wt.css");
52  useStyleSheet(cssPath + "/wt_ie.css", "lt IE 7", "all");
53  useStyleSheet("css/home.css");
54  useStyleSheet("css/sourceview.css");
55  useStyleSheet("css/chatwidget.css");
56  useStyleSheet("css/chatwidget_ie6.css", "lt IE 7", "all");
57  setTitle(title);
58 
59  setLocale("");
60  language_ = 0;
61 }
62 
63 void Home::init()
64 {
68 
69  setup();
70 
72 }
73 
75 {
76  /*
77  * This function switches between the two major components of the homepage,
78  * depending on the internal path:
79  * /src -> source viewer
80  * /... -> homepage
81  *
82  * FIXME: we should take into account language /cn/src ...
83  */
84  std::string base = internalPathNextPart("/");
85 
86  if (base == SRC_INTERNAL_PATH) {
87  if (!sourceViewer_) {
89  homePage_ = nullptr;
90 
91  root()->clear();
92 
93  auto layout = std::make_unique<WVBoxLayout>();
94  layout->setContentsMargins(0, 0, 0, 0);
95  auto source = sourceViewer("/" + SRC_INTERNAL_PATH + "/");
96  sourceViewer_ = source.get();
97  layout->addWidget(std::move(source));
98 
99  root()->setLayout(std::move(layout));
100  }
101  } else {
102  if (!homePage_) {
104  sourceViewer_ = nullptr;
105  root()->clear();
106 
107  createHome();
108 
110  }
111  }
112 }
113 
115 {
116  WTemplate *result = root()->addWidget(std::make_unique<WTemplate>(tr("template")));
117  homePage_ = result;
118 
119  auto languagesDiv = std::make_unique<WContainerWidget>();
120  languagesDiv->setId("top_languages");
121 
122  for (unsigned i = 0; i < languages.size(); ++i) {
123  if (i != 0)
124  languagesDiv->addWidget(std::make_unique<WText>("- "));
125 
126  const Lang& l = languages[i];
127 
128  languagesDiv->addWidget(std::make_unique<WAnchor>(WLink(LinkType::InternalPath, l.path_), l.longDescription_));
129  }
130 
131  auto contents = std::make_unique<WStackedWidget>();
132  WAnimation fade(AnimationEffect::Fade, TimingFunction::Linear, 250);
133  contents->setTransitionAnimation(fade);
134  contents->setId("main_page");
135 
136  auto mainMenu = std::make_unique<WMenu>(contents.get());
137  mainMenu_ = mainMenu.get();
139  (tr("introduction"), introduction())->setPathComponent("");
140 
142  (tr("blog"), deferCreate(std::bind(&Home::blog, this)));
143 
145  (tr("features"), wrapView(&Home::features),
146  ContentLoading::Eager);
147 
149  (tr("documentation"), wrapView(&Home::documentation),
150  ContentLoading::Eager);
151 
153  (tr("examples"), examples(),
154  ContentLoading::Eager)->setPathComponent("examples/");
155 
157  (tr("download"), deferCreate(std::bind(&Home::download, this)),
158  ContentLoading::Eager);
159 
161  (tr("community"), wrapView(&Home::community),
162  ContentLoading::Eager);
163 
165  (tr("other-language"), wrapView(&Home::otherLanguage),
166  ContentLoading::Eager);
167 
169 
171 
172  // Make the menu be internal-path aware.
174 
175  sideBarContent_ = std::make_unique<WContainerWidget>();
176 
177  result->bindWidget("languages", std::move(languagesDiv));
178  result->bindWidget("menu", std::move(mainMenu));
179  result->bindWidget("contents", std::move(contents));
180  result->bindWidget("sidebar", std::move(sideBarContent_));
181 }
182 
183 void Home::setLanguage(int index)
184 {
185  if (homePage_) {
186  const Lang& l = languages[index];
187 
188  setLocale(l.code_);
189 
190  std::string langPath = l.path_;
191  mainMenu_->setInternalBasePath(langPath);
192  examplesMenu_->setInternalBasePath(langPath + "examples");
193  BlogView *blog = dynamic_cast<BlogView *>(findWidget("blog"));
194  if (blog)
195  blog->setInternalBasePath(langPath + "blog/");
196  updateTitle();
197 
198  language_ = index;
199  }
200 }
201 
202 std::unique_ptr<WWidget> Home::linkSourceBrowser(const std::string& example)
203 {
204  /*
205  * Instead of using a WAnchor, which will not progress properly because
206  * it is wrapped with wrapView() (-- should we not fix that?), we use
207  * a WText which contains an anchor, and enable internal path encoding.
208  */
209  std::string path = "#/" + SRC_INTERNAL_PATH + "/" + example;
210  std::unique_ptr<WText> a(std::make_unique<WText>(tr("source-browser-link").arg(path)));
211  a->setInternalPathEncoding(true);
212  return std::move(a);
213 }
214 
216 {
217  std::string langPath = internalPathNextPart("/");
218 
219  if (langPath.empty())
220  langPath = '/';
221  else
222  langPath = '/' + langPath + '/';
223 
224  int newLanguage = 0;
225 
226  for (unsigned i = 0; i < languages.size(); ++i) {
227  if (languages[i].path_ == langPath) {
228  newLanguage = i;
229  break;
230  }
231  }
232 
233  if (newLanguage != language_)
234  setLanguage(newLanguage);
235 }
236 
238 {
239  if (mainMenu_->currentItem()) {
240  setTitle(tr("wt") + " - " + mainMenu_->currentItem()->text());
241  }
242 }
243 
244 void Home::logInternalPath(const std::string& path)
245 {
246  // simulate an access log for the interal paths
247  log("path") << path;
248 
249  // If this goes to /src, we need to invoke google analytics method too
250  if (path.size() >= 4 && path.substr(0, 4) == "/src") {
252  }
253 }
254 
255 std::unique_ptr<WWidget> Home::introduction()
256 {
257  return std::make_unique<WText>(tr("home.intro"));
258 }
259 
260 std::unique_ptr<WWidget> Home::blog()
261 {
262  const Lang& l = languages[language_];
263  std::string langPath = l.path_;
264  std::unique_ptr<BlogView> blog
265  = std::make_unique<BlogView>(langPath + "blog/",
266  blogDb_, "/wt/blog/feed/");
267  blog->setObjectName("blog");
268 
269  if (!blog->user().empty())
270  chatSetUser(blog->user());
271 
272  blog->userChanged().connect(std::bind(&Home::chatSetUser, this, std::placeholders::_1));
273 
274  return std::move(blog);
275 }
276 
277 void Home::chatSetUser(const WString& userName)
278 {
279  WApplication::instance()->doJavaScript
280  ("if (window.chat && window.chat.emit) {"
281  """try {"
282  "" "window.chat.emit(window.chat, 'login', "
283  "" "" + userName.jsStringLiteral() + "); "
284  """} catch (e) {"
285  "" "window.chatUser=" + userName.jsStringLiteral() + ";"
286  """}"
287  "} else "
288  """window.chatUser=" + userName.jsStringLiteral() + ";");
289 }
290 
291 std::unique_ptr<WWidget> Home::status()
292 {
293  return std::make_unique<WText>(tr("home.status"));
294 }
295 
296 std::unique_ptr<WWidget> Home::features()
297 {
298  return std::unique_ptr<WText>(std::make_unique<WText>(tr("home.features")));
299 }
300 
301 std::unique_ptr<WWidget> Home::documentation()
302 {
303  std::unique_ptr<WText> result
304  = std::make_unique<WText>(tr("home.documentation"));
305  result->setInternalPathEncoding(true);
306  return std::move(result);
307 }
308 
309 std::unique_ptr<WWidget> Home::otherLanguage()
310 {
311  return std::unique_ptr<WText>(std::make_unique<WText>(tr("home.other-language")));
312 }
313 
314 std::unique_ptr<WWidget> Home::wrapView(std::unique_ptr<WWidget> (Home::*createWidget)())
315 {
316  return makeStaticModel(std::bind(createWidget, this));
317 }
318 
319 std::string Home::href(const std::string& url, const std::string& description)
320 {
321  return "<a href=\"" + url + "\" target=\"_blank\">" + description + "</a>";
322 }
323 
324 std::unique_ptr<WWidget> Home::community()
325 {
326  return std::make_unique<WText>(tr("home.community"));
327 }
328 
329 void Home::readReleases(WTable *releaseTable)
330 {
331  std::ifstream f((filePrefix() + "releases.txt").c_str());
332 
333  releaseTable->clear();
334 
335  releaseTable->elementAt(0, 0)
336  ->addWidget(std::make_unique<WText>(tr("home.download.version")));
337  releaseTable->elementAt(0, 1)
338  ->addWidget(std::make_unique<WText>(tr("home.download.date")));
339  releaseTable->elementAt(0, 2)
340  ->addWidget(std::make_unique<WText>(tr("home.download.description")));
341 
342  releaseTable->elementAt(0, 0)->resize(WLength(15, LengthUnit::FontEx),
343  WLength::Auto);
344  releaseTable->elementAt(0, 1)->resize(WLength(15, LengthUnit::FontEx),
345  WLength::Auto);
346 
347  int row = 1;
348 
349  while (f) {
350  std::string line;
351  getline(f, line);
352 
353  if (f) {
354  typedef boost::tokenizer<boost::escaped_list_separator<char> >
355  CsvTokenizer;
356  CsvTokenizer tok(line);
357 
358  CsvTokenizer::iterator i=tok.begin();
359 
360  std::string fileName = *i;
361  std::string description = *(++i);
362  releaseTable->elementAt(row, 1)->addWidget(std::make_unique<WText>(*(++i)));
363  releaseTable->elementAt(row, 2)->addWidget(std::make_unique<WText>(*(++i)));
364 
365  ++i;
366  std::string url = "http://prdownloads.sourceforge.net/witty/"
367  + fileName + "?download";
368  if (i != tok.end())
369  url = *i;
370 
371  releaseTable->elementAt(row, 0)->addWidget
372  (std::make_unique<WText>(href(url, description)));
373 
374  ++row;
375  }
376  }
377 }
378 
379 #ifdef WT_EMWEB_BUILD
380 std::unique_ptr<WWidget> Home::quoteForm()
381 {
382  auto result = std::make_unique<WContainerWidget>();
383  result->setStyleClass("quote");
384 
385  WTemplate *requestTemplate =
386  result->addWidget(std::make_unique<WTemplate>(tr("quote.request")));
387 
388  auto quoteButton = std::make_unique<WPushButton>(tr("quote.requestbutton"));
389  auto quoteButtonPtr = requestTemplate->bindWidget("button", std::move(quoteButton));
390 
391  auto quoteForm = result->addWidget(std::move(createQuoteForm()));
392 
393  quoteButtonPtr->clicked().connect(quoteForm, &WWidget::show);
394  quoteButtonPtr->clicked().connect(requestTemplate, &WWidget::hide);
395 
396  quoteForm->hide();
397 
398  return result;
399 }
400 #endif // WT_EMWEB_BUILD
401 
402 std::unique_ptr<WWidget> Home::download()
403 {
404  auto result = std::make_unique<WContainerWidget>();
405  result->addWidget(std::make_unique<WText>(tr("home.download")));
406 
407  result->addWidget(std::make_unique<WText>(tr("home.download.license")));
408 
409 #ifdef WT_EMWEB_BUILD
410  result->addWidget(std::move(quoteForm()));
411 #endif // WT_EMWEB_BUILD
412 
413  result->addWidget(std::make_unique<WText>(tr("home.download.packages")));
414 
415  auto releases = std::make_unique<WTable>();
416  readReleases(releases.get());
417  releases_ = result->addWidget(std::move(releases));
418 
419  result->addWidget(std::make_unique<WText>(tr("home.download.other")));
420 
421  return std::move(result);
422 }
423 
424 
425 WString Home::tr(const char *key)
426 {
427  return WString::tr(key);
428 }
429 
431 {
432  doJavaScript("if (window.ga) ga('send','pageview',"
433  + WWebWidget::jsStringLiteral(environment().deploymentPath()
434  + internalPath()) + ");");
435 }
436 
static const std::string SRC_INTERNAL_PATH
Definition: Home.C:34
std::unique_ptr< DeferredWidget< Function > > deferCreate(Function f)
Definition: Home.h:62
Definition: Home.h:68
std::unique_ptr< WWidget > blog()
Definition: Home.C:260
void setup()
Definition: Home.C:74
std::unique_ptr< WWidget > community()
Definition: Home.C:324
std::unique_ptr< WWidget > linkSourceBrowser(const std::string &examplePath)
Definition: Home.C:202
std::unique_ptr< WWidget > quoteForm()
void createHome()
Definition: Home.C:114
std::unique_ptr< WWidget > download()
Definition: Home.C:402
Home(const WEnvironment &env, Dbo::SqlConnectionPool &blogDb, const std::string &title, const std::string &resourceBundle, const std::string &cssPath)
Definition: Home.C:40
WTable * releases_
Definition: Home.h:94
WTabWidget * examplesMenu_
Definition: Home.h:89
void googleAnalyticsLogger()
Definition: Home.C:430
std::string href(const std::string &url, const std::string &description)
Definition: Home.C:319
std::unique_ptr< WWidget > wrapView(std::unique_ptr< WWidget >(Home::*createFunction)())
Definition: Home.C:314
int language_
Definition: Home.h:118
std::unique_ptr< WWidget > otherLanguage()
Definition: Home.C:309
void setLanguage(int language)
Definition: Home.C:183
WWidget * homePage_
Definition: Home.h:99
std::unique_ptr< WWidget > documentation()
Definition: Home.C:301
void init()
Definition: Home.C:63
void updateTitle()
Definition: Home.C:237
Dbo::SqlConnectionPool & blogDb_
Definition: Home.h:98
virtual ~Home()
Definition: Home.C:36
WString tr(const char *key)
Definition: Home.C:425
virtual std::string filePrefix() const =0
WWidget * sourceViewer_
Definition: Home.h:100
std::unique_ptr< WWidget > features()
Definition: Home.C:296
virtual std::unique_ptr< WWidget > sourceViewer(const std::string &deployPath)=0
WMenu * mainMenu_
Definition: Home.h:116
void readReleases(WTable *releaseTable)
Definition: Home.C:329
std::unique_ptr< WContainerWidget > sideBarContent_
Definition: Home.h:131
std::unique_ptr< WWidget > status()
Definition: Home.C:291
void logInternalPath(const std::string &path)
Definition: Home.C:244
std::vector< Lang > languages
Definition: Home.h:133
virtual std::unique_ptr< WWidget > createQuoteForm()=0
void setLanguageFromPath()
Definition: Home.C:215
std::unique_ptr< WWidget > introduction()
Definition: Home.C:255
void chatSetUser(const WString &name)
Definition: Home.C:277
virtual std::unique_ptr< WWidget > examples()=0
virtual Wt::Signals::connection connect(WObject *target, WObject::Method method) override
WWidget * findWidget(const std::string &name)
void doJavaScript(const std::string &javascript, bool afterLoaded=true)
std::string internalPath() const
WContainerWidget * root() const
const WString & title() const
WMessageResourceBundle & messageResourceBundle()
Signal< std::string > & internalPathChanged()
std::string internalPathNextPart(const std::string &path) const
void setTitle(const WString &title)
static std::string appRoot()
void useStyleSheet(const WLink &link, const std::string &media="all")
WLogEntry log(const std::string &type) const
std::string url(const std::string &internalPath=std::string()) const
const WEnvironment & environment() const
void setLocale(const WLocale &locale)
virtual void clear()
void setLayout(std::unique_ptr< WLayout > layout)
virtual void addWidget(std::unique_ptr< WWidget > widget)
virtual void setPathComponent(const std::string &path)
WString text() const
Signal< WMenuItem * > & itemSelected()
WMenuItem * addItem(const WString &label, std::unique_ptr< WWidget > contents=nullptr, ContentLoading policy=ContentLoading::Lazy)
Signal< WMenuItem * > & itemSelectRendered()
WMenuItem * currentItem() const
void setInternalBasePath(const std::string &basePath)
void setInternalPathEnabled(const std::string &basePath="")
void use(const std::string &path, bool loadInMemory=true)
std::unique_ptr< WObject > removeChild(WObject *child)
std::string jsStringLiteral(char delimiter='\'') const
void setInternalBasePath(const std::string &path)
virtual void clear()
WTableCell * elementAt(int row, int column)
virtual void bindWidget(const std::string &varName, std::unique_ptr< WWidget > widget)
virtual void resize(const WLength &width, const WLength &height) override
std::unique_ptr< Wt::WApplication > createWidget(const Wt::WEnvironment &env, SimpleChatServer &server)
Definition: simpleChat.C:148
Definition: Home.h:23
std::string longDescription_
Definition: Home.h:33
std::string code_
Definition: Home.h:33
std::string path_
Definition: Home.h:33