Home.C 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. /*
  2. * Copyright (C) 2008 Emweb bvba, Kessel-Lo, Belgium.
  3. *
  4. * See the LICENSE file for terms of use.
  5. */
  6. #include <fstream>
  7. #include <iostream>
  8. #include <boost/lexical_cast.hpp>
  9. #include <boost/tokenizer.hpp>
  10. #include <boost/algorithm/string.hpp>
  11. #include <Wt/WAnchor>
  12. #include <Wt/WApplication>
  13. #include <Wt/WEnvironment>
  14. #include <Wt/WLogger>
  15. #include <Wt/WMenu>
  16. #include <Wt/WPushButton>
  17. #include <Wt/WStackedWidget>
  18. #include <Wt/WTabWidget>
  19. #include <Wt/WTable>
  20. #include <Wt/WTableCell>
  21. #include <Wt/WTemplate>
  22. #include <Wt/WText>
  23. #include <Wt/WViewWidget>
  24. #include <Wt/WVBoxLayout>
  25. #include "Home.h"
  26. #include "view/BlogView.h"
  27. static const std::string SRC_INTERNAL_PATH = "src";
  28. Home::~Home()
  29. {
  30. }
  31. Home::Home(const WEnvironment& env,
  32. Wt::Dbo::SqlConnectionPool& blogDb,
  33. const std::string& title, const std::string& resourceBundle,
  34. const std::string& cssPath)
  35. : WApplication(env),
  36. releases_(0),
  37. blogDb_(blogDb),
  38. homePage_(0),
  39. sourceViewer_(0)
  40. {
  41. messageResourceBundle().use(appRoot() + resourceBundle, false);
  42. useStyleSheet(cssPath + "/wt.css");
  43. useStyleSheet(cssPath + "/wt_ie.css", "lt IE 7", "all");
  44. useStyleSheet("css/home.css");
  45. useStyleSheet("css/sourceview.css");
  46. useStyleSheet("css/chatwidget.css");
  47. useStyleSheet("css/chatwidget_ie6.css", "lt IE 7", "all");
  48. setTitle(title);
  49. setLocale("");
  50. language_ = 0;
  51. }
  52. void Home::init()
  53. {
  54. internalPathChanged().connect(this, &Home::setup);
  55. internalPathChanged().connect(this, &Home::setLanguageFromPath);
  56. internalPathChanged().connect(this, &Home::logInternalPath);
  57. setup();
  58. setLanguageFromPath();
  59. }
  60. void Home::setup()
  61. {
  62. /*
  63. * This function switches between the two major components of the homepage,
  64. * depending on the internal path:
  65. * /src -> source viewer
  66. * /... -> homepage
  67. *
  68. * FIXME: we should take into account language /cn/src ...
  69. */
  70. std::string base = internalPathNextPart("/");
  71. if (base == SRC_INTERNAL_PATH) {
  72. if (!sourceViewer_) {
  73. delete homePage_;
  74. homePage_ = 0;
  75. root()->clear();
  76. sourceViewer_ = sourceViewer("/" + SRC_INTERNAL_PATH + "/");
  77. WVBoxLayout *layout = new WVBoxLayout();
  78. layout->setContentsMargins(0, 0, 0, 0);
  79. layout->addWidget(sourceViewer_);
  80. root()->setLayout(layout);
  81. }
  82. } else {
  83. if (!homePage_) {
  84. delete sourceViewer_;
  85. sourceViewer_ = 0;
  86. root()->clear();
  87. createHome();
  88. root()->addWidget(homePage_);
  89. setLanguageFromPath();
  90. }
  91. }
  92. }
  93. void Home::createHome()
  94. {
  95. WTemplate *result = new WTemplate(tr("template"), root());
  96. homePage_ = result;
  97. WContainerWidget *languagesDiv = new WContainerWidget();
  98. languagesDiv->setId("top_languages");
  99. for (unsigned i = 0; i < languages.size(); ++i) {
  100. if (i != 0)
  101. new WText("- ", languagesDiv);
  102. const Lang& l = languages[i];
  103. new WAnchor(WLink(WLink::InternalPath, l.path_),
  104. WString::fromUTF8(l.longDescription_), languagesDiv);
  105. }
  106. WStackedWidget *contents = new WStackedWidget();
  107. WAnimation fade(WAnimation::Fade, WAnimation::Linear, 250);
  108. contents->setTransitionAnimation(fade);
  109. contents->setId("main_page");
  110. mainMenu_ = new WMenu(contents, Vertical);
  111. mainMenu_->addItem
  112. (tr("introduction"), introduction())->setPathComponent("");
  113. mainMenu_->addItem
  114. (tr("blog"), deferCreate(boost::bind(&Home::blog, this)));
  115. mainMenu_->addItem
  116. (tr("features"), wrapView(&Home::features), WMenuItem::PreLoading);
  117. mainMenu_->addItem
  118. (tr("documentation"), wrapView(&Home::documentation),
  119. WMenuItem::PreLoading);
  120. mainMenu_->addItem
  121. (tr("examples"), examples(),
  122. WMenuItem::PreLoading)->setPathComponent("examples/");
  123. mainMenu_->addItem
  124. (tr("download"), deferCreate(boost::bind(&Home::download, this)),
  125. WMenuItem::PreLoading);
  126. mainMenu_->addItem
  127. (tr("community"), wrapView(&Home::community), WMenuItem::PreLoading);
  128. mainMenu_->addItem
  129. (tr("other-language"), wrapView(&Home::otherLanguage),
  130. WMenuItem::PreLoading);
  131. mainMenu_->itemSelectRendered().connect(this, &Home::updateTitle);
  132. mainMenu_->itemSelected().connect(this, &Home::googleAnalyticsLogger);
  133. // Make the menu be internal-path aware.
  134. mainMenu_->setInternalPathEnabled("/");
  135. sideBarContent_ = new WContainerWidget();
  136. result->bindWidget("languages", languagesDiv);
  137. result->bindWidget("menu", mainMenu_);
  138. result->bindWidget("contents", contents);
  139. result->bindWidget("sidebar", sideBarContent_);
  140. }
  141. void Home::setLanguage(int index)
  142. {
  143. if (homePage_) {
  144. const Lang& l = languages[index];
  145. setLocale(l.code_);
  146. std::string langPath = l.path_;
  147. mainMenu_->setInternalBasePath(langPath);
  148. examplesMenu_->setInternalBasePath(langPath + "examples");
  149. BlogView *blog = dynamic_cast<BlogView *>(findWidget("blog"));
  150. if (blog)
  151. blog->setInternalBasePath(langPath + "blog/");
  152. updateTitle();
  153. language_ = index;
  154. }
  155. }
  156. WWidget *Home::linkSourceBrowser(const std::string& example)
  157. {
  158. /*
  159. * Instead of using a WAnchor, which will not progress properly because
  160. * it is wrapped with wrapView() (-- should we not fix that?), we use
  161. * a WText which contains an anchor, and enable internal path encoding.
  162. */
  163. std::string path = "#/" + SRC_INTERNAL_PATH + "/" + example;
  164. WText *a = new WText(tr("source-browser-link").arg(path));
  165. a->setInternalPathEncoding(true);
  166. return a;
  167. }
  168. void Home::setLanguageFromPath()
  169. {
  170. std::string langPath = internalPathNextPart("/");
  171. if (langPath.empty())
  172. langPath = '/';
  173. else
  174. langPath = '/' + langPath + '/';
  175. int newLanguage = 0;
  176. for (unsigned i = 0; i < languages.size(); ++i) {
  177. if (languages[i].path_ == langPath) {
  178. newLanguage = i;
  179. break;
  180. }
  181. }
  182. if (newLanguage != language_)
  183. setLanguage(newLanguage);
  184. }
  185. void Home::updateTitle()
  186. {
  187. if (mainMenu_->currentItem()) {
  188. setTitle(tr("wt") + " - " + mainMenu_->currentItem()->text());
  189. }
  190. }
  191. void Home::logInternalPath(const std::string& path)
  192. {
  193. // simulate an access log for the interal paths
  194. log("path") << path;
  195. // If this goes to /src, we need to invoke google analytics method too
  196. if (path.size() >= 4 && path.substr(0, 4) == "/src") {
  197. googleAnalyticsLogger();
  198. }
  199. }
  200. WWidget *Home::introduction()
  201. {
  202. return new WText(tr("home.intro"));
  203. }
  204. WWidget *Home::blog()
  205. {
  206. const Lang& l = languages[language_];
  207. std::string langPath = l.path_;
  208. BlogView *blog = new BlogView(langPath + "blog/",
  209. blogDb_, "/wt/blog/feed/");
  210. blog->setObjectName("blog");
  211. if (!blog->user().empty())
  212. chatSetUser(blog->user());
  213. blog->userChanged().connect(this, &Home::chatSetUser);
  214. return blog;
  215. }
  216. void Home::chatSetUser(const WString& userName)
  217. {
  218. WApplication::instance()->doJavaScript
  219. ("if (window.chat && window.chat.emit) {"
  220. """try {"
  221. "" "window.chat.emit(window.chat, 'login', "
  222. "" "" + userName.jsStringLiteral() + "); "
  223. """} catch (e) {"
  224. "" "window.chatUser=" + userName.jsStringLiteral() + ";"
  225. """}"
  226. "} else "
  227. """window.chatUser=" + userName.jsStringLiteral() + ";");
  228. }
  229. WWidget *Home::status()
  230. {
  231. return new WText(tr("home.status"));
  232. }
  233. WWidget *Home::features()
  234. {
  235. return new WText(tr("home.features"));
  236. }
  237. WWidget *Home::documentation()
  238. {
  239. WText *result = new WText(tr("home.documentation"));
  240. result->setInternalPathEncoding(true);
  241. return result;
  242. }
  243. WWidget *Home::otherLanguage()
  244. {
  245. return new WText(tr("home.other-language"));
  246. }
  247. WWidget *Home::wrapView(WWidget *(Home::*createWidget)())
  248. {
  249. return makeStaticModel(boost::bind(createWidget, this));
  250. }
  251. std::string Home::href(const std::string& url, const std::string& description)
  252. {
  253. return "<a href=\"" + url + "\" target=\"_blank\">" + description + "</a>";
  254. }
  255. WWidget *Home::community()
  256. {
  257. return new WText(tr("home.community"));
  258. }
  259. void Home::readReleases(WTable *releaseTable)
  260. {
  261. std::ifstream f((filePrefix() + "releases.txt").c_str());
  262. releaseTable->clear();
  263. releaseTable->elementAt(0, 0)
  264. ->addWidget(new WText(tr("home.download.version")));
  265. releaseTable->elementAt(0, 1)
  266. ->addWidget(new WText(tr("home.download.date")));
  267. releaseTable->elementAt(0, 2)
  268. ->addWidget(new WText(tr("home.download.description")));
  269. releaseTable->elementAt(0, 0)->resize(WLength(15, WLength::FontEx),
  270. WLength::Auto);
  271. releaseTable->elementAt(0, 1)->resize(WLength(15, WLength::FontEx),
  272. WLength::Auto);
  273. int row = 1;
  274. while (f) {
  275. std::string line;
  276. getline(f, line);
  277. if (f) {
  278. typedef boost::tokenizer<boost::escaped_list_separator<char> >
  279. CsvTokenizer;
  280. CsvTokenizer tok(line);
  281. CsvTokenizer::iterator i=tok.begin();
  282. std::string fileName = *i;
  283. std::string description = *(++i);
  284. releaseTable->elementAt(row, 1)->addWidget(new WText(*(++i)));
  285. releaseTable->elementAt(row, 2)->addWidget(new WText(*(++i)));
  286. ++i;
  287. std::string url = "http://prdownloads.sourceforge.net/witty/"
  288. + fileName + "?download";
  289. if (i != tok.end())
  290. url = *i;
  291. releaseTable->elementAt(row, 0)->addWidget
  292. (new WText(href(url, description)));
  293. ++row;
  294. }
  295. }
  296. }
  297. #ifdef WT_EMWEB_BUILD
  298. WWidget *Home::quoteForm()
  299. {
  300. WContainerWidget *result = new WContainerWidget();
  301. result->setStyleClass("quote");
  302. WTemplate *requestTemplate = new WTemplate(tr("quote.request"), result);
  303. WPushButton *quoteButton = new WPushButton(tr("quote.requestbutton"));
  304. requestTemplate->bindWidget("button", quoteButton);
  305. WWidget *quoteForm = createQuoteForm();
  306. result->addWidget(quoteForm);
  307. quoteButton->clicked().connect(quoteForm, &WWidget::show);
  308. quoteButton->clicked().connect(requestTemplate, &WWidget::hide);
  309. quoteForm->hide();
  310. return result;
  311. }
  312. #endif // WT_EMWEB_BUILD
  313. WWidget *Home::download()
  314. {
  315. WContainerWidget *result = new WContainerWidget();
  316. result->addWidget(new WText(tr("home.download")));
  317. result->addWidget(new WText(tr("home.download.license")));
  318. #ifdef WT_EMWEB_BUILD
  319. result->addWidget(quoteForm());
  320. #endif // WT_EMWEB_BUILD
  321. result->addWidget(new WText(tr("home.download.packages")));
  322. releases_ = new WTable();
  323. readReleases(releases_);
  324. result->addWidget(releases_);
  325. result->addWidget(new WText(tr("home.download.other")));
  326. return result;
  327. }
  328. WString Home::tr(const char *key)
  329. {
  330. return WString::tr(key);
  331. }
  332. void Home::googleAnalyticsLogger()
  333. {
  334. doJavaScript("if (window.ga) ga('send','pageview',"
  335. + WWebWidget::jsStringLiteral(environment().deploymentPath()
  336. + internalPath()) + ");");
  337. }