Project

General

Profile

Feature #4898 » bugreport-statelessSlotRender.C

Saif Rehman, 05/23/2016 12:37 PM

 
#include <Wt/WApplication>
#include <Wt/WContainerWidget>
#include <Wt/WPushButton>
#include <Wt/WText>
#include <Wt/WBootstrapTheme>
#include <Wt/WProgressBar>
#include <Wt/WTemplate>
#include <Wt/WMenu>
#include <Wt/WStackedWidget>

using namespace Wt;

//My Classes
class Reloadable
{
public:
Reloadable() { }
virtual void reload() = 0;
};

template<class Base>
class ReloadOnVisibleWidget : public Base, public Reloadable
{
public:
ReloadOnVisibleWidget() { }

protected:
virtual void propagateSetVisible(bool visible) override;
virtual void render(Wt::WFlags<Wt::RenderFlag> flags) override;
bool _wasVisible = true;
};

class ReloadableProgress : public WProgressBar, public Reloadable
{
public:
ReloadableProgress(WContainerWidget *parent = nullptr) : WProgressBar(parent) { }
virtual void reload() override;
};

class ReloadableProgressTemplate : public Wt::WTemplate, public Reloadable
{
public:
ReloadableProgressTemplate(WContainerWidget *parent);
virtual void reload() override;

protected:
Wt::WText *_text = nullptr;
};

class ReloadableContainer : public ReloadOnVisibleWidget<Wt::WContainerWidget>
{
public:
virtual void reload() override
{
//isNotStateless(); doesnt work either; already called previously on the call stack in ReloadOnVisibleWidget::render
for(auto w : children())
{
if(auto rW = dynamic_cast<Reloadable*>(w))
rW->reload();
}
}
};

class HelloApplication : public WApplication
{
public:
HelloApplication(const WEnvironment& env);
};

//APPLICATION LOGIC
HelloApplication::HelloApplication(const WEnvironment& env)
: WApplication(env)
{
setTitle("Bug when reloading within render() during a learned slot event");

//Irrelevant
auto theme = new WBootstrapTheme();
theme->setVersion(WBootstrapTheme::Version3);
setTheme(theme);

//WMenu with stacked widget change currentWidget using a learned slot
Wt::WStackedWidget *stack = new Wt::WStackedWidget();
auto menu = new WMenu(stack, root());
root()->addWidget(stack);

//Every Reloadable object's reload() is called when it becomes visible again
auto reloadableContainer = new ReloadableContainer();
menu->addItem("ReloadableContainer", reloadableContainer);
(new ReloadableProgress(reloadableContainer))->setInline(false);
new ReloadableProgressTemplate(reloadableContainer);

//Just to hide reloadableContainer
menu->addItem("Empty", new WContainerWidget());
}

//MAIN
WApplication *createApplication(const WEnvironment& env) { return new HelloApplication(env); }
int main(int argc, char **argv)
{
return WRun(argc, argv, &createApplication);
}

//FUCNTION DEFINITIONS
template<class Base>
void ReloadOnVisibleWidget<Base>::propagateSetVisible(bool visible)
{
scheduleRender();
Base::propagateSetVisible(visible);
}

template<class Base>
void ReloadOnVisibleWidget<Base>::render(Wt::WFlags<Wt::RenderFlag> flags)
{
if(canOptimizeUpdates() && (flags & Wt::RenderFull) == 0)
{
bool visible = isVisible();
if(visible && !_wasVisible)
{
isNotStateless();
reload();
}

_wasVisible = visible;
}

Base::render(flags);
}

ReloadableProgressTemplate::ReloadableProgressTemplate(WContainerWidget *parent)
: WTemplate(parent)
{
setTemplateText(
"<div class=\"progress\">"
"${progress-bar class=\"progress-bar\"}"
"</div>"
);

auto container = new Wt::WContainerWidget();
container->setWidth(Wt::WLength(0, Wt::WLength::Percentage));
_text = new Wt::WText("0%", container);
bindWidget("progress-bar", container);
}

void ReloadableProgressTemplate::reload()
{
auto container = resolveWidget("progress-bar");
container->setWidth(Wt::WLength(container->width().value() + 5, WLength::Percentage));
_text->setText(container->width().cssText());
Wt::log("warn") << "ReloadableProgressTemplate::reload(): " << _text->text();
}

void ReloadableProgress::reload()
{
setValue(value() + 5);
Wt::log("warn") << "ReloadableProgress::reload(): " << value() << "%";
}
(3-3/3)