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