Wt examples  3.3.0
/home/koen/project/wt/public-git/wt/examples/wt-homepage/Home.C
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008 Emweb bvba, Kessel-Lo, Belgium.
00003  *
00004  * See the LICENSE file for terms of use.
00005  */
00006 
00007 #include <fstream>
00008 #include <iostream>
00009 
00010 #include <boost/lexical_cast.hpp>
00011 #include <boost/tokenizer.hpp>
00012 #include <boost/algorithm/string.hpp>
00013 
00014 #include <Wt/WAnchor>
00015 #include <Wt/WApplication>
00016 #include <Wt/WEnvironment>
00017 #include <Wt/WLogger>
00018 #include <Wt/WMenu>
00019 #include <Wt/WPushButton>
00020 #include <Wt/WStackedWidget>
00021 #include <Wt/WTabWidget>
00022 #include <Wt/WTable>
00023 #include <Wt/WTableCell>
00024 #include <Wt/WTemplate>
00025 #include <Wt/WText>
00026 #include <Wt/WViewWidget>
00027 #include <Wt/WVBoxLayout>
00028 
00029 #include "Home.h"
00030 #include "view/BlogView.h"
00031 
00032 static const std::string SRC_INTERNAL_PATH = "src";
00033 
00034 Home::~Home() 
00035 {
00036 }
00037 
00038 Home::Home(const WEnvironment& env, const std::string& title,
00039            const std::string& resourceBundle, const std::string& cssPath)
00040   : WApplication(env),
00041     releases_(0),
00042     homePage_(0),
00043     sourceViewer_(0)
00044 {
00045   messageResourceBundle().use(appRoot() + resourceBundle, false);
00046 
00047   useStyleSheet(cssPath + "/wt.css");
00048   useStyleSheet(cssPath + "/wt_ie.css", "lt IE 7");
00049   useStyleSheet("css/home.css");
00050   useStyleSheet("css/sourceview.css");
00051   useStyleSheet("css/chatwidget.css");
00052   useStyleSheet("css/chatwidget_ie6.css", "lt IE 7");
00053   setTitle(title);
00054 
00055   setLocale("");
00056   language_ = 0;
00057 }
00058 
00059 void Home::init()
00060 {
00061   internalPathChanged().connect(this, &Home::setup);
00062   internalPathChanged().connect(this, &Home::setLanguageFromPath);
00063   internalPathChanged().connect(this, &Home::logInternalPath);
00064 
00065   setup();
00066 
00067   setLanguageFromPath();
00068 }
00069 
00070 void Home::setup()
00071 {
00072   /*
00073    * This function switches between the two major components of the homepage,
00074    * depending on the internal path:
00075    * /src -> source viewer
00076    * /... -> homepage
00077    *
00078    * FIXME: we should take into account language /cn/src ...
00079    */
00080   std::string base = internalPathNextPart("/");
00081 
00082   if (base == SRC_INTERNAL_PATH) {
00083     if (!sourceViewer_) {
00084       delete homePage_;
00085       homePage_ = 0;
00086 
00087       root()->clear();
00088 
00089       sourceViewer_ = sourceViewer("/" + SRC_INTERNAL_PATH + "/");
00090       WVBoxLayout *layout = new WVBoxLayout();
00091       layout->setContentsMargins(0, 0, 0, 0);
00092       layout->addWidget(sourceViewer_);
00093       root()->setLayout(layout);
00094     }
00095   } else {
00096     if (!homePage_) {
00097       delete sourceViewer_;
00098       sourceViewer_ = 0;
00099 
00100       root()->clear();
00101 
00102       createHome();
00103       root()->addWidget(homePage_);
00104 
00105       setLanguageFromPath();
00106     }
00107   }
00108 }
00109 
00110 void Home::createHome()
00111 {
00112   WTemplate *result = new WTemplate(tr("template"), root());
00113   homePage_ = result;
00114 
00115   WContainerWidget *languagesDiv = new WContainerWidget();
00116   languagesDiv->setId("top_languages");
00117 
00118   for (unsigned i = 0; i < languages.size(); ++i) {
00119     if (i != 0)
00120       new WText("- ", languagesDiv);
00121 
00122     const Lang& l = languages[i];
00123 
00124     new WAnchor(WLink(WLink::InternalPath, l.path_),
00125                 WString::fromUTF8(l.longDescription_), languagesDiv);
00126   }
00127 
00128   WStackedWidget *contents = new WStackedWidget();
00129   WAnimation fade(WAnimation::Fade, WAnimation::Linear, 250);
00130   contents->setTransitionAnimation(fade);
00131   contents->setId("main_page");
00132 
00133   mainMenu_ = new WMenu(contents, Vertical);
00134 
00135   mainMenu_->addItem
00136     (tr("introduction"), introduction())->setPathComponent("");
00137 
00138   mainMenu_->addItem
00139     (tr("blog"), deferCreate(boost::bind(&Home::blog, this)));
00140 
00141   mainMenu_->addItem
00142     (tr("features"), wrapView(&Home::features), WMenuItem::PreLoading);
00143 
00144   mainMenu_->addItem
00145     (tr("documentation"), wrapView(&Home::documentation),
00146      WMenuItem::PreLoading);
00147 
00148   mainMenu_->addItem
00149     (tr("examples"), examples(),
00150      WMenuItem::PreLoading)->setPathComponent("examples/");
00151 
00152   mainMenu_->addItem
00153     (tr("download"), deferCreate(boost::bind(&Home::download, this)),
00154      WMenuItem::PreLoading);
00155 
00156   mainMenu_->addItem
00157     (tr("community"), wrapView(&Home::community), WMenuItem::PreLoading);
00158 
00159   mainMenu_->addItem
00160     (tr("other-language"), wrapView(&Home::otherLanguage),
00161      WMenuItem::PreLoading);
00162 
00163   mainMenu_->itemSelectRendered().connect(this, &Home::updateTitle);
00164 
00165   mainMenu_->itemSelected().connect(this, &Home::googleAnalyticsLogger);
00166 
00167   // Make the menu be internal-path aware.
00168   mainMenu_->setInternalPathEnabled("/");
00169 
00170   sideBarContent_ = new WContainerWidget();
00171 
00172   result->bindWidget("languages", languagesDiv);
00173   result->bindWidget("menu", mainMenu_);
00174   result->bindWidget("contents", contents);
00175   result->bindWidget("sidebar", sideBarContent_);
00176 }
00177 
00178 void Home::setLanguage(int index)
00179 {
00180   if (homePage_) {
00181     const Lang& l = languages[index];
00182 
00183     setLocale(l.code_);
00184 
00185     std::string langPath = l.path_;
00186     mainMenu_->setInternalBasePath(langPath);
00187     examplesMenu_->setInternalBasePath(langPath + "examples");
00188     BlogView *blog = dynamic_cast<BlogView *>(findWidget("blog"));
00189     if (blog)
00190       blog->setInternalBasePath(langPath + "blog/");
00191     updateTitle();
00192 
00193     language_ = index;
00194   }
00195 }
00196 
00197 WWidget *Home::linkSourceBrowser(const std::string& example)
00198 {
00199   /*
00200    * Instead of using a WAnchor, which will not progress properly because
00201    * it is wrapped with wrapView() (-- should we not fix that?), we use
00202    * a WText which contains an anchor, and enable internal path encoding.
00203    */
00204   std::string path = "#/" + SRC_INTERNAL_PATH + "/" + example;
00205   WText *a = new WText(tr("source-browser-link").arg(path));
00206   a->setInternalPathEncoding(true);
00207   return a;
00208 }
00209 
00210 void Home::setLanguageFromPath()
00211 {
00212   std::string langPath = internalPathNextPart("/");
00213 
00214   if (langPath.empty())
00215     langPath = '/';
00216   else
00217     langPath = '/' + langPath + '/';
00218 
00219   int newLanguage = 0;
00220 
00221   for (unsigned i = 0; i < languages.size(); ++i) {
00222     if (languages[i].path_ == langPath) {
00223       newLanguage = i;
00224       break;
00225     }
00226   }
00227 
00228   if (newLanguage != language_)
00229     setLanguage(newLanguage);
00230 }
00231 
00232 void Home::updateTitle()
00233 {
00234   if (mainMenu_->currentItem()) {
00235     setTitle(tr("wt") + " - " + mainMenu_->currentItem()->text());
00236   }
00237 }
00238 
00239 void Home::logInternalPath(const std::string& path)
00240 {
00241   // simulate an access log for the interal paths
00242   log("path") << path;
00243 
00244   // If this goes to /src, we need to invoke google analytics method too
00245   if (path.size() >= 4 && path.substr(0, 4) == "/src") {
00246     googleAnalyticsLogger();
00247   }
00248 }
00249 
00250 WWidget *Home::introduction()
00251 {
00252   return new WText(tr("home.intro"));
00253 }
00254 
00255 WWidget *Home::blog()
00256 {
00257   const Lang& l = languages[language_];
00258   std::string langPath = l.path_;
00259   BlogView *blog = new BlogView(langPath + "blog/",
00260                                 appRoot() + "blog.db", "/wt/blog/feed/");
00261   blog->setObjectName("blog");
00262 
00263   if (!blog->user().empty())
00264     chatSetUser(blog->user());
00265 
00266   blog->userChanged().connect(this, &Home::chatSetUser);
00267 
00268   return blog;
00269 }
00270 
00271 void Home::chatSetUser(const WString& userName)
00272 {
00273   WApplication::instance()->doJavaScript
00274     ("if (window.chat && window.chat.emit) {"
00275      """try {"
00276      ""  "window.chat.emit(window.chat, 'login', "
00277      ""                    "" + userName.jsStringLiteral() + "); "
00278      """} catch (e) {"
00279      ""  "window.chatUser=" + userName.jsStringLiteral() + ";"
00280      """}"
00281      "} else "
00282      """window.chatUser=" + userName.jsStringLiteral() + ";");
00283 }
00284 
00285 WWidget *Home::status()
00286 {
00287   return new WText(tr("home.status"));
00288 }
00289 
00290 WWidget *Home::features()
00291 {
00292   return new WText(tr("home.features"));
00293 }
00294 
00295 WWidget *Home::documentation()
00296 {
00297   WText *result = new WText(tr("home.documentation"));
00298   result->setInternalPathEncoding(true);
00299   return result;
00300 }
00301 
00302 WWidget *Home::otherLanguage()
00303 {
00304   return new WText(tr("home.other-language"));
00305 }
00306 
00307 WWidget *Home::wrapView(WWidget *(Home::*createWidget)())
00308 {
00309   return makeStaticModel(boost::bind(createWidget, this));
00310 }
00311 
00312 std::string Home::href(const std::string& url, const std::string& description)
00313 {
00314   return "<a href=\"" + url + "\" target=\"_blank\">" + description + "</a>";
00315 }
00316 
00317 WWidget *Home::community()
00318 {
00319   return new WText(tr("home.community"));
00320 }
00321 
00322 void Home::readReleases(WTable *releaseTable)
00323 {
00324   std::ifstream f((filePrefix() + "releases.txt").c_str());
00325 
00326   releaseTable->clear();
00327 
00328   releaseTable->elementAt(0, 0)
00329     ->addWidget(new WText(tr("home.download.version")));
00330   releaseTable->elementAt(0, 1)
00331     ->addWidget(new WText(tr("home.download.date")));
00332   releaseTable->elementAt(0, 2)
00333     ->addWidget(new WText(tr("home.download.description")));
00334 
00335   releaseTable->elementAt(0, 0)->resize(WLength(15, WLength::FontEx),
00336                                         WLength::Auto);
00337   releaseTable->elementAt(0, 1)->resize(WLength(15, WLength::FontEx),
00338                                         WLength::Auto);
00339 
00340   int row = 1;
00341 
00342   while (f) {
00343     std::string line;
00344     getline(f, line);
00345 
00346     if (f) {
00347       typedef boost::tokenizer<boost::escaped_list_separator<char> >
00348         CsvTokenizer;
00349       CsvTokenizer tok(line);
00350 
00351       CsvTokenizer::iterator i=tok.begin();
00352 
00353       std::string fileName = *i;
00354       std::string description = *(++i);
00355       releaseTable->elementAt(row, 0)->addWidget
00356         (new WText(href("http://prdownloads.sourceforge.net/witty/" 
00357                         + fileName + "?download", description)));
00358       releaseTable->elementAt(row, 1)->addWidget(new WText(*(++i)));
00359       releaseTable->elementAt(row, 2)->addWidget(new WText(*(++i)));
00360 
00361       ++row;
00362     }
00363   }
00364 }
00365 
00366 #ifdef WT_EMWEB_BUILD
00367 WWidget *Home::quoteForm()
00368 {
00369   WContainerWidget *result = new WContainerWidget();
00370   result->setStyleClass("quote");
00371 
00372   WTemplate *requestTemplate = new WTemplate(tr("quote.request"), result);
00373 
00374   WPushButton *quoteButton = new WPushButton(tr("quote.requestbutton"));
00375   requestTemplate->bindWidget("button", quoteButton);
00376 
00377   WWidget *quoteForm = createQuoteForm();
00378   result->addWidget(quoteForm);
00379 
00380   quoteButton->clicked().connect(quoteForm, &WWidget::show);
00381   quoteButton->clicked().connect(requestTemplate, &WWidget::hide);
00382 
00383   quoteForm->hide();
00384 
00385   return result;
00386 }
00387 #endif // WT_EMWEB_BUILD
00388 
00389 WWidget *Home::download()
00390 {
00391   WContainerWidget *result = new WContainerWidget();
00392   result->addWidget(new WText(tr("home.download")));
00393 
00394   result->addWidget(new WText(tr("home.download.license")));
00395 
00396 #ifdef WT_EMWEB_BUILD
00397   result->addWidget(quoteForm());
00398 #endif // WT_EMWEB_BUILD
00399 
00400   result->addWidget(new WText(tr("home.download.packages")));
00401 
00402   releases_ = new WTable();
00403   readReleases(releases_);
00404   result->addWidget(releases_);
00405 
00406   result->addWidget(new WText(tr("home.download.other")));
00407 
00408   return result;
00409 }
00410 
00411 
00412 WString Home::tr(const char *key)
00413 {
00414   return WString::tr(key);
00415 }
00416 
00417 void Home::googleAnalyticsLogger()
00418 {
00419   std::string googleCmd = 
00420     "if (window.pageTracker) {"
00421     """try {"
00422     ""  "setTimeout(function() {"
00423     ""  "window.pageTracker._trackPageview(\""
00424     + environment().deploymentPath() + internalPath() + "\");"
00425     ""  "}, 1000);"
00426     """} catch (e) { }"
00427     "}";
00428 
00429   doJavaScript(googleCmd);
00430 }
00431 

Generated on Mon Apr 8 2013 for the C++ Web Toolkit (Wt) by doxygen 1.7.5.1