I want a Menu item to be set to some default data, then have a combo box change 
the data from a server side call back based on the value of the combo box or 
URL.


Since I could not find a way to change the data that is already loaded
on the page, using my example of a Dynamic Menu, I want to find another
method that will do the same job.

Dynamic content needs to change based on combo boxes or URL as in
example attached, the data itself can be anything, but will be properly
formatted HTML that only needs to replace what is already in the default
data tag, as such I have a Template:

<div id="main_content" class="panel">
    <div id="content" class="panel-body">
         ${contents}
    </div>
</div>

which gets bound in App::create_menu():
result->bindWidget("contents", contents); // Binding to content

I bind it to the default data based on the combo boxes or URL, then on a change 
to the combo boxes or URL, I do a server side call back to fetch the new data 
and display it.

Sorry but I don't know how to explain this any better.

For a lack of a better name, I call this Dynamic Menu.

Thanks
#include <iostream>
#include <fstream>
#include <boost/lexical_cast.hpp>
#include <boost/tokenizer.hpp>
#include <boost/algorithm/string.hpp>
#include <Wt/WApplication>
#include <Wt/WMenu>
#include <Wt/WMenuItem>
#include <Wt/WPopupMenu>
#include <Wt/WStackedWidget>
#include <Wt/WText>
#include <Wt/WBootstrapTheme>
#include <Wt/WTemplate>
#include <Wt/WNavigationBar>
#include <Wt/WComboBox>
#include <Wt/WVideo>
#include <Wt/WImage>
#include <Wt/WLineEdit>
/* ****************************************************************************
 * DeferredWidget
 * A utility container widget which defers creation of its single
 * child widget until the container is loaded (which is done on-demand by a WMenu).
 * The constructor takes the create function for the widget as a parameter.
 * We use this to defer widget creation until needed.
 */
template <typename Function>
class DeferredWidget : public Wt::WContainerWidget
{
    public:
        DeferredWidget(Function f) : f_(f) { }
    private:
        void load() { Wt::WContainerWidget::load(); if (count() == 0) { addWidget(f_()); } }
        Function f_;
};
template <typename Function>
DeferredWidget<Function> *deferCreate(Function f)
{
    return new DeferredWidget<Function>(f);
}
/* ****************************************************************************
 * App
 */
class App : public Wt::WApplication
{
    public:
        App(const Wt::WEnvironment& e);
    protected:
        Wt::WString tr(const char *key);
    private:
        Wt::WWidget *homePage_;
        void create_menu();
        Wt::WWidget *Statically();
        Wt::WWidget *Dynamically();
        //
        void logInternalPath(const std::string& path);
        void categoryComboChanged();
        void messageComboChanged();
        //
        Wt::WComboBox *categoryCombo;
        Wt::WComboBox *messageCombo;
        Wt::WStackedWidget *contents;
        //
        bool isComboBoxInit=false;
        bool bindMessage = false;
        bool isChanged=false;
};
/* ****************************************************************************
 * App Contructor
 */
App::App(const Wt::WEnvironment& e) : Wt::WApplication(e)
{
    messageResourceBundle().use(appRoot() + "dynamic-menu", false);
    setTheme(new Wt::WBootstrapTheme());
    internalPathChanged().connect(this, &App::logInternalPath);
    create_menu();
}
/* ****************************************************************************
 * create_menu
 */
void App::create_menu()
{
    Wt::WTemplate *result = new Wt::WTemplate(tr("template"), root()); //  <message id="template">
    homePage_ = result;
    // Create private contents
    contents = new Wt::WStackedWidget();
    Wt::WAnimation fade(Wt::WAnimation::Fade, Wt::WAnimation::Linear, 250);
    contents->setTransitionAnimation(fade);
    contents->setId("main_page");
    // Create a navigation bar with a link to a web page.
    Wt::WNavigationBar *navigation = new Wt::WNavigationBar(contents);
    navigation->setTitle("Witty Wizard");
    // Create contentsStack
    Wt::WStackedWidget *contentsStack = new Wt::WStackedWidget(contents);
    //contentsStack->setId("contents");
    contentsStack->addStyleClass("contents");
    // Setup a Main menu.
    Wt::WMenu *mainMenu_ = new Wt::WMenu(contentsStack, contents);
    mainMenu_->setId("mainmenu");
    navigation->addMenu(mainMenu_);
    // Add two menu items for example
    mainMenu_->addItem(tr("static"),  Statically())->setPathComponent("");
    mainMenu_->addItem(tr("dynamic"),  deferCreate(boost::bind(&App::Dynamically, this)));
    // add contents to contentsStack
    contents->addWidget(contentsStack);
    // Make the menu is internal-path aware.
    mainMenu_->setInternalPathEnabled("/");
    // Bind to Template
    result->bindWidget("menu", navigation);
    result->bindWidget("contents", contents);
}
/* ****************************************************************************
 * Dynamically based on URL or Comoboxes
 * I want to be able to bookmark a message based on Category and Message ID
 * I want URL pattern /dynamic/categoryNumber/messageNumber to control Combo box
 */
Wt::WWidget *App::Dynamically()
{
    Wt::log("notice") << "( *** run function Dynamically *** " << ")";
    std::string message_ = "default-0";
    Wt::WContainerWidget *result = new Wt::WContainerWidget();
    // Check to see if Combo Box has been initalized
    if (!isComboBoxInit)
    {
        categoryCombo = new Wt::WComboBox(result);
        categoryCombo->addItem("Default");
        categoryCombo->addItem("Extra");
        categoryCombo->setCurrentIndex(0);
        categoryCombo->activated().connect(this, &App::categoryComboChanged);

        messageCombo = new Wt::WComboBox(result);
        messageCombo->addItem("Default 0");
        messageCombo->addItem("Default 1");
        messageCombo->addItem("Default 2");
        messageCombo->setCurrentIndex(0); // Trailer
        messageCombo->activated().connect(this, &App::messageComboChanged);
        isComboBoxInit = true;
    }
    // Check internal Path and Set Combo Box
    WApplication* app = WApplication::instance();
    std::string categoryNumber = app->internalPathNextPart("/dynamic/");
    if (!categoryNumber.empty())
    {
        if (categoryCombo->currentIndex() != std::stoi(categoryNumber))
        {
            // FIX add boundry test
            isChanged = true; // Prevent Combo Box from updating internalPath
            Wt::log("notice") << "(categoryCombo: " << categoryNumber << ")";
            categoryCombo->setCurrentIndex(std::stoi(categoryNumber));
            categoryComboChanged(); // Rebuild list in combo box
        }
        std::string messageNumber = app->internalPathNextPart("/dynamic/" + categoryNumber + "/");
        if (!messageNumber.empty())
        {
            if (messageCombo->currentIndex() != std::stoi(messageNumber))
            {
                // FIX add boundry test
                isChanged = true; // Prevent Combo Box from updating internalPath
                Wt::log("notice") << "(messageCombo: " << messageNumber << ")";
                messageCombo->setCurrentIndex(std::stoi(messageNumber));
            }
        }
        isChanged = false; // Allow Combo Box to update internalPath
    }
    // Set content based on Combo boxes, based on URL internal path /dynamic/categoryNumber/messageNumber if set
    if (categoryCombo->currentIndex() == 0)
    {
        switch (messageCombo->currentIndex())
        {
            case 0:
                message_ = "default-0";
                break;
            case 1:
                message_ = "default-1";
                break;
            case 2:
                message_ = "default-2";
                break;
        }
    }
    else if (categoryCombo->currentIndex() == 1)
    {
        switch (messageCombo->currentIndex())
        {
            case 0:
                message_ = "extra-0";
                break;
            case 1:
                message_ = "extra-1";
                break;
            case 2:
                message_ = "extra-2";
                break;
            case 3:
                message_ = "extra-3";
                break;
        }
    }
    // Dynamic content based on message ID
    new Wt::WText(Wt::WString::tr(message_), result);
    /* It seems that I need a referance to bind to contents in the stack
     * so I made Wt::WStackedWidget *contents private
     * or do I do this after return?
     */
    if (bindMessage)
    {
        bindMessage = false;
        // result->bindWidget("contents", contents);
    }
    // If called from menu, this will bind with contents in create_menu result->bindWidget("contents", contents);
    return result;
}
/* ****************************************************************************
 * categoryComboChanged
 * Repopulate messageCombo based on categoryCombo
 */
void App::categoryComboChanged()
{
    messageCombo->clear();
    messageCombo->setCurrentIndex(0);

    switch (categoryCombo->currentIndex())
    {
        case 0:
            messageCombo->addItem("Default 0");
            messageCombo->addItem("Default 1");
            messageCombo->addItem("Default 2");
            break;
        case 1:
            messageCombo->addItem("Extra 0");
            messageCombo->addItem("Extra 1");
            messageCombo->addItem("Extra 2");
            messageCombo->addItem("Extra 3");
            break;
    }
    // Make sure we want to update URL
    if (!isChanged)
    {
        Wt::log("notice") << "(categoryComboChanged: " << std::to_string(categoryCombo->currentIndex()) << ")";
        Wt::WApplication::instance()->setInternalPath("/dynamic/" + std::to_string(categoryCombo->currentIndex()) + "/" + std::to_string(messageCombo->currentIndex()), true);
    }
}
/* ****************************************************************************
 * messageComboChanged
 */
void App::messageComboChanged()
{
    // Make sure we want to update URL
    if (!isChanged)
    {
        Wt::log("notice") << "(messageComboChanged: " << std::to_string(messageCombo->currentIndex()) << ")";
        Wt::WApplication::instance()->setInternalPath("/dynamic/" + std::to_string(categoryCombo->currentIndex()) + "/" + std::to_string(messageCombo->currentIndex()), true);
    }
}
/* ****************************************************************************
 * Statically
 */
Wt::WWidget *App::Statically()
{
    return new Wt::WText(tr("static.intro"));
}
/* ****************************************************************************
 * logInternalPath
 * This is a generic path change hook, I used it to to see if I need to update dynamic content
 */
void App::logInternalPath(const std::string& path)
{
    // simulate an access log for the interal paths
    log("Path Change") << path;

    // As far as I can tell, this would be the same if I did it in combobox change event
    Wt::log("notice") << "(logInternalPath: " << ")";
    WApplication* app = WApplication::instance();
    if (app->internalPathMatches("/dynamic/"))
    {
        std::string categoryNumber = app->internalPathNextPart("/dynamic/");
        if (!categoryNumber.empty())
        {
            std::string messageNumber = app->internalPathNextPart("/dynamic/" + categoryNumber + "/");
            if (!messageNumber.empty())
            {
                Wt::log("notice") << "(logInternalPath: " << categoryNumber + "/" + messageNumber << ")";
                bindMessage = true;
                /* We call Dynamically which returns a WWidget,
                 * do I bind it to something here?
                 */
                Dynamically();
            }
        }
    }
}
/* ****************************************************************************
 * tr
 */
Wt::WString App::tr(const char *key)
{
    return Wt::WString::tr(key);
}
/* ****************************************************************************
 * create_app
 */
Wt::WApplication* create_app(const Wt::WEnvironment& env)
{
    return new App(env);
}
/* ****************************************************************************
 * main
 */
int main(int argc, char* argv[])
{
    return Wt::WRun(argc, argv, create_app);
}
// --- End of File ------------------------------------------------------------

Attachment: dynamic-menu.xml
Description: XML document

------------------------------------------------------------------------------
Flow-based real-time traffic analytics software. Cisco certified tool.
Monitor traffic, SLAs, QoS, Medianet, WAAS etc. with NetFlow Analyzer
Customize your own dashboards, set traffic alerts and generate reports.
Network behavioral analysis & security monitoring. All-in-one tool.
http://pubads.g.doubleclick.net/gampad/clk?id=126839071&iu=/4140/ostg.clktrk
_______________________________________________
witty-interest mailing list
witty-interest@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/witty-interest

Reply via email to