Wt examples
3.3.0
|
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