00001
00002
00003
00004
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 setTitle(title);
00052
00053 setLocale("");
00054 language_ = 0;
00055 }
00056
00057 void Home::init()
00058 {
00059 internalPathChanged().connect(this, &Home::setup);
00060 internalPathChanged().connect(this, &Home::setLanguageFromPath);
00061 internalPathChanged().connect(this, &Home::logInternalPath);
00062
00063 setup();
00064
00065 setLanguageFromPath();
00066 }
00067
00068 void Home::setup()
00069 {
00070
00071
00072
00073
00074
00075
00076
00077
00078 std::string base = internalPathNextPart("/");
00079
00080 if (base == SRC_INTERNAL_PATH) {
00081 if (!sourceViewer_) {
00082 delete homePage_;
00083 homePage_ = 0;
00084
00085 root()->clear();
00086
00087 sourceViewer_ = sourceViewer("/" + SRC_INTERNAL_PATH + "/");
00088 WVBoxLayout *layout = new WVBoxLayout();
00089 layout->setContentsMargins(0, 0, 0, 0);
00090 layout->addWidget(sourceViewer_);
00091 root()->setLayout(layout);
00092 }
00093 } else {
00094 if (!homePage_) {
00095 delete sourceViewer_;
00096 sourceViewer_ = 0;
00097
00098 root()->clear();
00099
00100 homePage_ = initHome();
00101 root()->addWidget(homePage_);
00102
00103 setLanguageFromPath();
00104 }
00105 }
00106 }
00107
00108 WWidget *Home::initHome()
00109 {
00110 WTemplate *result = new WTemplate(tr("template"), root());
00111
00112 WContainerWidget *languagesDiv = new WContainerWidget();
00113 languagesDiv->setId("top_languages");
00114
00115 for (unsigned i = 0; i < languages.size(); ++i) {
00116 if (i != 0)
00117 new WText("- ", languagesDiv);
00118
00119 const Lang& l = languages[i];
00120
00121 new WAnchor(WLink(WLink::InternalPath, l.path_),
00122 WString::fromUTF8(l.longDescription_), languagesDiv);
00123 }
00124
00125 WStackedWidget *contents = new WStackedWidget();
00126 WAnimation fade(WAnimation::Fade, WAnimation::Linear, 250);
00127 contents->setTransitionAnimation(fade);
00128 contents->setId("main_page");
00129
00130 mainMenu_ = new WMenu(contents, Vertical);
00131 mainMenu_->setRenderAsList(true);
00132
00133 mainMenu_->addItem
00134 (tr("introduction"), introduction())->setPathComponent("");
00135
00136 mainMenu_->addItem
00137 (tr("blog"), deferCreate(boost::bind(&Home::blog, this)));
00138
00139 mainMenu_->addItem
00140 (tr("features"), wrapView(&Home::features), WMenuItem::PreLoading);
00141
00142 mainMenu_->addItem
00143 (tr("documentation"), wrapView(&Home::documentation),
00144 WMenuItem::PreLoading);
00145
00146 mainMenu_->addItem
00147 (tr("examples"), examples(),
00148 WMenuItem::PreLoading)->setPathComponent("examples/");
00149
00150 mainMenu_->addItem
00151 (tr("download"), deferCreate(boost::bind(&Home::download, this)),
00152 WMenuItem::PreLoading);
00153
00154 mainMenu_->addItem
00155 (tr("community"), wrapView(&Home::community), WMenuItem::PreLoading);
00156
00157 mainMenu_->addItem
00158 (tr("other-language"), wrapView(&Home::otherLanguage),
00159 WMenuItem::PreLoading);
00160
00161 mainMenu_->itemSelectRendered().connect(this, &Home::updateTitle);
00162
00163 mainMenu_->itemSelected().connect(this, &Home::googleAnalyticsLogger);
00164
00165
00166 mainMenu_->setInternalPathEnabled("/");
00167
00168 sideBarContent_ = new WContainerWidget();
00169
00170 result->bindWidget("languages", languagesDiv);
00171 result->bindWidget("menu", mainMenu_);
00172 result->bindWidget("contents", contents);
00173 result->bindWidget("sidebar", sideBarContent_);
00174
00175 return result;
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
00201
00202
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
00242 log("path") << path;
00243
00244
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) "
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